From 3414c83d98602be838a0d2fa28329b34936d6020 Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Mon, 21 Jul 2014 10:56:02 -0500 Subject: [PATCH] Bug 1027885 - OdinMonkey: avoid passing JSContext to C++ functions that can instead use innermostAsmJSActivation (r=dougc) --- js/src/jit/AsmJS.cpp | 235 ++++------------------------- js/src/jit/AsmJSModule.cpp | 145 +++++++++++++++--- js/src/jit/AsmJSSignalHandlers.cpp | 18 +-- js/src/jit/arm/Simulator-arm.cpp | 3 +- js/src/jit/mips/Simulator-mips.cpp | 2 +- js/src/vm/ArrayBufferObject.cpp | 2 +- js/src/vm/Runtime.h | 7 +- 7 files changed, 169 insertions(+), 243 deletions(-) diff --git a/js/src/jit/AsmJS.cpp b/js/src/jit/AsmJS.cpp index 8d02779dbec4..d9a4a3d74ea4 100644 --- a/js/src/jit/AsmJS.cpp +++ b/js/src/jit/AsmJS.cpp @@ -5880,12 +5880,6 @@ LoadAsmJSActivationIntoRegister(MacroAssembler &masm, Register reg) #endif } -static void -LoadJSContextFromActivation(MacroAssembler &masm, Register activation, Register dest) -{ - masm.loadPtr(Address(activation, AsmJSActivation::offsetOfContext()), dest); -} - static void AssertStackAlignment(MacroAssembler &masm) { @@ -6070,102 +6064,6 @@ GenerateEntry(ModuleCompiler &m, const AsmJSModule::ExportedFunction &exportedFu return true; } -// This function and InvokeFromAsmJS* functions all return int32_t rather than -// bool to prevent the compiler from optimizing bits higher than what's -// actually needed for a bool (as the result is tested in asm.js generated code -// which the compiler isn't aware of). -static inline int32_t -TryEnablingIon(JSContext *cx, AsmJSModule &module, HandleFunction fun, uint32_t exitIndex, - int32_t argc, Value *argv) -{ - if (!fun->hasScript()) - return true; - - // Test if the function is Ion compiled - JSScript *script = fun->nonLazyScript(); - if (!script->hasIonScript()) - return true; - - // Currently we can't rectify arguments. Therefore disabling if argc is too low. - if (fun->nargs() > size_t(argc)) - return true; - - // Normally the types should corresond, since we just ran with those types, - // but there are reports this is asserting. Therefore doing it as a check, instead of DEBUG only. - if (!types::TypeScript::ThisTypes(script)->hasType(types::Type::UndefinedType())) - return true; - for(uint32_t i = 0; i < fun->nargs(); i++) { - types::StackTypeSet *typeset = types::TypeScript::ArgTypes(script, i); - types::Type type = types::Type::DoubleType(); - if (!argv[i].isDouble()) - type = types::Type::PrimitiveType(argv[i].extractNonDoubleType()); - if (!typeset->hasType(type)) - return true; - } - - // Enable - IonScript *ionScript = script->ionScript(); - if (!ionScript->addDependentAsmJSModule(cx, DependentAsmJSModuleExit(&module, exitIndex))) - return false; - - module.exitIndexToGlobalDatum(exitIndex).exit = module.ionExitTrampoline(module.exit(exitIndex)); - return true; -} - -namespace js { - -// See comment above TryEnablingIon. -int32_t -InvokeFromAsmJS(JSContext *cx, int32_t exitIndex, int32_t argc, Value *argv, - MutableHandleValue rval) -{ - AsmJSModule &module = cx->mainThread().asmJSActivationStackFromOwnerThread()->module(); - - RootedFunction fun(cx, module.exitIndexToGlobalDatum(exitIndex).fun); - RootedValue fval(cx, ObjectValue(*fun)); - if (!Invoke(cx, UndefinedValue(), fval, argc, argv, rval)) - return false; - - return TryEnablingIon(cx, module, fun, exitIndex, argc, argv); -} - -int32_t -InvokeFromAsmJS_Ignore(JSContext *cx, int32_t exitIndex, int32_t argc, Value *argv) -{ - RootedValue rval(cx); - return InvokeFromAsmJS(cx, exitIndex, argc, argv, &rval); -} - -int32_t -InvokeFromAsmJS_ToInt32(JSContext *cx, int32_t exitIndex, int32_t argc, Value *argv) -{ - RootedValue rval(cx); - if (!InvokeFromAsmJS(cx, exitIndex, argc, argv, &rval)) - return false; - - int32_t i32; - if (!ToInt32(cx, rval, &i32)) - return false; - argv[0] = Int32Value(i32); - return true; -} - -int32_t -InvokeFromAsmJS_ToNumber(JSContext *cx, int32_t exitIndex, int32_t argc, Value *argv) -{ - RootedValue rval(cx); - if (!InvokeFromAsmJS(cx, exitIndex, argc, argv, &rval)) - return false; - - double dbl; - if (!ToNumber(cx, rval, &dbl)) - return false; - argv[0] = DoubleValue(dbl); - return true; -} - -} // namespace js - static void FillArgumentArray(ModuleCompiler &m, const VarTypeVector &argTypes, unsigned offsetToArgs, unsigned offsetToCallerStackArgs, @@ -6226,8 +6124,7 @@ GenerateFFIInterpreterExit(ModuleCompiler &m, const ModuleCompiler::ExitDescript LoadAsmJSActivationIntoRegister(masm, activation); masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitFP())); - MIRType typeArray[] = { MIRType_Pointer, // cx - MIRType_Pointer, // exitDatum + MIRType typeArray[] = { MIRType_Pointer, // exitDatum MIRType_Int32, // argc MIRType_Pointer }; // argv MIRTypeVector invokeArgTypes(m.cx()); @@ -6235,9 +6132,9 @@ GenerateFFIInterpreterExit(ModuleCompiler &m, const ModuleCompiler::ExitDescript // At the point of the call, the stack layout shall be (sp grows to the left): // | stack args | padding | Value argv[] | padding | retaddr | caller stack args | - // The padding between stack args and argv ensures that sp is aligned. The - // padding between argv and retaddr ensures that argv is aligned. - unsigned offsetToArgv = AlignBytes(StackArgBytes(invokeArgTypes), StackAlignment); + // The padding between stack args and argv ensures that argv is aligned. The + // padding between argv and retaddr ensures that sp is aligned. + unsigned offsetToArgv = AlignBytes(StackArgBytes(invokeArgTypes), sizeof(double)); unsigned argvBytes = Max(1, exit.sig().args().length()) * sizeof(Value); unsigned stackDec = StackDecrementForCall(masm, offsetToArgv + argvBytes); masm.reserveStack(stackDec); @@ -6250,23 +6147,14 @@ GenerateFFIInterpreterExit(ModuleCompiler &m, const ModuleCompiler::ExitDescript // Prepare the arguments for the call to InvokeFromAsmJS_*. ABIArgMIRTypeIter i(invokeArgTypes); - // argument 0: cx - if (i->kind() == ABIArg::GPR) { - LoadJSContextFromActivation(masm, activation, i->gpr()); - } else { - LoadJSContextFromActivation(masm, activation, scratch); - masm.storePtr(scratch, Address(StackPointer, i->offsetFromArgBase())); - } - i++; - - // argument 1: exitIndex + // argument 0: exitIndex if (i->kind() == ABIArg::GPR) masm.mov(ImmWord(exitIndex), i->gpr()); else masm.store32(Imm32(exitIndex), Address(StackPointer, i->offsetFromArgBase())); i++; - // argument 2: argc + // argument 1: argc unsigned argc = exit.sig().args().length(); if (i->kind() == ABIArg::GPR) masm.mov(ImmWord(argc), i->gpr()); @@ -6274,7 +6162,7 @@ GenerateFFIInterpreterExit(ModuleCompiler &m, const ModuleCompiler::ExitDescript masm.store32(Imm32(argc), Address(StackPointer, i->offsetFromArgBase())); i++; - // argument 3: argv + // argument 2: argv Address argv(StackPointer, offsetToArgv); if (i->kind() == ABIArg::GPR) { masm.computeEffectiveAddress(argv, i->gpr()); @@ -6371,25 +6259,26 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit // Ion calls use the following stack layout (sp grows to the left): // | return address | descriptor | callee | argc | this | arg1 | arg2 | ... - unsigned offsetToArgs = MaybeRetAddr; - unsigned argBytes = 3 * sizeof(size_t) + (1 + exit.sig().args().length()) * sizeof(Value); - unsigned totalIonBytes = offsetToArgs + argBytes + savedRegBytes; + unsigned offsetToIonArgs = MaybeRetAddr; + unsigned ionArgBytes = 3 * sizeof(size_t) + (1 + exit.sig().args().length()) * sizeof(Value); + unsigned totalIonBytes = offsetToIonArgs + ionArgBytes + savedRegBytes; unsigned ionFrameSize = StackDecrementForCall(masm, totalIonBytes); // Coercion calls use the following stack layout (sp grows to the left): - // | stack args | Value argv[1] | ... + // | stack args | padding | Value argv[1] | ... + // The padding between args and argv ensures that argv is aligned. MIRTypeVector coerceArgTypes(m.cx()); - coerceArgTypes.infallibleAppend(MIRType_Pointer); // cx coerceArgTypes.infallibleAppend(MIRType_Pointer); // argv - unsigned bytesAfterArgs = sizeof(Value) + savedRegBytes; - unsigned coerceFrameSize = StackDecrementForCall(masm, coerceArgTypes, bytesAfterArgs); + unsigned offsetToCoerceArgv = AlignBytes(StackArgBytes(coerceArgTypes), sizeof(double)); + unsigned totalCoerceBytes = offsetToCoerceArgv + sizeof(Value) + savedRegBytes; + unsigned coerceFrameSize = StackDecrementForCall(masm, totalCoerceBytes); // Allocate a frame large enough for both of the above calls. unsigned framePushed = Max(ionFrameSize, coerceFrameSize); masm.reserveStack(framePushed); // 1. Descriptor - size_t argOffset = offsetToArgs; + size_t argOffset = offsetToIonArgs; uint32_t descriptor = MakeFrameDescriptor(framePushed, JitFrame_Entry); masm.storePtr(ImmWord(uintptr_t(descriptor)), Address(StackPointer, argOffset)); argOffset += sizeof(size_t); @@ -6430,7 +6319,7 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit unsigned offsetToCallerStackArgs = framePushed + AsmJSFrameSize; FillArgumentArray(m, exit.sig().args(), argOffset, offsetToCallerStackArgs, scratch); argOffset += exit.sig().args().length() * sizeof(Value); - JS_ASSERT(argOffset == offsetToArgs + argBytes); + JS_ASSERT(argOffset == offsetToIonArgs + ionArgBytes); // 6. Store asm.js pinned registers #if defined(JS_CODEGEN_X64) @@ -6556,24 +6445,11 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit masm.setFramePushed(framePushed); // Store return value into argv[0] - unsigned offsetToArgv = StackArgBytes(coerceArgTypes); - JS_ASSERT(offsetToArgv % sizeof(Value) == 0); - masm.storeValue(JSReturnOperand, Address(StackPointer, offsetToArgv)); + masm.storeValue(JSReturnOperand, Address(StackPointer, offsetToCoerceArgv)); + // argument 0: argv ABIArgMIRTypeIter i(coerceArgTypes); - - // argument 0: cx - LoadAsmJSActivationIntoRegister(masm, scratch); - if (i->kind() == ABIArg::GPR) { - LoadJSContextFromActivation(masm, scratch, i->gpr()); - } else { - LoadJSContextFromActivation(masm, scratch, scratch); - masm.storePtr(scratch, Address(StackPointer, i->offsetFromArgBase())); - } - i++; - - // argument 1: argv - Address argv(StackPointer, offsetToArgv); + Address argv(StackPointer, offsetToCoerceArgv); if (i->kind() == ABIArg::GPR) { masm.computeEffectiveAddress(argv, i->gpr()); } else { @@ -6589,12 +6465,12 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit case RetType::Signed: masm.call(AsmJSImmPtr(AsmJSImm_CoerceInPlace_ToInt32)); masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel); - masm.unboxInt32(Address(StackPointer, offsetToArgv), ReturnReg); + masm.unboxInt32(Address(StackPointer, offsetToCoerceArgv), ReturnReg); break; case RetType::Double: masm.call(AsmJSImmPtr(AsmJSImm_CoerceInPlace_ToNumber)); masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel); - masm.loadDouble(Address(StackPointer, offsetToArgv), ReturnDoubleReg); + masm.loadDouble(Address(StackPointer, offsetToCoerceArgv), ReturnDoubleReg); break; default: MOZ_ASSUME_UNREACHABLE("Unsupported convert type"); @@ -6629,7 +6505,7 @@ GenerateStackOverflowExit(ModuleCompiler &m, Label *throwLabel) masm.align(CodeAlignment); masm.bind(&m.stackOverflowLabel()); - // The stack-overflow is checked before bumping the stack. + // For the benefit of AssertStackAlignment. masm.setFramePushed(0); // Store the frame pointer in AsmJSActivation::exitFP for stack unwinding. @@ -6637,24 +6513,8 @@ GenerateStackOverflowExit(ModuleCompiler &m, Label *throwLabel) LoadAsmJSActivationIntoRegister(masm, activation); masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitFP())); - MIRTypeVector argTypes(m.cx()); - argTypes.infallibleAppend(MIRType_Pointer); // cx - - unsigned stackDec = StackDecrementForCall(masm, argTypes); - masm.reserveStack(stackDec); - - ABIArgMIRTypeIter i(argTypes); - - // argument 0: cx - if (i->kind() == ABIArg::GPR) { - LoadJSContextFromActivation(masm, activation, i->gpr()); - } else { - LoadJSContextFromActivation(masm, activation, activation); - masm.storePtr(activation, Address(StackPointer, i->offsetFromArgBase())); - } - i++; - - JS_ASSERT(i.done()); + // Even without arguments, various platforms require stack adjustment. + masm.reserveStack(ComputeByteAlignment(AsmJSFrameSize + ShadowStackSpace, StackAlignment)); AssertStackAlignment(masm); masm.call(AsmJSImmPtr(AsmJSImm_ReportOverRecursed)); @@ -6697,34 +6557,23 @@ GenerateAsyncInterruptExit(ModuleCompiler &m, Label *throwLabel) masm.setFramePushed(0); // set to zero so we can use masm.framePushed() below masm.PushRegsInMask(AllRegsExceptSP); // save all GP/FP registers (except SP) - Register activation = ABIArgGenerator::NonArgReturnVolatileReg0; - Register scratch = ABIArgGenerator::NonArgReturnVolatileReg1; + Register scratch = ABIArgGenerator::NonArgReturnVolatileReg0; // Store resumePC into the reserved space. - LoadAsmJSActivationIntoRegister(masm, activation); - masm.loadPtr(Address(activation, AsmJSActivation::offsetOfResumePC()), scratch); + LoadAsmJSActivationIntoRegister(masm, scratch); + masm.loadPtr(Address(scratch, AsmJSActivation::offsetOfResumePC()), scratch); masm.storePtr(scratch, Address(StackPointer, masm.framePushed() + sizeof(void*))); // We know that StackPointer is word-aligned, but not necessarily // stack-aligned, so we need to align it dynamically. masm.mov(StackPointer, ABIArgGenerator::NonVolatileReg); -#if defined(JS_CODEGEN_X86) - // Ensure that at least one slot is pushed for passing 'cx' below. - masm.push(Imm32(0)); -#endif masm.andPtr(Imm32(~(StackAlignment - 1)), StackPointer); if (ShadowStackSpace) masm.subPtr(Imm32(ShadowStackSpace), StackPointer); - // argument 0: cx -#if defined(JS_CODEGEN_X86) - LoadJSContextFromActivation(masm, activation, scratch); - masm.storePtr(scratch, Address(StackPointer, 0)); -#elif defined(JS_CODEGEN_X64) - LoadJSContextFromActivation(masm, activation, IntArgReg0); -#endif - + AssertStackAlignment(masm); masm.call(AsmJSImmPtr(AsmJSImm_HandleExecutionInterrupt)); + masm.branchIfFalseBool(ReturnReg, throwLabel); // Restore the StackPointer to it's position before the call. @@ -6752,9 +6601,6 @@ GenerateAsyncInterruptExit(ModuleCompiler &m, Label *throwLabel) masm.loadPtr(Address(IntArgReg0, AsmJSActivation::offsetOfResumePC()), IntArgReg1); masm.storePtr(IntArgReg1, Address(s0, masm.framePushed())); - // argument 0: cx - masm.loadPtr(Address(IntArgReg0, AsmJSActivation::offsetOfContext()), IntArgReg0); - // MIPS ABI requires rewserving stack for registes $a0 to $a3. masm.subPtr(Imm32(4 * sizeof(intptr_t)), StackPointer); @@ -6791,9 +6637,6 @@ GenerateAsyncInterruptExit(ModuleCompiler &m, Label *throwLabel) masm.loadPtr(Address(IntArgReg0, AsmJSActivation::offsetOfResumePC()), IntArgReg1); masm.storePtr(IntArgReg1, Address(r6, 14 * sizeof(uint32_t*))); - // argument 0: cx - masm.loadPtr(Address(IntArgReg0, AsmJSActivation::offsetOfContext()), IntArgReg0); - masm.PushRegsInMask(RegisterSet(GeneralRegisterSet(0), FloatRegisterSet(FloatRegisters::AllDoubleMask))); // save all FP registers masm.call(AsmJSImm_HandleExecutionInterrupt); masm.branchIfFalseBool(ReturnReg, throwLabel); @@ -6842,9 +6685,6 @@ GenerateSyncInterruptExit(ModuleCompiler &m, Label *throwLabel) masm.align(CodeAlignment); masm.bind(&m.syncInterruptLabel()); - MIRTypeVector argTypes(m.cx()); - argTypes.infallibleAppend(MIRType_Pointer); // cx - // See AsmJSFrameSize comment in Assembler-shared.h. #if defined(JS_CODEGEN_ARM) masm.push(lr); @@ -6859,22 +6699,9 @@ GenerateSyncInterruptExit(ModuleCompiler &m, Label *throwLabel) masm.PushRegsInMask(VolatileRegs); - unsigned stackDec = StackDecrementForCall(masm, argTypes); + unsigned stackDec = StackDecrementForCall(masm, ShadowStackSpace); masm.reserveStack(stackDec); - ABIArgMIRTypeIter i(argTypes); - - // argument 0: cx - if (i->kind() == ABIArg::GPR) { - LoadJSContextFromActivation(masm, activation, i->gpr()); - } else { - LoadJSContextFromActivation(masm, activation, activation); - masm.storePtr(activation, Address(StackPointer, i->offsetFromArgBase())); - } - i++; - - JS_ASSERT(i.done()); - AssertStackAlignment(masm); masm.call(AsmJSImmPtr(AsmJSImm_HandleExecutionInterrupt)); masm.branchIfFalseBool(ReturnReg, throwLabel); diff --git a/js/src/jit/AsmJSModule.cpp b/js/src/jit/AsmJSModule.cpp index 4c2551567d6e..9afe6ca3b07f 100644 --- a/js/src/jit/AsmJSModule.cpp +++ b/js/src/jit/AsmJSModule.cpp @@ -32,6 +32,7 @@ #include "jsobjinlines.h" #include "frontend/ParseNode-inl.h" +#include "vm/Stack-inl.h" using namespace js; using namespace jit; @@ -448,9 +449,25 @@ AsmJSModule::setAutoFlushICacheRange() AutoFlushICache::setRange(uintptr_t(code_), pod.codeBytes_); } -static int32_t -CoerceInPlace_ToInt32(JSContext *cx, MutableHandleValue val) +static void +AsmJSReportOverRecursed() { + JSContext *cx = PerThreadData::innermostAsmJSActivation()->cx(); + js_ReportOverRecursed(cx); +} + +static void +AsmJSHandleExecutionInterrupt() +{ + JSContext *cx = PerThreadData::innermostAsmJSActivation()->cx(); + HandleExecutionInterrupt(cx); +} + +static int32_t +CoerceInPlace_ToInt32(MutableHandleValue val) +{ + JSContext *cx = PerThreadData::innermostAsmJSActivation()->cx(); + int32_t i32; if (!ToInt32(cx, val, &i32)) return false; @@ -460,8 +477,10 @@ CoerceInPlace_ToInt32(JSContext *cx, MutableHandleValue val) } static int32_t -CoerceInPlace_ToNumber(JSContext *cx, MutableHandleValue val) +CoerceInPlace_ToNumber(MutableHandleValue val) { + JSContext *cx = PerThreadData::innermostAsmJSActivation()->cx(); + double dbl; if (!ToNumber(cx, val, &dbl)) return false; @@ -470,19 +489,109 @@ CoerceInPlace_ToNumber(JSContext *cx, MutableHandleValue val) return true; } -namespace js { +static bool +TryEnablingIon(JSContext *cx, AsmJSModule &module, HandleFunction fun, uint32_t exitIndex, + int32_t argc, Value *argv) +{ + if (!fun->hasScript()) + return true; -// Defined in AsmJS.cpp: + // Test if the function is Ion compiled + JSScript *script = fun->nonLazyScript(); + if (!script->hasIonScript()) + return true; -int32_t -InvokeFromAsmJS_Ignore(JSContext *cx, int32_t exitIndex, int32_t argc, Value *argv); + // Currently we can't rectify arguments. Therefore disabling if argc is too low. + if (fun->nargs() > size_t(argc)) + return true; -int32_t -InvokeFromAsmJS_ToInt32(JSContext *cx, int32_t exitIndex, int32_t argc, Value *argv); + // Normally the types should corresond, since we just ran with those types, + // but there are reports this is asserting. Therefore doing it as a check, instead of DEBUG only. + if (!types::TypeScript::ThisTypes(script)->hasType(types::Type::UndefinedType())) + return true; + for(uint32_t i = 0; i < fun->nargs(); i++) { + types::StackTypeSet *typeset = types::TypeScript::ArgTypes(script, i); + types::Type type = types::Type::DoubleType(); + if (!argv[i].isDouble()) + type = types::Type::PrimitiveType(argv[i].extractNonDoubleType()); + if (!typeset->hasType(type)) + return true; + } -int32_t -InvokeFromAsmJS_ToNumber(JSContext *cx, int32_t exitIndex, int32_t argc, Value *argv); + // Enable + IonScript *ionScript = script->ionScript(); + if (!ionScript->addDependentAsmJSModule(cx, DependentAsmJSModuleExit(&module, exitIndex))) + return false; + module.exitIndexToGlobalDatum(exitIndex).exit = module.ionExitTrampoline(module.exit(exitIndex)); + return true; +} + +static bool +InvokeFromAsmJS(AsmJSActivation *activation, int32_t exitIndex, int32_t argc, Value *argv, + MutableHandleValue rval) +{ + JSContext *cx = activation->cx(); + AsmJSModule &module = activation->module(); + + RootedFunction fun(cx, module.exitIndexToGlobalDatum(exitIndex).fun); + RootedValue fval(cx, ObjectValue(*fun)); + if (!Invoke(cx, UndefinedValue(), fval, argc, argv, rval)) + return false; + + return TryEnablingIon(cx, module, fun, exitIndex, argc, argv); +} + +// Use an int32_t return type instead of bool since bool does not have a +// specified width and the caller is assuming a word-sized return. +static int32_t +InvokeFromAsmJS_Ignore(int32_t exitIndex, int32_t argc, Value *argv) +{ + AsmJSActivation *activation = PerThreadData::innermostAsmJSActivation(); + JSContext *cx = activation->cx(); + + RootedValue rval(cx); + return InvokeFromAsmJS(activation, exitIndex, argc, argv, &rval); +} + +// Use an int32_t return type instead of bool since bool does not have a +// specified width and the caller is assuming a word-sized return. +static int32_t +InvokeFromAsmJS_ToInt32(int32_t exitIndex, int32_t argc, Value *argv) +{ + AsmJSActivation *activation = PerThreadData::innermostAsmJSActivation(); + JSContext *cx = activation->cx(); + + RootedValue rval(cx); + if (!InvokeFromAsmJS(activation, exitIndex, argc, argv, &rval)) + return false; + + int32_t i32; + if (!ToInt32(cx, rval, &i32)) + return false; + + argv[0] = Int32Value(i32); + return true; +} + +// Use an int32_t return type instead of bool since bool does not have a +// specified width and the caller is assuming a word-sized return. +static int32_t +InvokeFromAsmJS_ToNumber(int32_t exitIndex, int32_t argc, Value *argv) +{ + AsmJSActivation *activation = PerThreadData::innermostAsmJSActivation(); + JSContext *cx = activation->cx(); + + RootedValue rval(cx); + if (!InvokeFromAsmJS(activation, exitIndex, argc, argv, &rval)) + return false; + + double dbl; + if (!ToNumber(cx, rval, &dbl)) + return false; + + argv[0] = DoubleValue(dbl); + return true; } #if defined(JS_CODEGEN_ARM) @@ -524,19 +633,19 @@ AddressOf(AsmJSImmKind kind, ExclusiveContext *cx) case AsmJSImm_StackLimit: return cx->stackLimitAddressForJitCode(StackForUntrustedScript); case AsmJSImm_ReportOverRecursed: - return RedirectCall(FuncCast(js_ReportOverRecursed), Args_General1); + return RedirectCall(FuncCast(AsmJSReportOverRecursed), Args_General0); case AsmJSImm_HandleExecutionInterrupt: - return RedirectCall(FuncCast(js::HandleExecutionInterrupt), Args_General1); + return RedirectCall(FuncCast(AsmJSHandleExecutionInterrupt), Args_General0); case AsmJSImm_InvokeFromAsmJS_Ignore: - return RedirectCall(FuncCast(InvokeFromAsmJS_Ignore), Args_General4); + return RedirectCall(FuncCast(InvokeFromAsmJS_Ignore), Args_General3); case AsmJSImm_InvokeFromAsmJS_ToInt32: - return RedirectCall(FuncCast(InvokeFromAsmJS_ToInt32), Args_General4); + return RedirectCall(FuncCast(InvokeFromAsmJS_ToInt32), Args_General3); case AsmJSImm_InvokeFromAsmJS_ToNumber: - return RedirectCall(FuncCast(InvokeFromAsmJS_ToNumber), Args_General4); + return RedirectCall(FuncCast(InvokeFromAsmJS_ToNumber), Args_General3); case AsmJSImm_CoerceInPlace_ToInt32: - return RedirectCall(FuncCast(CoerceInPlace_ToInt32), Args_General2); + return RedirectCall(FuncCast(CoerceInPlace_ToInt32), Args_General1); case AsmJSImm_CoerceInPlace_ToNumber: - return RedirectCall(FuncCast(CoerceInPlace_ToNumber), Args_General2); + return RedirectCall(FuncCast(CoerceInPlace_ToNumber), Args_General1); case AsmJSImm_ToInt32: return RedirectCall(FuncCast(js::ToInt32), Args_Int_Double); #if defined(JS_CODEGEN_ARM) diff --git a/js/src/jit/AsmJSSignalHandlers.cpp b/js/src/jit/AsmJSSignalHandlers.cpp index 236f689ae7ad..6ae3b1ffb83a 100644 --- a/js/src/jit/AsmJSSignalHandlers.cpp +++ b/js/src/jit/AsmJSSignalHandlers.cpp @@ -150,16 +150,6 @@ using mozilla::DebugOnly; // thread/stack as the victim (Unix and Windows), we can use TLS to find any // currently executing asm.js code. #if !defined(XP_MACOSX) -static AsmJSActivation * -InnermostAsmJSActivation() -{ - PerThreadData *threadData = TlsPerThreadData.get(); - if (!threadData) - return nullptr; - - return threadData->asmJSActivationStackFromOwnerThread(); -} - static JSRuntime * RuntimeForCurrentThread() { @@ -451,7 +441,7 @@ HandleException(PEXCEPTION_POINTERS exception) if (rt->jitRuntime() && rt->jitRuntime()->handleAccessViolation(rt, faultingAddress)) return true; - AsmJSActivation *activation = InnermostAsmJSActivation(); + AsmJSActivation *activation = PerThreadData::innermostAsmJSActivation(); if (!activation) return false; @@ -648,7 +638,7 @@ HandleMachException(JSRuntime *rt, const ExceptionRequest &request) if (rt->jitRuntime() && rt->jitRuntime()->handleAccessViolation(rt, faultingAddress)) return true; - AsmJSActivation *activation = rt->mainThread.asmJSActivationStackFromAnyThread(); + AsmJSActivation *activation = rt->mainThread.asmJSActivationStack(); if (!activation) return false; @@ -898,7 +888,7 @@ HandleSignal(int signum, siginfo_t *info, void *ctx) if (rt->jitRuntime() && rt->jitRuntime()->handleAccessViolation(rt, faultingAddress)) return true; - AsmJSActivation *activation = InnermostAsmJSActivation(); + AsmJSActivation *activation = PerThreadData::innermostAsmJSActivation(); if (!activation) return false; @@ -1048,7 +1038,7 @@ js::RequestInterruptForAsmJSCode(JSRuntime *rt, int interruptModeRaw) return; } - AsmJSActivation *activation = rt->mainThread.asmJSActivationStackFromAnyThread(); + AsmJSActivation *activation = rt->mainThread.asmJSActivationStack(); if (!activation) return; diff --git a/js/src/jit/arm/Simulator-arm.cpp b/js/src/jit/arm/Simulator-arm.cpp index 7fbf1f3efdff..d5315478f79a 100644 --- a/js/src/jit/arm/Simulator-arm.cpp +++ b/js/src/jit/arm/Simulator-arm.cpp @@ -4065,7 +4065,6 @@ Simulator::execute() // Get the PC to simulate. Cannot use the accessor here as we need the raw // PC value and not the one used as input to arithmetic instructions. int program_counter = get_pc(); - AsmJSActivation *activation = TlsPerThreadData.get()->asmJSActivationStackFromOwnerThread(); while (program_counter != end_sim_pc) { if (EnableStopSimAt && (icount_ == Simulator::StopSimAt)) { @@ -4080,7 +4079,7 @@ Simulator::execute() int32_t rpc = resume_pc_; if (MOZ_UNLIKELY(rpc != 0)) { // AsmJS signal handler ran and we have to adjust the pc. - activation->setResumePC((void *)get_pc()); + PerThreadData::innermostAsmJSActivation()->setResumePC((void *)get_pc()); set_pc(rpc); resume_pc_ = 0; } diff --git a/js/src/jit/mips/Simulator-mips.cpp b/js/src/jit/mips/Simulator-mips.cpp index 01759055b505..2250350c0f95 100644 --- a/js/src/jit/mips/Simulator-mips.cpp +++ b/js/src/jit/mips/Simulator-mips.cpp @@ -3310,7 +3310,7 @@ Simulator::execute() // Get the PC to simulate. Cannot use the accessor here as we need the // raw PC value and not the one used as input to arithmetic instructions. int program_counter = get_pc(); - AsmJSActivation *activation = TlsPerThreadData.get()->asmJSActivationStackFromOwnerThread(); + AsmJSActivation *activation = TlsPerThreadData.get()->asmJSActivationStack(); while (program_counter != end_sim_pc) { if (enableStopSimAt && (icount_ == Simulator::StopSimAt)) { diff --git a/js/src/vm/ArrayBufferObject.cpp b/js/src/vm/ArrayBufferObject.cpp index eec36de1acdc..e1e2ce5c9ac4 100644 --- a/js/src/vm/ArrayBufferObject.cpp +++ b/js/src/vm/ArrayBufferObject.cpp @@ -548,7 +548,7 @@ ArrayBufferObject::canNeuterAsmJSArrayBuffer(JSContext *cx, ArrayBufferObject &b { JS_ASSERT(!buffer.isSharedArrayBuffer()); #ifdef JS_ION - AsmJSActivation *act = cx->mainThread().asmJSActivationStackFromOwnerThread(); + AsmJSActivation *act = cx->mainThread().asmJSActivationStack(); for (; act; act = act->prevAsmJS()) { if (act->module().maybeHeapBufferObject() == &buffer) break; diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 58e20efef884..bb8fee16d6d3 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -591,11 +591,12 @@ class PerThreadData : public PerThreadDataFriendFields return offsetof(PerThreadData, activation_); } - js::AsmJSActivation *asmJSActivationStackFromAnyThread() const { + js::AsmJSActivation *asmJSActivationStack() const { return asmJSActivationStack_; } - js::AsmJSActivation *asmJSActivationStackFromOwnerThread() const { - return asmJSActivationStack_; + static js::AsmJSActivation *innermostAsmJSActivation() { + PerThreadData *ptd = TlsPerThreadData.get(); + return ptd ? ptd->asmJSActivationStack_ : nullptr; } js::Activation *activation() const {