BaselineFrameInfo.cpp (6453B)
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/. */ 6 7 #include "jit/BaselineFrameInfo.h" 8 9 #include <algorithm> 10 11 #include "jit/BaselineIC.h" 12 #ifdef DEBUG 13 # include "jit/BytecodeAnalysis.h" 14 #endif 15 16 #include "jit/BaselineFrameInfo-inl.h" 17 #include "jit/JitFrames.h" 18 #include "jit/MacroAssembler-inl.h" 19 20 using namespace js; 21 using namespace js::jit; 22 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; 33 } 34 35 return true; 36 } 37 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"); 59 } 60 61 val->setStack(); 62 } 63 64 void CompilerFrameInfo::syncStack(uint32_t uses) { 65 MOZ_ASSERT(uses <= stackDepth()); 66 67 uint32_t depth = stackDepth() - uses; 68 69 for (uint32_t i = 0; i < depth; i++) { 70 StackValue* current = &stack[i]; 71 sync(current); 72 } 73 } 74 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; 81 } 82 } 83 return i; 84 } 85 86 void CompilerFrameInfo::popValue(ValueOperand dest) { 87 StackValue* val = peek(-1); 88 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"); 110 } 111 112 // masm.popValue already adjusted the stack pointer, don't do it twice. 113 pop(DontAdjustStack); 114 } 115 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()); 123 124 syncStack(uses); 125 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); 137 } 138 popValue(R1); 139 popValue(R0); 140 break; 141 } 142 default: 143 MOZ_CRASH("Invalid uses"); 144 } 145 // On arm64, SP may be < PSP now (that's OK). 146 // eg testcase: tests/bug1580246.js 147 } 148 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; 158 } 159 default: 160 MOZ_CRASH("Invalid uses"); 161 } 162 // On arm64, SP may be < PSP now (that's OK). 163 // eg testcase: tests/backup-point-bug1315634.js 164 } 165 166 void InterpreterFrameInfo::bumpInterpreterICEntry() { 167 masm.addPtr(Imm32(sizeof(ICEntry)), addressOfInterpreterICEntry()); 168 } 169 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"); 198 } 199 } 200 201 #ifdef DEBUG 202 void CompilerFrameInfo::assertValidState(const BytecodeInfo& info) { 203 // Check stack depth. 204 MOZ_ASSERT(stackDepth() == info.stackDepth); 205 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; 211 } 212 } 213 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); 217 } 218 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; 223 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"); 235 } 236 } 237 } 238 } 239 #endif