js/src/jit/x86/MacroAssembler-x86.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "jit/x86/MacroAssembler-x86.h"
michael@0 8
michael@0 9 #include "mozilla/Casting.h"
michael@0 10
michael@0 11 #include "jit/Bailouts.h"
michael@0 12 #include "jit/BaselineFrame.h"
michael@0 13 #include "jit/IonFrames.h"
michael@0 14 #include "jit/MoveEmitter.h"
michael@0 15
michael@0 16 #include "jsscriptinlines.h"
michael@0 17
michael@0 18 using namespace js;
michael@0 19 using namespace js::jit;
michael@0 20
michael@0 21 MacroAssemblerX86::Double *
michael@0 22 MacroAssemblerX86::getDouble(double d)
michael@0 23 {
michael@0 24 if (!doubleMap_.initialized()) {
michael@0 25 enoughMemory_ &= doubleMap_.init();
michael@0 26 if (!enoughMemory_)
michael@0 27 return nullptr;
michael@0 28 }
michael@0 29 size_t doubleIndex;
michael@0 30 DoubleMap::AddPtr p = doubleMap_.lookupForAdd(d);
michael@0 31 if (p) {
michael@0 32 doubleIndex = p->value();
michael@0 33 } else {
michael@0 34 doubleIndex = doubles_.length();
michael@0 35 enoughMemory_ &= doubles_.append(Double(d));
michael@0 36 enoughMemory_ &= doubleMap_.add(p, d, doubleIndex);
michael@0 37 if (!enoughMemory_)
michael@0 38 return nullptr;
michael@0 39 }
michael@0 40 Double &dbl = doubles_[doubleIndex];
michael@0 41 JS_ASSERT(!dbl.uses.bound());
michael@0 42 return &dbl;
michael@0 43 }
michael@0 44
michael@0 45 void
michael@0 46 MacroAssemblerX86::loadConstantDouble(double d, const FloatRegister &dest)
michael@0 47 {
michael@0 48 if (maybeInlineDouble(d, dest))
michael@0 49 return;
michael@0 50 Double *dbl = getDouble(d);
michael@0 51 if (!dbl)
michael@0 52 return;
michael@0 53 masm.movsd_mr(reinterpret_cast<const void *>(dbl->uses.prev()), dest.code());
michael@0 54 dbl->uses.setPrev(masm.size());
michael@0 55 }
michael@0 56
michael@0 57 void
michael@0 58 MacroAssemblerX86::addConstantDouble(double d, const FloatRegister &dest)
michael@0 59 {
michael@0 60 Double *dbl = getDouble(d);
michael@0 61 if (!dbl)
michael@0 62 return;
michael@0 63 masm.addsd_mr(reinterpret_cast<const void *>(dbl->uses.prev()), dest.code());
michael@0 64 dbl->uses.setPrev(masm.size());
michael@0 65 }
michael@0 66
michael@0 67 MacroAssemblerX86::Float *
michael@0 68 MacroAssemblerX86::getFloat(float f)
michael@0 69 {
michael@0 70 if (!floatMap_.initialized()) {
michael@0 71 enoughMemory_ &= floatMap_.init();
michael@0 72 if (!enoughMemory_)
michael@0 73 return nullptr;
michael@0 74 }
michael@0 75 size_t floatIndex;
michael@0 76 FloatMap::AddPtr p = floatMap_.lookupForAdd(f);
michael@0 77 if (p) {
michael@0 78 floatIndex = p->value();
michael@0 79 } else {
michael@0 80 floatIndex = floats_.length();
michael@0 81 enoughMemory_ &= floats_.append(Float(f));
michael@0 82 enoughMemory_ &= floatMap_.add(p, f, floatIndex);
michael@0 83 if (!enoughMemory_)
michael@0 84 return nullptr;
michael@0 85 }
michael@0 86 Float &flt = floats_[floatIndex];
michael@0 87 JS_ASSERT(!flt.uses.bound());
michael@0 88 return &flt;
michael@0 89 }
michael@0 90
michael@0 91 void
michael@0 92 MacroAssemblerX86::loadConstantFloat32(float f, const FloatRegister &dest)
michael@0 93 {
michael@0 94 if (maybeInlineFloat(f, dest))
michael@0 95 return;
michael@0 96 Float *flt = getFloat(f);
michael@0 97 if (!flt)
michael@0 98 return;
michael@0 99 masm.movss_mr(reinterpret_cast<const void *>(flt->uses.prev()), dest.code());
michael@0 100 flt->uses.setPrev(masm.size());
michael@0 101 }
michael@0 102
michael@0 103 void
michael@0 104 MacroAssemblerX86::addConstantFloat32(float f, const FloatRegister &dest)
michael@0 105 {
michael@0 106 Float *flt = getFloat(f);
michael@0 107 if (!flt)
michael@0 108 return;
michael@0 109 masm.addss_mr(reinterpret_cast<const void *>(flt->uses.prev()), dest.code());
michael@0 110 flt->uses.setPrev(masm.size());
michael@0 111 }
michael@0 112
michael@0 113 void
michael@0 114 MacroAssemblerX86::finish()
michael@0 115 {
michael@0 116 if (!doubles_.empty())
michael@0 117 masm.align(sizeof(double));
michael@0 118 for (size_t i = 0; i < doubles_.length(); i++) {
michael@0 119 CodeLabel cl(doubles_[i].uses);
michael@0 120 writeDoubleConstant(doubles_[i].value, cl.src());
michael@0 121 enoughMemory_ &= addCodeLabel(cl);
michael@0 122 if (!enoughMemory_)
michael@0 123 return;
michael@0 124 }
michael@0 125
michael@0 126 if (!floats_.empty())
michael@0 127 masm.align(sizeof(float));
michael@0 128 for (size_t i = 0; i < floats_.length(); i++) {
michael@0 129 CodeLabel cl(floats_[i].uses);
michael@0 130 writeFloatConstant(floats_[i].value, cl.src());
michael@0 131 enoughMemory_ &= addCodeLabel(cl);
michael@0 132 if (!enoughMemory_)
michael@0 133 return;
michael@0 134 }
michael@0 135 }
michael@0 136
michael@0 137 void
michael@0 138 MacroAssemblerX86::setupABICall(uint32_t args)
michael@0 139 {
michael@0 140 JS_ASSERT(!inCall_);
michael@0 141 inCall_ = true;
michael@0 142
michael@0 143 args_ = args;
michael@0 144 passedArgs_ = 0;
michael@0 145 stackForCall_ = 0;
michael@0 146 }
michael@0 147
michael@0 148 void
michael@0 149 MacroAssemblerX86::setupAlignedABICall(uint32_t args)
michael@0 150 {
michael@0 151 setupABICall(args);
michael@0 152 dynamicAlignment_ = false;
michael@0 153 }
michael@0 154
michael@0 155 void
michael@0 156 MacroAssemblerX86::setupUnalignedABICall(uint32_t args, const Register &scratch)
michael@0 157 {
michael@0 158 setupABICall(args);
michael@0 159 dynamicAlignment_ = true;
michael@0 160
michael@0 161 movl(esp, scratch);
michael@0 162 andl(Imm32(~(StackAlignment - 1)), esp);
michael@0 163 push(scratch);
michael@0 164 }
michael@0 165
michael@0 166 void
michael@0 167 MacroAssemblerX86::passABIArg(const MoveOperand &from, MoveOp::Type type)
michael@0 168 {
michael@0 169 ++passedArgs_;
michael@0 170 MoveOperand to = MoveOperand(StackPointer, stackForCall_);
michael@0 171 switch (type) {
michael@0 172 case MoveOp::FLOAT32: stackForCall_ += sizeof(float); break;
michael@0 173 case MoveOp::DOUBLE: stackForCall_ += sizeof(double); break;
michael@0 174 case MoveOp::INT32: stackForCall_ += sizeof(int32_t); break;
michael@0 175 case MoveOp::GENERAL: stackForCall_ += sizeof(intptr_t); break;
michael@0 176 default: MOZ_ASSUME_UNREACHABLE("Unexpected argument type");
michael@0 177 }
michael@0 178 enoughMemory_ &= moveResolver_.addMove(from, to, type);
michael@0 179 }
michael@0 180
michael@0 181 void
michael@0 182 MacroAssemblerX86::passABIArg(const Register &reg)
michael@0 183 {
michael@0 184 passABIArg(MoveOperand(reg), MoveOp::GENERAL);
michael@0 185 }
michael@0 186
michael@0 187 void
michael@0 188 MacroAssemblerX86::passABIArg(const FloatRegister &reg, MoveOp::Type type)
michael@0 189 {
michael@0 190 passABIArg(MoveOperand(reg), type);
michael@0 191 }
michael@0 192
michael@0 193 void
michael@0 194 MacroAssemblerX86::callWithABIPre(uint32_t *stackAdjust)
michael@0 195 {
michael@0 196 JS_ASSERT(inCall_);
michael@0 197 JS_ASSERT(args_ == passedArgs_);
michael@0 198
michael@0 199 if (dynamicAlignment_) {
michael@0 200 *stackAdjust = stackForCall_
michael@0 201 + ComputeByteAlignment(stackForCall_ + sizeof(intptr_t),
michael@0 202 StackAlignment);
michael@0 203 } else {
michael@0 204 *stackAdjust = stackForCall_
michael@0 205 + ComputeByteAlignment(stackForCall_ + framePushed_,
michael@0 206 StackAlignment);
michael@0 207 }
michael@0 208
michael@0 209 reserveStack(*stackAdjust);
michael@0 210
michael@0 211 // Position all arguments.
michael@0 212 {
michael@0 213 enoughMemory_ &= moveResolver_.resolve();
michael@0 214 if (!enoughMemory_)
michael@0 215 return;
michael@0 216
michael@0 217 MoveEmitter emitter(*this);
michael@0 218 emitter.emit(moveResolver_);
michael@0 219 emitter.finish();
michael@0 220 }
michael@0 221
michael@0 222 #ifdef DEBUG
michael@0 223 {
michael@0 224 // Check call alignment.
michael@0 225 Label good;
michael@0 226 testl(esp, Imm32(StackAlignment - 1));
michael@0 227 j(Equal, &good);
michael@0 228 breakpoint();
michael@0 229 bind(&good);
michael@0 230 }
michael@0 231 #endif
michael@0 232 }
michael@0 233
michael@0 234 void
michael@0 235 MacroAssemblerX86::callWithABIPost(uint32_t stackAdjust, MoveOp::Type result)
michael@0 236 {
michael@0 237 freeStack(stackAdjust);
michael@0 238 if (result == MoveOp::DOUBLE) {
michael@0 239 reserveStack(sizeof(double));
michael@0 240 fstp(Operand(esp, 0));
michael@0 241 loadDouble(Operand(esp, 0), ReturnFloatReg);
michael@0 242 freeStack(sizeof(double));
michael@0 243 } else if (result == MoveOp::FLOAT32) {
michael@0 244 reserveStack(sizeof(float));
michael@0 245 fstp32(Operand(esp, 0));
michael@0 246 loadFloat32(Operand(esp, 0), ReturnFloatReg);
michael@0 247 freeStack(sizeof(float));
michael@0 248 }
michael@0 249 if (dynamicAlignment_)
michael@0 250 pop(esp);
michael@0 251
michael@0 252 JS_ASSERT(inCall_);
michael@0 253 inCall_ = false;
michael@0 254 }
michael@0 255
michael@0 256 void
michael@0 257 MacroAssemblerX86::callWithABI(void *fun, MoveOp::Type result)
michael@0 258 {
michael@0 259 uint32_t stackAdjust;
michael@0 260 callWithABIPre(&stackAdjust);
michael@0 261 call(ImmPtr(fun));
michael@0 262 callWithABIPost(stackAdjust, result);
michael@0 263 }
michael@0 264
michael@0 265 void
michael@0 266 MacroAssemblerX86::callWithABI(AsmJSImmPtr fun, MoveOp::Type result)
michael@0 267 {
michael@0 268 uint32_t stackAdjust;
michael@0 269 callWithABIPre(&stackAdjust);
michael@0 270 call(fun);
michael@0 271 callWithABIPost(stackAdjust, result);
michael@0 272 }
michael@0 273
michael@0 274 void
michael@0 275 MacroAssemblerX86::callWithABI(const Address &fun, MoveOp::Type result)
michael@0 276 {
michael@0 277 uint32_t stackAdjust;
michael@0 278 callWithABIPre(&stackAdjust);
michael@0 279 call(Operand(fun));
michael@0 280 callWithABIPost(stackAdjust, result);
michael@0 281 }
michael@0 282
michael@0 283 void
michael@0 284 MacroAssemblerX86::handleFailureWithHandler(void *handler)
michael@0 285 {
michael@0 286 // Reserve space for exception information.
michael@0 287 subl(Imm32(sizeof(ResumeFromException)), esp);
michael@0 288 movl(esp, eax);
michael@0 289
michael@0 290 // Ask for an exception handler.
michael@0 291 setupUnalignedABICall(1, ecx);
michael@0 292 passABIArg(eax);
michael@0 293 callWithABI(handler);
michael@0 294
michael@0 295 JitCode *excTail = GetIonContext()->runtime->jitRuntime()->getExceptionTail();
michael@0 296 jmp(excTail);
michael@0 297 }
michael@0 298
michael@0 299 void
michael@0 300 MacroAssemblerX86::handleFailureWithHandlerTail()
michael@0 301 {
michael@0 302 Label entryFrame;
michael@0 303 Label catch_;
michael@0 304 Label finally;
michael@0 305 Label return_;
michael@0 306 Label bailout;
michael@0 307
michael@0 308 loadPtr(Address(esp, offsetof(ResumeFromException, kind)), eax);
michael@0 309 branch32(Assembler::Equal, eax, Imm32(ResumeFromException::RESUME_ENTRY_FRAME), &entryFrame);
michael@0 310 branch32(Assembler::Equal, eax, Imm32(ResumeFromException::RESUME_CATCH), &catch_);
michael@0 311 branch32(Assembler::Equal, eax, Imm32(ResumeFromException::RESUME_FINALLY), &finally);
michael@0 312 branch32(Assembler::Equal, eax, Imm32(ResumeFromException::RESUME_FORCED_RETURN), &return_);
michael@0 313 branch32(Assembler::Equal, eax, Imm32(ResumeFromException::RESUME_BAILOUT), &bailout);
michael@0 314
michael@0 315 breakpoint(); // Invalid kind.
michael@0 316
michael@0 317 // No exception handler. Load the error value, load the new stack pointer
michael@0 318 // and return from the entry frame.
michael@0 319 bind(&entryFrame);
michael@0 320 moveValue(MagicValue(JS_ION_ERROR), JSReturnOperand);
michael@0 321 loadPtr(Address(esp, offsetof(ResumeFromException, stackPointer)), esp);
michael@0 322 ret();
michael@0 323
michael@0 324 // If we found a catch handler, this must be a baseline frame. Restore state
michael@0 325 // and jump to the catch block.
michael@0 326 bind(&catch_);
michael@0 327 loadPtr(Address(esp, offsetof(ResumeFromException, target)), eax);
michael@0 328 loadPtr(Address(esp, offsetof(ResumeFromException, framePointer)), ebp);
michael@0 329 loadPtr(Address(esp, offsetof(ResumeFromException, stackPointer)), esp);
michael@0 330 jmp(Operand(eax));
michael@0 331
michael@0 332 // If we found a finally block, this must be a baseline frame. Push
michael@0 333 // two values expected by JSOP_RETSUB: BooleanValue(true) and the
michael@0 334 // exception.
michael@0 335 bind(&finally);
michael@0 336 ValueOperand exception = ValueOperand(ecx, edx);
michael@0 337 loadValue(Address(esp, offsetof(ResumeFromException, exception)), exception);
michael@0 338
michael@0 339 loadPtr(Address(esp, offsetof(ResumeFromException, target)), eax);
michael@0 340 loadPtr(Address(esp, offsetof(ResumeFromException, framePointer)), ebp);
michael@0 341 loadPtr(Address(esp, offsetof(ResumeFromException, stackPointer)), esp);
michael@0 342
michael@0 343 pushValue(BooleanValue(true));
michael@0 344 pushValue(exception);
michael@0 345 jmp(Operand(eax));
michael@0 346
michael@0 347 // Only used in debug mode. Return BaselineFrame->returnValue() to the caller.
michael@0 348 bind(&return_);
michael@0 349 loadPtr(Address(esp, offsetof(ResumeFromException, framePointer)), ebp);
michael@0 350 loadPtr(Address(esp, offsetof(ResumeFromException, stackPointer)), esp);
michael@0 351 loadValue(Address(ebp, BaselineFrame::reverseOffsetOfReturnValue()), JSReturnOperand);
michael@0 352 movl(ebp, esp);
michael@0 353 pop(ebp);
michael@0 354 ret();
michael@0 355
michael@0 356 // If we are bailing out to baseline to handle an exception, jump to
michael@0 357 // the bailout tail stub.
michael@0 358 bind(&bailout);
michael@0 359 loadPtr(Address(esp, offsetof(ResumeFromException, bailoutInfo)), ecx);
michael@0 360 movl(Imm32(BAILOUT_RETURN_OK), eax);
michael@0 361 jmp(Operand(esp, offsetof(ResumeFromException, target)));
michael@0 362 }
michael@0 363
michael@0 364 void
michael@0 365 MacroAssemblerX86::branchTestValue(Condition cond, const ValueOperand &value, const Value &v, Label *label)
michael@0 366 {
michael@0 367 jsval_layout jv = JSVAL_TO_IMPL(v);
michael@0 368 if (v.isMarkable())
michael@0 369 cmpl(value.payloadReg(), ImmGCPtr(reinterpret_cast<gc::Cell *>(v.toGCThing())));
michael@0 370 else
michael@0 371 cmpl(value.payloadReg(), Imm32(jv.s.payload.i32));
michael@0 372
michael@0 373 if (cond == Equal) {
michael@0 374 Label done;
michael@0 375 j(NotEqual, &done);
michael@0 376 {
michael@0 377 cmpl(value.typeReg(), Imm32(jv.s.tag));
michael@0 378 j(Equal, label);
michael@0 379 }
michael@0 380 bind(&done);
michael@0 381 } else {
michael@0 382 JS_ASSERT(cond == NotEqual);
michael@0 383 j(NotEqual, label);
michael@0 384
michael@0 385 cmpl(value.typeReg(), Imm32(jv.s.tag));
michael@0 386 j(NotEqual, label);
michael@0 387 }
michael@0 388 }
michael@0 389
michael@0 390 #ifdef JSGC_GENERATIONAL
michael@0 391
michael@0 392 void
michael@0 393 MacroAssemblerX86::branchPtrInNurseryRange(Register ptr, Register temp, Label *label)
michael@0 394 {
michael@0 395 JS_ASSERT(ptr != temp);
michael@0 396 JS_ASSERT(temp != InvalidReg); // A temp register is required for x86.
michael@0 397
michael@0 398 const Nursery &nursery = GetIonContext()->runtime->gcNursery();
michael@0 399 movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp);
michael@0 400 addPtr(ptr, temp);
michael@0 401 branchPtr(Assembler::Below, temp, Imm32(Nursery::NurserySize), label);
michael@0 402 }
michael@0 403
michael@0 404 void
michael@0 405 MacroAssemblerX86::branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label)
michael@0 406 {
michael@0 407 Label done;
michael@0 408
michael@0 409 branchTestObject(Assembler::NotEqual, value, &done);
michael@0 410 branchPtrInNurseryRange(value.payloadReg(), temp, label);
michael@0 411
michael@0 412 bind(&done);
michael@0 413 }
michael@0 414
michael@0 415 #endif

mercurial