1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jit/BaselineFrameInfo.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,183 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "jit/BaselineFrameInfo.h" 1.11 + 1.12 +#ifdef DEBUG 1.13 +# include "jit/BytecodeAnalysis.h" 1.14 +#endif 1.15 + 1.16 +using namespace js; 1.17 +using namespace js::jit; 1.18 + 1.19 +bool 1.20 +FrameInfo::init(TempAllocator &alloc) 1.21 +{ 1.22 + // One slot is always needed for this/arguments type checks. 1.23 + size_t nstack = Max(script->nslots() - script->nfixed(), size_t(1)); 1.24 + if (!stack.init(alloc, nstack)) 1.25 + return false; 1.26 + 1.27 + return true; 1.28 +} 1.29 + 1.30 +void 1.31 +FrameInfo::sync(StackValue *val) 1.32 +{ 1.33 + switch (val->kind()) { 1.34 + case StackValue::Stack: 1.35 + break; 1.36 + case StackValue::LocalSlot: 1.37 + masm.pushValue(addressOfLocal(val->localSlot())); 1.38 + break; 1.39 + case StackValue::ArgSlot: 1.40 + masm.pushValue(addressOfArg(val->argSlot())); 1.41 + break; 1.42 + case StackValue::ThisSlot: 1.43 + masm.pushValue(addressOfThis()); 1.44 + break; 1.45 + case StackValue::Register: 1.46 + masm.pushValue(val->reg()); 1.47 + break; 1.48 + case StackValue::Constant: 1.49 + masm.pushValue(val->constant()); 1.50 + break; 1.51 + default: 1.52 + MOZ_ASSUME_UNREACHABLE("Invalid kind"); 1.53 + } 1.54 + 1.55 + val->setStack(); 1.56 +} 1.57 + 1.58 +void 1.59 +FrameInfo::syncStack(uint32_t uses) 1.60 +{ 1.61 + JS_ASSERT(uses <= stackDepth()); 1.62 + 1.63 + uint32_t depth = stackDepth() - uses; 1.64 + 1.65 + for (uint32_t i = 0; i < depth; i++) { 1.66 + StackValue *current = &stack[i]; 1.67 + sync(current); 1.68 + } 1.69 +} 1.70 + 1.71 +uint32_t 1.72 +FrameInfo::numUnsyncedSlots() 1.73 +{ 1.74 + // Start at the bottom, find the first value that's not synced. 1.75 + uint32_t i = 0; 1.76 + for (; i < stackDepth(); i++) { 1.77 + if (peek(-int32_t(i + 1))->kind() == StackValue::Stack) 1.78 + break; 1.79 + } 1.80 + return i; 1.81 +} 1.82 + 1.83 +void 1.84 +FrameInfo::popValue(ValueOperand dest) 1.85 +{ 1.86 + StackValue *val = peek(-1); 1.87 + 1.88 + switch (val->kind()) { 1.89 + case StackValue::Constant: 1.90 + masm.moveValue(val->constant(), dest); 1.91 + break; 1.92 + case StackValue::LocalSlot: 1.93 + masm.loadValue(addressOfLocal(val->localSlot()), dest); 1.94 + break; 1.95 + case StackValue::ArgSlot: 1.96 + masm.loadValue(addressOfArg(val->argSlot()), dest); 1.97 + break; 1.98 + case StackValue::ThisSlot: 1.99 + masm.loadValue(addressOfThis(), dest); 1.100 + break; 1.101 + case StackValue::Stack: 1.102 + masm.popValue(dest); 1.103 + break; 1.104 + case StackValue::Register: 1.105 + masm.moveValue(val->reg(), dest); 1.106 + break; 1.107 + default: 1.108 + MOZ_ASSUME_UNREACHABLE("Invalid kind"); 1.109 + } 1.110 + 1.111 + // masm.popValue already adjusted the stack pointer, don't do it twice. 1.112 + pop(DontAdjustStack); 1.113 +} 1.114 + 1.115 +void 1.116 +FrameInfo::popRegsAndSync(uint32_t uses) 1.117 +{ 1.118 + // x86 has only 3 Value registers. Only support 2 regs here for now, 1.119 + // so that there's always a scratch Value register for reg -> reg 1.120 + // moves. 1.121 + JS_ASSERT(uses > 0); 1.122 + JS_ASSERT(uses <= 2); 1.123 + JS_ASSERT(uses <= stackDepth()); 1.124 + 1.125 + syncStack(uses); 1.126 + 1.127 + switch (uses) { 1.128 + case 1: 1.129 + popValue(R0); 1.130 + break; 1.131 + case 2: { 1.132 + // If the second value is in R1, move it to R2 so that it's not 1.133 + // clobbered by the first popValue. 1.134 + StackValue *val = peek(-2); 1.135 + if (val->kind() == StackValue::Register && val->reg() == R1) { 1.136 + masm.moveValue(R1, R2); 1.137 + val->setRegister(R2); 1.138 + } 1.139 + popValue(R1); 1.140 + popValue(R0); 1.141 + break; 1.142 + } 1.143 + default: 1.144 + MOZ_ASSUME_UNREACHABLE("Invalid uses"); 1.145 + } 1.146 +} 1.147 + 1.148 +#ifdef DEBUG 1.149 +void 1.150 +FrameInfo::assertValidState(const BytecodeInfo &info) 1.151 +{ 1.152 + // Check stack depth. 1.153 + JS_ASSERT(stackDepth() == info.stackDepth); 1.154 + 1.155 + // Start at the bottom, find the first value that's not synced. 1.156 + uint32_t i = 0; 1.157 + for (; i < stackDepth(); i++) { 1.158 + if (stack[i].kind() != StackValue::Stack) 1.159 + break; 1.160 + } 1.161 + 1.162 + // Assert all values on top of it are also not synced. 1.163 + for (; i < stackDepth(); i++) 1.164 + JS_ASSERT(stack[i].kind() != StackValue::Stack); 1.165 + 1.166 + // Assert every Value register is used by at most one StackValue. 1.167 + // R2 is used as scratch register by the compiler and FrameInfo, 1.168 + // so it shouldn't be used for StackValues. 1.169 + bool usedR0 = false, usedR1 = false; 1.170 + 1.171 + for (i = 0; i < stackDepth(); i++) { 1.172 + if (stack[i].kind() == StackValue::Register) { 1.173 + ValueOperand reg = stack[i].reg(); 1.174 + if (reg == R0) { 1.175 + JS_ASSERT(!usedR0); 1.176 + usedR0 = true; 1.177 + } else if (reg == R1) { 1.178 + JS_ASSERT(!usedR1); 1.179 + usedR1 = true; 1.180 + } else { 1.181 + MOZ_ASSUME_UNREACHABLE("Invalid register"); 1.182 + } 1.183 + } 1.184 + } 1.185 +} 1.186 +#endif