summaryrefslogtreecommitdiffstats
path: root/js/src/jit/StackSlotAllocator.h
blob: b058c3129439a5c184f0b658eb3dc6407a1f7dd5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef jit_StackSlotAllocator_h
#define jit_StackSlotAllocator_h

#include "mozilla/Unused.h"

#include "jit/Registers.h"

namespace js {
namespace jit {

class StackSlotAllocator {
  js::Vector<uint32_t, 4, SystemAllocPolicy> normalSlots;
  js::Vector<uint32_t, 4, SystemAllocPolicy> doubleSlots;
  uint32_t height_;

  void addAvailableSlot(uint32_t index) {
    // Ignoring OOM here (and below) is fine; it just means the stack slot
    // will be unused.
    mozilla::Unused << normalSlots.append(index);
  }
  void addAvailableDoubleSlot(uint32_t index) {
    mozilla::Unused << doubleSlots.append(index);
  }

  uint32_t allocateQuadSlot() {
    // This relies on the fact that any architecture specific
    // alignment of the stack pointer is done a priori.
    if (height_ % 8 != 0) {
      addAvailableSlot(height_ += 4);
    }
    if (height_ % 16 != 0) {
      addAvailableDoubleSlot(height_ += 8);
    }
    return height_ += 16;
  }
  uint32_t allocateDoubleSlot() {
    if (!doubleSlots.empty()) {
      return doubleSlots.popCopy();
    }
    if (height_ % 8 != 0) {
      addAvailableSlot(height_ += 4);
    }
    return height_ += 8;
  }
  uint32_t allocateSlot() {
    if (!normalSlots.empty()) {
      return normalSlots.popCopy();
    }
    if (!doubleSlots.empty()) {
      uint32_t index = doubleSlots.popCopy();
      addAvailableSlot(index - 4);
      return index;
    }
    return height_ += 4;
  }

 public:
  StackSlotAllocator() : height_(0) {}

  void allocateStackArea(LStackArea* alloc) {
    uint32_t size = alloc->size();

    MOZ_ASSERT(size % 4 == 0);
    switch (alloc->alignment()) {
      case 8:
        if ((height_ + size) % 8 != 0) {
          addAvailableSlot(height_ += 4);
        }
        break;
      default:
        MOZ_CRASH("unexpected stack results area alignment");
    }
    MOZ_ASSERT((height_ + size) % alloc->alignment() == 0);

    height_ += size;
    alloc->setBase(height_);
  }

  static uint32_t width(LDefinition::Type type) {
    switch (type) {
#if JS_BITS_PER_WORD == 32
      case LDefinition::GENERAL:
      case LDefinition::OBJECT:
      case LDefinition::SLOTS:
#endif
      case LDefinition::INT32:
      case LDefinition::FLOAT32:
        return 4;
#if JS_BITS_PER_WORD == 64
      case LDefinition::GENERAL:
      case LDefinition::OBJECT:
      case LDefinition::SLOTS:
#endif
#ifdef JS_PUNBOX64
      case LDefinition::BOX:
#endif
#ifdef JS_NUNBOX32
      case LDefinition::TYPE:
      case LDefinition::PAYLOAD:
#endif
      case LDefinition::DOUBLE:
        return 8;
      case LDefinition::SIMD128:
        return 16;
      case LDefinition::STACKRESULTS:
        MOZ_CRASH("Stack results area must be allocated manually");
    }
    MOZ_CRASH("Unknown slot type");
  }

  uint32_t allocateSlot(LDefinition::Type type) {
    switch (width(type)) {
      case 4:
        return allocateSlot();
      case 8:
        return allocateDoubleSlot();
      case 16:
        return allocateQuadSlot();
    }
    MOZ_CRASH("Unknown slot width");
  }

  uint32_t stackHeight() const { return height_; }
};

}  // namespace jit
}  // namespace js

#endif /* jit_StackSlotAllocator_h */