1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jit/x86/MacroAssembler-x86.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,415 @@ 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/x86/MacroAssembler-x86.h" 1.11 + 1.12 +#include "mozilla/Casting.h" 1.13 + 1.14 +#include "jit/Bailouts.h" 1.15 +#include "jit/BaselineFrame.h" 1.16 +#include "jit/IonFrames.h" 1.17 +#include "jit/MoveEmitter.h" 1.18 + 1.19 +#include "jsscriptinlines.h" 1.20 + 1.21 +using namespace js; 1.22 +using namespace js::jit; 1.23 + 1.24 +MacroAssemblerX86::Double * 1.25 +MacroAssemblerX86::getDouble(double d) 1.26 +{ 1.27 + if (!doubleMap_.initialized()) { 1.28 + enoughMemory_ &= doubleMap_.init(); 1.29 + if (!enoughMemory_) 1.30 + return nullptr; 1.31 + } 1.32 + size_t doubleIndex; 1.33 + DoubleMap::AddPtr p = doubleMap_.lookupForAdd(d); 1.34 + if (p) { 1.35 + doubleIndex = p->value(); 1.36 + } else { 1.37 + doubleIndex = doubles_.length(); 1.38 + enoughMemory_ &= doubles_.append(Double(d)); 1.39 + enoughMemory_ &= doubleMap_.add(p, d, doubleIndex); 1.40 + if (!enoughMemory_) 1.41 + return nullptr; 1.42 + } 1.43 + Double &dbl = doubles_[doubleIndex]; 1.44 + JS_ASSERT(!dbl.uses.bound()); 1.45 + return &dbl; 1.46 +} 1.47 + 1.48 +void 1.49 +MacroAssemblerX86::loadConstantDouble(double d, const FloatRegister &dest) 1.50 +{ 1.51 + if (maybeInlineDouble(d, dest)) 1.52 + return; 1.53 + Double *dbl = getDouble(d); 1.54 + if (!dbl) 1.55 + return; 1.56 + masm.movsd_mr(reinterpret_cast<const void *>(dbl->uses.prev()), dest.code()); 1.57 + dbl->uses.setPrev(masm.size()); 1.58 +} 1.59 + 1.60 +void 1.61 +MacroAssemblerX86::addConstantDouble(double d, const FloatRegister &dest) 1.62 +{ 1.63 + Double *dbl = getDouble(d); 1.64 + if (!dbl) 1.65 + return; 1.66 + masm.addsd_mr(reinterpret_cast<const void *>(dbl->uses.prev()), dest.code()); 1.67 + dbl->uses.setPrev(masm.size()); 1.68 +} 1.69 + 1.70 +MacroAssemblerX86::Float * 1.71 +MacroAssemblerX86::getFloat(float f) 1.72 +{ 1.73 + if (!floatMap_.initialized()) { 1.74 + enoughMemory_ &= floatMap_.init(); 1.75 + if (!enoughMemory_) 1.76 + return nullptr; 1.77 + } 1.78 + size_t floatIndex; 1.79 + FloatMap::AddPtr p = floatMap_.lookupForAdd(f); 1.80 + if (p) { 1.81 + floatIndex = p->value(); 1.82 + } else { 1.83 + floatIndex = floats_.length(); 1.84 + enoughMemory_ &= floats_.append(Float(f)); 1.85 + enoughMemory_ &= floatMap_.add(p, f, floatIndex); 1.86 + if (!enoughMemory_) 1.87 + return nullptr; 1.88 + } 1.89 + Float &flt = floats_[floatIndex]; 1.90 + JS_ASSERT(!flt.uses.bound()); 1.91 + return &flt; 1.92 +} 1.93 + 1.94 +void 1.95 +MacroAssemblerX86::loadConstantFloat32(float f, const FloatRegister &dest) 1.96 +{ 1.97 + if (maybeInlineFloat(f, dest)) 1.98 + return; 1.99 + Float *flt = getFloat(f); 1.100 + if (!flt) 1.101 + return; 1.102 + masm.movss_mr(reinterpret_cast<const void *>(flt->uses.prev()), dest.code()); 1.103 + flt->uses.setPrev(masm.size()); 1.104 +} 1.105 + 1.106 +void 1.107 +MacroAssemblerX86::addConstantFloat32(float f, const FloatRegister &dest) 1.108 +{ 1.109 + Float *flt = getFloat(f); 1.110 + if (!flt) 1.111 + return; 1.112 + masm.addss_mr(reinterpret_cast<const void *>(flt->uses.prev()), dest.code()); 1.113 + flt->uses.setPrev(masm.size()); 1.114 +} 1.115 + 1.116 +void 1.117 +MacroAssemblerX86::finish() 1.118 +{ 1.119 + if (!doubles_.empty()) 1.120 + masm.align(sizeof(double)); 1.121 + for (size_t i = 0; i < doubles_.length(); i++) { 1.122 + CodeLabel cl(doubles_[i].uses); 1.123 + writeDoubleConstant(doubles_[i].value, cl.src()); 1.124 + enoughMemory_ &= addCodeLabel(cl); 1.125 + if (!enoughMemory_) 1.126 + return; 1.127 + } 1.128 + 1.129 + if (!floats_.empty()) 1.130 + masm.align(sizeof(float)); 1.131 + for (size_t i = 0; i < floats_.length(); i++) { 1.132 + CodeLabel cl(floats_[i].uses); 1.133 + writeFloatConstant(floats_[i].value, cl.src()); 1.134 + enoughMemory_ &= addCodeLabel(cl); 1.135 + if (!enoughMemory_) 1.136 + return; 1.137 + } 1.138 +} 1.139 + 1.140 +void 1.141 +MacroAssemblerX86::setupABICall(uint32_t args) 1.142 +{ 1.143 + JS_ASSERT(!inCall_); 1.144 + inCall_ = true; 1.145 + 1.146 + args_ = args; 1.147 + passedArgs_ = 0; 1.148 + stackForCall_ = 0; 1.149 +} 1.150 + 1.151 +void 1.152 +MacroAssemblerX86::setupAlignedABICall(uint32_t args) 1.153 +{ 1.154 + setupABICall(args); 1.155 + dynamicAlignment_ = false; 1.156 +} 1.157 + 1.158 +void 1.159 +MacroAssemblerX86::setupUnalignedABICall(uint32_t args, const Register &scratch) 1.160 +{ 1.161 + setupABICall(args); 1.162 + dynamicAlignment_ = true; 1.163 + 1.164 + movl(esp, scratch); 1.165 + andl(Imm32(~(StackAlignment - 1)), esp); 1.166 + push(scratch); 1.167 +} 1.168 + 1.169 +void 1.170 +MacroAssemblerX86::passABIArg(const MoveOperand &from, MoveOp::Type type) 1.171 +{ 1.172 + ++passedArgs_; 1.173 + MoveOperand to = MoveOperand(StackPointer, stackForCall_); 1.174 + switch (type) { 1.175 + case MoveOp::FLOAT32: stackForCall_ += sizeof(float); break; 1.176 + case MoveOp::DOUBLE: stackForCall_ += sizeof(double); break; 1.177 + case MoveOp::INT32: stackForCall_ += sizeof(int32_t); break; 1.178 + case MoveOp::GENERAL: stackForCall_ += sizeof(intptr_t); break; 1.179 + default: MOZ_ASSUME_UNREACHABLE("Unexpected argument type"); 1.180 + } 1.181 + enoughMemory_ &= moveResolver_.addMove(from, to, type); 1.182 +} 1.183 + 1.184 +void 1.185 +MacroAssemblerX86::passABIArg(const Register ®) 1.186 +{ 1.187 + passABIArg(MoveOperand(reg), MoveOp::GENERAL); 1.188 +} 1.189 + 1.190 +void 1.191 +MacroAssemblerX86::passABIArg(const FloatRegister ®, MoveOp::Type type) 1.192 +{ 1.193 + passABIArg(MoveOperand(reg), type); 1.194 +} 1.195 + 1.196 +void 1.197 +MacroAssemblerX86::callWithABIPre(uint32_t *stackAdjust) 1.198 +{ 1.199 + JS_ASSERT(inCall_); 1.200 + JS_ASSERT(args_ == passedArgs_); 1.201 + 1.202 + if (dynamicAlignment_) { 1.203 + *stackAdjust = stackForCall_ 1.204 + + ComputeByteAlignment(stackForCall_ + sizeof(intptr_t), 1.205 + StackAlignment); 1.206 + } else { 1.207 + *stackAdjust = stackForCall_ 1.208 + + ComputeByteAlignment(stackForCall_ + framePushed_, 1.209 + StackAlignment); 1.210 + } 1.211 + 1.212 + reserveStack(*stackAdjust); 1.213 + 1.214 + // Position all arguments. 1.215 + { 1.216 + enoughMemory_ &= moveResolver_.resolve(); 1.217 + if (!enoughMemory_) 1.218 + return; 1.219 + 1.220 + MoveEmitter emitter(*this); 1.221 + emitter.emit(moveResolver_); 1.222 + emitter.finish(); 1.223 + } 1.224 + 1.225 +#ifdef DEBUG 1.226 + { 1.227 + // Check call alignment. 1.228 + Label good; 1.229 + testl(esp, Imm32(StackAlignment - 1)); 1.230 + j(Equal, &good); 1.231 + breakpoint(); 1.232 + bind(&good); 1.233 + } 1.234 +#endif 1.235 +} 1.236 + 1.237 +void 1.238 +MacroAssemblerX86::callWithABIPost(uint32_t stackAdjust, MoveOp::Type result) 1.239 +{ 1.240 + freeStack(stackAdjust); 1.241 + if (result == MoveOp::DOUBLE) { 1.242 + reserveStack(sizeof(double)); 1.243 + fstp(Operand(esp, 0)); 1.244 + loadDouble(Operand(esp, 0), ReturnFloatReg); 1.245 + freeStack(sizeof(double)); 1.246 + } else if (result == MoveOp::FLOAT32) { 1.247 + reserveStack(sizeof(float)); 1.248 + fstp32(Operand(esp, 0)); 1.249 + loadFloat32(Operand(esp, 0), ReturnFloatReg); 1.250 + freeStack(sizeof(float)); 1.251 + } 1.252 + if (dynamicAlignment_) 1.253 + pop(esp); 1.254 + 1.255 + JS_ASSERT(inCall_); 1.256 + inCall_ = false; 1.257 +} 1.258 + 1.259 +void 1.260 +MacroAssemblerX86::callWithABI(void *fun, MoveOp::Type result) 1.261 +{ 1.262 + uint32_t stackAdjust; 1.263 + callWithABIPre(&stackAdjust); 1.264 + call(ImmPtr(fun)); 1.265 + callWithABIPost(stackAdjust, result); 1.266 +} 1.267 + 1.268 +void 1.269 +MacroAssemblerX86::callWithABI(AsmJSImmPtr fun, MoveOp::Type result) 1.270 +{ 1.271 + uint32_t stackAdjust; 1.272 + callWithABIPre(&stackAdjust); 1.273 + call(fun); 1.274 + callWithABIPost(stackAdjust, result); 1.275 +} 1.276 + 1.277 +void 1.278 +MacroAssemblerX86::callWithABI(const Address &fun, MoveOp::Type result) 1.279 +{ 1.280 + uint32_t stackAdjust; 1.281 + callWithABIPre(&stackAdjust); 1.282 + call(Operand(fun)); 1.283 + callWithABIPost(stackAdjust, result); 1.284 +} 1.285 + 1.286 +void 1.287 +MacroAssemblerX86::handleFailureWithHandler(void *handler) 1.288 +{ 1.289 + // Reserve space for exception information. 1.290 + subl(Imm32(sizeof(ResumeFromException)), esp); 1.291 + movl(esp, eax); 1.292 + 1.293 + // Ask for an exception handler. 1.294 + setupUnalignedABICall(1, ecx); 1.295 + passABIArg(eax); 1.296 + callWithABI(handler); 1.297 + 1.298 + JitCode *excTail = GetIonContext()->runtime->jitRuntime()->getExceptionTail(); 1.299 + jmp(excTail); 1.300 +} 1.301 + 1.302 +void 1.303 +MacroAssemblerX86::handleFailureWithHandlerTail() 1.304 +{ 1.305 + Label entryFrame; 1.306 + Label catch_; 1.307 + Label finally; 1.308 + Label return_; 1.309 + Label bailout; 1.310 + 1.311 + loadPtr(Address(esp, offsetof(ResumeFromException, kind)), eax); 1.312 + branch32(Assembler::Equal, eax, Imm32(ResumeFromException::RESUME_ENTRY_FRAME), &entryFrame); 1.313 + branch32(Assembler::Equal, eax, Imm32(ResumeFromException::RESUME_CATCH), &catch_); 1.314 + branch32(Assembler::Equal, eax, Imm32(ResumeFromException::RESUME_FINALLY), &finally); 1.315 + branch32(Assembler::Equal, eax, Imm32(ResumeFromException::RESUME_FORCED_RETURN), &return_); 1.316 + branch32(Assembler::Equal, eax, Imm32(ResumeFromException::RESUME_BAILOUT), &bailout); 1.317 + 1.318 + breakpoint(); // Invalid kind. 1.319 + 1.320 + // No exception handler. Load the error value, load the new stack pointer 1.321 + // and return from the entry frame. 1.322 + bind(&entryFrame); 1.323 + moveValue(MagicValue(JS_ION_ERROR), JSReturnOperand); 1.324 + loadPtr(Address(esp, offsetof(ResumeFromException, stackPointer)), esp); 1.325 + ret(); 1.326 + 1.327 + // If we found a catch handler, this must be a baseline frame. Restore state 1.328 + // and jump to the catch block. 1.329 + bind(&catch_); 1.330 + loadPtr(Address(esp, offsetof(ResumeFromException, target)), eax); 1.331 + loadPtr(Address(esp, offsetof(ResumeFromException, framePointer)), ebp); 1.332 + loadPtr(Address(esp, offsetof(ResumeFromException, stackPointer)), esp); 1.333 + jmp(Operand(eax)); 1.334 + 1.335 + // If we found a finally block, this must be a baseline frame. Push 1.336 + // two values expected by JSOP_RETSUB: BooleanValue(true) and the 1.337 + // exception. 1.338 + bind(&finally); 1.339 + ValueOperand exception = ValueOperand(ecx, edx); 1.340 + loadValue(Address(esp, offsetof(ResumeFromException, exception)), exception); 1.341 + 1.342 + loadPtr(Address(esp, offsetof(ResumeFromException, target)), eax); 1.343 + loadPtr(Address(esp, offsetof(ResumeFromException, framePointer)), ebp); 1.344 + loadPtr(Address(esp, offsetof(ResumeFromException, stackPointer)), esp); 1.345 + 1.346 + pushValue(BooleanValue(true)); 1.347 + pushValue(exception); 1.348 + jmp(Operand(eax)); 1.349 + 1.350 + // Only used in debug mode. Return BaselineFrame->returnValue() to the caller. 1.351 + bind(&return_); 1.352 + loadPtr(Address(esp, offsetof(ResumeFromException, framePointer)), ebp); 1.353 + loadPtr(Address(esp, offsetof(ResumeFromException, stackPointer)), esp); 1.354 + loadValue(Address(ebp, BaselineFrame::reverseOffsetOfReturnValue()), JSReturnOperand); 1.355 + movl(ebp, esp); 1.356 + pop(ebp); 1.357 + ret(); 1.358 + 1.359 + // If we are bailing out to baseline to handle an exception, jump to 1.360 + // the bailout tail stub. 1.361 + bind(&bailout); 1.362 + loadPtr(Address(esp, offsetof(ResumeFromException, bailoutInfo)), ecx); 1.363 + movl(Imm32(BAILOUT_RETURN_OK), eax); 1.364 + jmp(Operand(esp, offsetof(ResumeFromException, target))); 1.365 +} 1.366 + 1.367 +void 1.368 +MacroAssemblerX86::branchTestValue(Condition cond, const ValueOperand &value, const Value &v, Label *label) 1.369 +{ 1.370 + jsval_layout jv = JSVAL_TO_IMPL(v); 1.371 + if (v.isMarkable()) 1.372 + cmpl(value.payloadReg(), ImmGCPtr(reinterpret_cast<gc::Cell *>(v.toGCThing()))); 1.373 + else 1.374 + cmpl(value.payloadReg(), Imm32(jv.s.payload.i32)); 1.375 + 1.376 + if (cond == Equal) { 1.377 + Label done; 1.378 + j(NotEqual, &done); 1.379 + { 1.380 + cmpl(value.typeReg(), Imm32(jv.s.tag)); 1.381 + j(Equal, label); 1.382 + } 1.383 + bind(&done); 1.384 + } else { 1.385 + JS_ASSERT(cond == NotEqual); 1.386 + j(NotEqual, label); 1.387 + 1.388 + cmpl(value.typeReg(), Imm32(jv.s.tag)); 1.389 + j(NotEqual, label); 1.390 + } 1.391 +} 1.392 + 1.393 +#ifdef JSGC_GENERATIONAL 1.394 + 1.395 +void 1.396 +MacroAssemblerX86::branchPtrInNurseryRange(Register ptr, Register temp, Label *label) 1.397 +{ 1.398 + JS_ASSERT(ptr != temp); 1.399 + JS_ASSERT(temp != InvalidReg); // A temp register is required for x86. 1.400 + 1.401 + const Nursery &nursery = GetIonContext()->runtime->gcNursery(); 1.402 + movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp); 1.403 + addPtr(ptr, temp); 1.404 + branchPtr(Assembler::Below, temp, Imm32(Nursery::NurserySize), label); 1.405 +} 1.406 + 1.407 +void 1.408 +MacroAssemblerX86::branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label) 1.409 +{ 1.410 + Label done; 1.411 + 1.412 + branchTestObject(Assembler::NotEqual, value, &done); 1.413 + branchPtrInNurseryRange(value.payloadReg(), temp, label); 1.414 + 1.415 + bind(&done); 1.416 +} 1.417 + 1.418 +#endif