Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
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/. */
6 :
7 : #include "jit/BaselineFrameInfo.h"
8 :
9 : #ifdef DEBUG
10 : # include "jit/BytecodeAnalysis.h"
11 : #endif
12 :
13 : #include "jit/BaselineFrameInfo-inl.h"
14 : #include "jit/MacroAssembler-inl.h"
15 :
16 : using namespace js;
17 : using namespace js::jit;
18 :
19 : bool
20 628 : FrameInfo::init(TempAllocator& alloc)
21 : {
22 : // An extra slot is needed for global scopes because INITGLEXICAL (stack
23 : // depth 1) is compiled as a SETPROP (stack depth 2) on the global lexical
24 : // scope.
25 628 : size_t extra = script->isGlobalCode() ? 1 : 0;
26 628 : size_t nstack = Max(script->nslots() - script->nfixed(), size_t(MinJITStackSize)) + extra;
27 628 : if (!stack.init(alloc, nstack))
28 0 : return false;
29 :
30 628 : return true;
31 : }
32 :
33 : void
34 113436 : FrameInfo::sync(StackValue* val)
35 : {
36 113436 : switch (val->kind()) {
37 : case StackValue::Stack:
38 93842 : break;
39 : case StackValue::LocalSlot:
40 2009 : masm.pushValue(addressOfLocal(val->localSlot()));
41 2009 : break;
42 : case StackValue::ArgSlot:
43 1098 : masm.pushValue(addressOfArg(val->argSlot()));
44 1098 : break;
45 : case StackValue::ThisSlot:
46 0 : masm.pushValue(addressOfThis());
47 0 : break;
48 : case StackValue::EvalNewTargetSlot:
49 0 : MOZ_ASSERT(script->isForEval());
50 0 : masm.pushValue(addressOfEvalNewTarget());
51 0 : break;
52 : case StackValue::Register:
53 12469 : masm.pushValue(val->reg());
54 12469 : break;
55 : case StackValue::Constant:
56 4018 : masm.pushValue(val->constant());
57 4018 : break;
58 : default:
59 0 : MOZ_CRASH("Invalid kind");
60 : }
61 :
62 113436 : val->setStack();
63 113436 : }
64 :
65 : void
66 62395 : FrameInfo::syncStack(uint32_t uses)
67 : {
68 62395 : MOZ_ASSERT(uses <= stackDepth());
69 :
70 62395 : uint32_t depth = stackDepth() - uses;
71 :
72 175831 : for (uint32_t i = 0; i < depth; i++) {
73 113436 : StackValue* current = &stack[i];
74 113436 : sync(current);
75 : }
76 62395 : }
77 :
78 : uint32_t
79 122358 : FrameInfo::numUnsyncedSlots()
80 : {
81 : // Start at the bottom, find the first value that's not synced.
82 122358 : uint32_t i = 0;
83 329850 : for (; i < stackDepth(); i++) {
84 162984 : if (peek(-int32_t(i + 1))->kind() == StackValue::Stack)
85 59238 : break;
86 : }
87 122358 : return i;
88 : }
89 :
90 : void
91 22544 : FrameInfo::popValue(ValueOperand dest)
92 : {
93 22544 : StackValue* val = peek(-1);
94 :
95 22544 : switch (val->kind()) {
96 : case StackValue::Constant:
97 2176 : masm.moveValue(val->constant(), dest);
98 2176 : break;
99 : case StackValue::LocalSlot:
100 3410 : masm.loadValue(addressOfLocal(val->localSlot()), dest);
101 3410 : break;
102 : case StackValue::ArgSlot:
103 1649 : masm.loadValue(addressOfArg(val->argSlot()), dest);
104 1649 : break;
105 : case StackValue::ThisSlot:
106 707 : masm.loadValue(addressOfThis(), dest);
107 707 : break;
108 : case StackValue::EvalNewTargetSlot:
109 0 : masm.loadValue(addressOfEvalNewTarget(), dest);
110 0 : break;
111 : case StackValue::Stack:
112 4248 : masm.popValue(dest);
113 4248 : break;
114 : case StackValue::Register:
115 10354 : masm.moveValue(val->reg(), dest);
116 10354 : break;
117 : default:
118 0 : MOZ_CRASH("Invalid kind");
119 : }
120 :
121 : // masm.popValue already adjusted the stack pointer, don't do it twice.
122 22544 : pop(DontAdjustStack);
123 22544 : }
124 :
125 : void
126 16455 : FrameInfo::popRegsAndSync(uint32_t uses)
127 : {
128 : // x86 has only 3 Value registers. Only support 2 regs here for now,
129 : // so that there's always a scratch Value register for reg -> reg
130 : // moves.
131 16455 : MOZ_ASSERT(uses > 0);
132 16455 : MOZ_ASSERT(uses <= 2);
133 16455 : MOZ_ASSERT(uses <= stackDepth());
134 :
135 16455 : syncStack(uses);
136 :
137 16455 : switch (uses) {
138 : case 1:
139 11182 : popValue(R0);
140 11182 : break;
141 : case 2: {
142 : // If the second value is in R1, move it to R2 so that it's not
143 : // clobbered by the first popValue.
144 5273 : StackValue* val = peek(-2);
145 5273 : if (val->kind() == StackValue::Register && val->reg() == R1) {
146 4 : masm.moveValue(R1, R2);
147 4 : val->setRegister(R2);
148 : }
149 5273 : popValue(R1);
150 5273 : popValue(R0);
151 5273 : break;
152 : }
153 : default:
154 0 : MOZ_CRASH("Invalid uses");
155 : }
156 16455 : }
157 :
158 : #ifdef DEBUG
159 : void
160 61179 : FrameInfo::assertValidState(const BytecodeInfo& info)
161 : {
162 : // Check stack depth.
163 61179 : MOZ_ASSERT(stackDepth() == info.stackDepth);
164 :
165 : // Start at the bottom, find the first value that's not synced.
166 61179 : uint32_t i = 0;
167 211349 : for (; i < stackDepth(); i++) {
168 113393 : if (stack[i].kind() != StackValue::Stack)
169 38308 : break;
170 : }
171 :
172 : // Assert all values on top of it are also not synced.
173 164925 : for (; i < stackDepth(); i++)
174 51873 : MOZ_ASSERT(stack[i].kind() != StackValue::Stack);
175 :
176 : // Assert every Value register is used by at most one StackValue.
177 : // R2 is used as scratch register by the compiler and FrameInfo,
178 : // so it shouldn't be used for StackValues.
179 61179 : bool usedR0 = false, usedR1 = false;
180 :
181 188137 : for (i = 0; i < stackDepth(); i++) {
182 126958 : if (stack[i].kind() == StackValue::Register) {
183 30878 : ValueOperand reg = stack[i].reg();
184 30878 : if (reg == R0) {
185 26617 : MOZ_ASSERT(!usedR0);
186 26617 : usedR0 = true;
187 4261 : } else if (reg == R1) {
188 4261 : MOZ_ASSERT(!usedR1);
189 4261 : usedR1 = true;
190 : } else {
191 0 : MOZ_CRASH("Invalid register");
192 : }
193 : }
194 : }
195 61179 : }
196 : #endif
|