Bug 1874684 - Part 31: Correctly reject invalid durations in some RoundDuration calls...
[gecko.git] / js / src / jit / BaselineFrameInfo.cpp
blobd641ace2ab14f9d42bc0cdd1e7564a986d0a3a8c
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "jit/BaselineFrameInfo.h"
9 #include <algorithm>
11 #include "jit/BaselineIC.h"
12 #ifdef DEBUG
13 # include "jit/BytecodeAnalysis.h"
14 #endif
16 #include "jit/BaselineFrameInfo-inl.h"
17 #include "jit/JitFrames.h"
18 #include "jit/MacroAssembler-inl.h"
20 using namespace js;
21 using namespace js::jit;
23 bool CompilerFrameInfo::init(TempAllocator& alloc) {
24 // An extra slot is needed for global scopes because INITGLEXICAL (stack
25 // depth 1) is compiled as a SETPROP (stack depth 2) on the global lexical
26 // scope.
27 size_t extra = script->isGlobalCode() ? 1 : 0;
28 size_t nstack =
29 std::max(script->nslots() - script->nfixed(), size_t(MinJITStackSize)) +
30 extra;
31 if (!stack.init(alloc, nstack)) {
32 return false;
35 return true;
38 void CompilerFrameInfo::sync(StackValue* val) {
39 switch (val->kind()) {
40 case StackValue::Stack:
41 break;
42 case StackValue::LocalSlot:
43 masm.pushValue(addressOfLocal(val->localSlot()));
44 break;
45 case StackValue::ArgSlot:
46 masm.pushValue(addressOfArg(val->argSlot()));
47 break;
48 case StackValue::ThisSlot:
49 masm.pushValue(addressOfThis());
50 break;
51 case StackValue::Register:
52 masm.pushValue(val->reg());
53 break;
54 case StackValue::Constant:
55 masm.pushValue(val->constant());
56 break;
57 default:
58 MOZ_CRASH("Invalid kind");
61 val->setStack();
64 void CompilerFrameInfo::syncStack(uint32_t uses) {
65 MOZ_ASSERT(uses <= stackDepth());
67 uint32_t depth = stackDepth() - uses;
69 for (uint32_t i = 0; i < depth; i++) {
70 StackValue* current = &stack[i];
71 sync(current);
75 uint32_t CompilerFrameInfo::numUnsyncedSlots() {
76 // Start at the bottom, find the first value that's not synced.
77 uint32_t i = 0;
78 for (; i < stackDepth(); i++) {
79 if (peek(-int32_t(i + 1))->kind() == StackValue::Stack) {
80 break;
83 return i;
86 void CompilerFrameInfo::popValue(ValueOperand dest) {
87 StackValue* val = peek(-1);
89 switch (val->kind()) {
90 case StackValue::Constant:
91 masm.moveValue(val->constant(), dest);
92 break;
93 case StackValue::LocalSlot:
94 masm.loadValue(addressOfLocal(val->localSlot()), dest);
95 break;
96 case StackValue::ArgSlot:
97 masm.loadValue(addressOfArg(val->argSlot()), dest);
98 break;
99 case StackValue::ThisSlot:
100 masm.loadValue(addressOfThis(), dest);
101 break;
102 case StackValue::Stack:
103 masm.popValue(dest);
104 break;
105 case StackValue::Register:
106 masm.moveValue(val->reg(), dest);
107 break;
108 default:
109 MOZ_CRASH("Invalid kind");
112 // masm.popValue already adjusted the stack pointer, don't do it twice.
113 pop(DontAdjustStack);
116 void CompilerFrameInfo::popRegsAndSync(uint32_t uses) {
117 // x86 has only 3 Value registers. Only support 2 regs here for now,
118 // so that there's always a scratch Value register for reg -> reg
119 // moves.
120 MOZ_ASSERT(uses > 0);
121 MOZ_ASSERT(uses <= 2);
122 MOZ_ASSERT(uses <= stackDepth());
124 syncStack(uses);
126 switch (uses) {
127 case 1:
128 popValue(R0);
129 break;
130 case 2: {
131 // If the second value is in R1, move it to R2 so that it's not
132 // clobbered by the first popValue.
133 StackValue* val = peek(-2);
134 if (val->kind() == StackValue::Register && val->reg() == R1) {
135 masm.moveValue(R1, ValueOperand(R2));
136 val->setRegister(R2);
138 popValue(R1);
139 popValue(R0);
140 break;
142 default:
143 MOZ_CRASH("Invalid uses");
145 // On arm64, SP may be < PSP now (that's OK).
146 // eg testcase: tests/bug1580246.js
149 void InterpreterFrameInfo::popRegsAndSync(uint32_t uses) {
150 switch (uses) {
151 case 1:
152 popValue(R0);
153 break;
154 case 2: {
155 popValue(R1);
156 popValue(R0);
157 break;
159 default:
160 MOZ_CRASH("Invalid uses");
162 // On arm64, SP may be < PSP now (that's OK).
163 // eg testcase: tests/backup-point-bug1315634.js
166 void InterpreterFrameInfo::bumpInterpreterICEntry() {
167 masm.addPtr(Imm32(sizeof(ICEntry)), addressOfInterpreterICEntry());
170 void CompilerFrameInfo::storeStackValue(int32_t depth, const Address& dest,
171 const ValueOperand& scratch) {
172 const StackValue* source = peek(depth);
173 switch (source->kind()) {
174 case StackValue::Constant:
175 masm.storeValue(source->constant(), dest);
176 break;
177 case StackValue::Register:
178 masm.storeValue(source->reg(), dest);
179 break;
180 case StackValue::LocalSlot:
181 masm.loadValue(addressOfLocal(source->localSlot()), scratch);
182 masm.storeValue(scratch, dest);
183 break;
184 case StackValue::ArgSlot:
185 masm.loadValue(addressOfArg(source->argSlot()), scratch);
186 masm.storeValue(scratch, dest);
187 break;
188 case StackValue::ThisSlot:
189 masm.loadValue(addressOfThis(), scratch);
190 masm.storeValue(scratch, dest);
191 break;
192 case StackValue::Stack:
193 masm.loadValue(addressOfStackValue(depth), scratch);
194 masm.storeValue(scratch, dest);
195 break;
196 default:
197 MOZ_CRASH("Invalid kind");
201 #ifdef DEBUG
202 void CompilerFrameInfo::assertValidState(const BytecodeInfo& info) {
203 // Check stack depth.
204 MOZ_ASSERT(stackDepth() == info.stackDepth);
206 // Start at the bottom, find the first value that's not synced.
207 uint32_t i = 0;
208 for (; i < stackDepth(); i++) {
209 if (stack[i].kind() != StackValue::Stack) {
210 break;
214 // Assert all values on top of it are also not synced.
215 for (; i < stackDepth(); i++) {
216 MOZ_ASSERT(stack[i].kind() != StackValue::Stack);
219 // Assert every Value register is used by at most one StackValue.
220 // R2 is used as scratch register by the compiler and FrameInfo,
221 // so it shouldn't be used for StackValues.
222 bool usedR0 = false, usedR1 = false;
224 for (i = 0; i < stackDepth(); i++) {
225 if (stack[i].kind() == StackValue::Register) {
226 ValueOperand reg = stack[i].reg();
227 if (reg == R0) {
228 MOZ_ASSERT(!usedR0);
229 usedR0 = true;
230 } else if (reg == R1) {
231 MOZ_ASSERT(!usedR1);
232 usedR1 = true;
233 } else {
234 MOZ_CRASH("Invalid register");
239 #endif