зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 4 changesets (bug 1030446) for b2g non-unified build bustage on a CLOSED TREE
Backed out changeset d925c77d4b3f (bug 1030446) Backed out changeset 988f19a5ea1f (bug 1030446) Backed out changeset 6e87a7cf7eac (bug 1030446) Backed out changeset 1c761a455bbf (bug 1030446)
This commit is contained in:
Родитель
55a4baf944
Коммит
3fdbdfaeea
|
@ -98,9 +98,7 @@ assertThrowsValue(function() { f(8,2.4) }, 2.4+36);
|
|||
assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + 'var identity=imp.identity; function g(x) { x=+x; return +identity(x) } return g'), null, imp)(13.37), 13.37);
|
||||
|
||||
// Test asm.js => ion paths
|
||||
setJitCompilerOption("ion.usecount.trigger", 10);
|
||||
setJitCompilerOption("baseline.usecount.trigger", 0);
|
||||
setJitCompilerOption("offthread-compilation.enable", 0);
|
||||
setJitCompilerOption("ion.usecount.trigger", 20);
|
||||
|
||||
// In registers on x64 and ARM, on the stack for x86
|
||||
function ffiIntFew(a,b,c,d) { return d+1 }
|
||||
|
@ -111,32 +109,32 @@ for (var i = 0; i < 40; i++)
|
|||
// Stack and registers for x64 and ARM, stack for x86
|
||||
function ffiIntMany(a,b,c,d,e,f,g,h,i,j) { return j+1 }
|
||||
var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=i|0; return ffi(i|0,(i+1)|0,(i+2)|0,(i+3)|0,(i+4)|0,(i+5)|0,(i+6)|0,(i+7)|0,(i+8)|0,(i+9)|0)|0 } return f'), null, {ffi:ffiIntMany});
|
||||
for (var i = 0; i < 15; i++)
|
||||
for (var i = 0; i < 40; i++)
|
||||
assertEq(f(i), i+10);
|
||||
|
||||
// In registers on x64 and ARM, on the stack for x86
|
||||
function ffiDoubleFew(a,b,c,d) { return d+1 }
|
||||
var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=+i; return +ffi(i,i+1.0,i+2.0,i+3.0) } return f'), null, {ffi:ffiDoubleFew});
|
||||
for (var i = 0; i < 15; i++)
|
||||
for (var i = 0; i < 40; i++)
|
||||
assertEq(f(i), i+4);
|
||||
|
||||
// Stack and registers for x64 and ARM, stack for x86
|
||||
function ffiDoubleMany(a,b,c,d,e,f,g,h,i,j) { return j+1 }
|
||||
var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=+i; return +ffi(i,i+1.0,i+2.0,i+3.0,i+4.0,i+5.0,i+6.0,i+7.0,i+8.0,i+9.0) } return f'), null, {ffi:ffiDoubleMany});
|
||||
for (var i = 0; i < 15; i++)
|
||||
for (var i = 0; i < 40; i++)
|
||||
assertEq(f(i), i+10);
|
||||
|
||||
// Test the throw path
|
||||
function ffiThrow(n) { if (n == 14) throw 'yolo'; }
|
||||
function ffiThrow(n) { if (n == 38) throw 'yolo'; }
|
||||
var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=i|0; ffi(i >> 0); } return f'), null, {ffi:ffiThrow});
|
||||
var i = 0;
|
||||
try {
|
||||
for (; i < 15; i++)
|
||||
for (; i < 40; i++)
|
||||
f(i);
|
||||
throw 'assume unreachable';
|
||||
} catch (e) {
|
||||
assertEq(e, 'yolo');
|
||||
assertEq(i, 14);
|
||||
assertEq(i, 38);
|
||||
}
|
||||
|
||||
// OOL conversion paths
|
||||
|
|
|
@ -17,14 +17,10 @@ function dumpStack()
|
|||
stack = new Error().stack
|
||||
}
|
||||
|
||||
setJitCompilerOption("ion.usecount.trigger", 10);
|
||||
setJitCompilerOption("baseline.usecount.trigger", 0);
|
||||
setJitCompilerOption("offthread-compilation.enable", 0);
|
||||
|
||||
var callFFI = asmCompile('global', 'ffis', USE_ASM + "var ffi=ffis.ffi; function f() { return ffi()|0 } return f");
|
||||
|
||||
var f = asmLink(callFFI, null, {ffi:dumpStack});
|
||||
for (var i = 0; i < 15; i++) {
|
||||
for (var i = 0; i < 5000; i++) {
|
||||
stack = null;
|
||||
f();
|
||||
matchStack(stack, ['dumpStack', 'f']);
|
||||
|
@ -46,7 +42,7 @@ matchStack(stack, ["dumpStack", "f", "middle", "f"]);
|
|||
|
||||
function returnStackDumper() { return { valueOf:function() { stack = new Error().stack } } }
|
||||
var f = asmLink(callFFI, null, {ffi:returnStackDumper});
|
||||
for (var i = 0; i < 15; i++) {
|
||||
for (var i = 0; i < 5000; i++) {
|
||||
stack = null;
|
||||
f();
|
||||
matchStack(stack, ['valueOf', 'f']);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "jsprf.h"
|
||||
#include "prmjtime.h"
|
||||
|
||||
#include "assembler/assembler/MacroAssembler.h"
|
||||
#include "frontend/Parser.h"
|
||||
#include "jit/AsmJSLink.h"
|
||||
#include "jit/AsmJSModule.h"
|
||||
|
@ -1408,6 +1409,9 @@ class MOZ_STACK_CLASS ModuleCompiler
|
|||
return false;
|
||||
return exits_.add(p, Move(exitDescriptor), *exitIndex);
|
||||
}
|
||||
bool addFunctionName(PropertyName *name, uint32_t *index) {
|
||||
return module_->addFunctionName(name, index);
|
||||
}
|
||||
|
||||
// Note a constraint on the minimum size of the heap. The heap size is
|
||||
// constrained when linking to be at least the maximum of all such constraints.
|
||||
|
@ -1439,11 +1443,6 @@ class MOZ_STACK_CLASS ModuleCompiler
|
|||
bool finishGeneratingFunction(Func &func, MIRGenerator &mir, CodeGenerator &codegen) {
|
||||
JS_ASSERT(func.defined() && func.code()->bound());
|
||||
|
||||
uint32_t beginOffset = func.code()->offset();
|
||||
uint32_t endOffset = masm_.currentOffset();
|
||||
if (!module_->addFunctionCodeRange(func.name(), beginOffset, endOffset))
|
||||
return false;
|
||||
|
||||
jit::IonScriptCounts *counts = codegen.extractScriptCounts();
|
||||
if (counts && !module_->addFunctionCounts(counts)) {
|
||||
js_delete(counts);
|
||||
|
@ -1481,19 +1480,15 @@ class MOZ_STACK_CLASS ModuleCompiler
|
|||
module_->finishFunctionBodies(masm_.currentOffset());
|
||||
}
|
||||
|
||||
void startGeneratingEntry(unsigned exportIndex) {
|
||||
module_->exportedFunction(exportIndex).initCodeOffset(masm_.currentOffset());
|
||||
}
|
||||
bool finishGeneratingEntry(unsigned exportIndex) {
|
||||
return module_->addEntryCodeRange(exportIndex, masm_.currentOffset());
|
||||
}
|
||||
|
||||
void setInterpExitOffset(unsigned exitIndex) {
|
||||
module_->exit(exitIndex).initInterpOffset(masm_.currentOffset());
|
||||
}
|
||||
void setIonExitOffset(unsigned exitIndex) {
|
||||
module_->exit(exitIndex).initIonOffset(masm_.currentOffset());
|
||||
}
|
||||
void setEntryOffset(unsigned exportIndex) {
|
||||
module_->exportedFunction(exportIndex).initCodeOffset(masm_.currentOffset());
|
||||
}
|
||||
|
||||
void buildCompilationTimeReport(bool storedInCache, ScopedJSFreePtr<char> *out) {
|
||||
ScopedJSFreePtr<char> slowFuns;
|
||||
|
@ -1813,6 +1808,7 @@ class FunctionCompiler
|
|||
ModuleCompiler & m_;
|
||||
LifoAlloc & lifo_;
|
||||
ParseNode * fn_;
|
||||
uint32_t functionNameIndex_;
|
||||
|
||||
LocalMap locals_;
|
||||
VarInitializerVector varInitializers_;
|
||||
|
@ -1833,11 +1829,15 @@ class FunctionCompiler
|
|||
LabeledBlockMap labeledBreaks_;
|
||||
LabeledBlockMap labeledContinues_;
|
||||
|
||||
static const uint32_t NO_FUNCTION_NAME_INDEX = UINT32_MAX;
|
||||
JS_STATIC_ASSERT(NO_FUNCTION_NAME_INDEX > CallSiteDesc::FUNCTION_NAME_INDEX_MAX);
|
||||
|
||||
public:
|
||||
FunctionCompiler(ModuleCompiler &m, ParseNode *fn, LifoAlloc &lifo)
|
||||
: m_(m),
|
||||
lifo_(lifo),
|
||||
fn_(fn),
|
||||
functionNameIndex_(NO_FUNCTION_NAME_INDEX),
|
||||
locals_(m.cx()),
|
||||
varInitializers_(m.cx()),
|
||||
alloc_(nullptr),
|
||||
|
@ -2279,7 +2279,12 @@ class FunctionCompiler
|
|||
uint32_t line, column;
|
||||
m_.tokenStream().srcCoords.lineNumAndColumnIndex(call.node_->pn_pos.begin, &line, &column);
|
||||
|
||||
CallSiteDesc desc(line, column);
|
||||
if (functionNameIndex_ == NO_FUNCTION_NAME_INDEX) {
|
||||
if (!m_.addFunctionName(FunctionName(fn_), &functionNameIndex_))
|
||||
return false;
|
||||
}
|
||||
|
||||
CallSiteDesc desc(line, column, functionNameIndex_);
|
||||
MAsmJSCall *ins = MAsmJSCall::New(alloc(), desc, callee, call.regArgs_, returnType,
|
||||
call.spIncrement_);
|
||||
if (!ins)
|
||||
|
@ -5950,7 +5955,7 @@ GenerateEntry(ModuleCompiler &m, const AsmJSModule::ExportedFunction &exportedFu
|
|||
// PushRegsInMask(NonVolatileRegs).
|
||||
masm.setFramePushed(0);
|
||||
|
||||
// See AsmJSFrameSize comment in Assembler-shared.h.
|
||||
// See AsmJSFrameSize comment in Assembler-*.h.
|
||||
#if defined(JS_CODEGEN_ARM)
|
||||
masm.push(lr);
|
||||
#endif // JS_CODEGEN_ARM
|
||||
|
@ -6025,7 +6030,7 @@ GenerateEntry(ModuleCompiler &m, const AsmJSModule::ExportedFunction &exportedFu
|
|||
|
||||
// Call into the real function.
|
||||
AssertStackAlignment(masm);
|
||||
masm.call(func.code());
|
||||
masm.call(CallSiteDesc::Entry(), func.code());
|
||||
|
||||
// Pop the stack and recover the original 'argv' argument passed to the
|
||||
// trampoline (which was pushed on the stack).
|
||||
|
@ -6209,18 +6214,14 @@ GenerateFFIInterpreterExit(ModuleCompiler &m, const ModuleCompiler::ExitDescript
|
|||
m.setInterpExitOffset(exitIndex);
|
||||
masm.setFramePushed(0);
|
||||
|
||||
// See AsmJSFrameSize comment in Assembler-shared.h.
|
||||
// See AsmJSFrameSize comment in Assembler-*.h.
|
||||
#if defined(JS_CODEGEN_ARM)
|
||||
masm.push(lr);
|
||||
#elif defined(JS_CODEGEN_MIPS)
|
||||
#endif
|
||||
#if defined(JS_CODEGEN_MIPS)
|
||||
masm.push(ra);
|
||||
#endif
|
||||
|
||||
// Store the frame pointer in AsmJSActivation::exitFP for stack unwinding.
|
||||
Register activation = ABIArgGenerator::NonArgReturnVolatileReg0;
|
||||
LoadAsmJSActivationIntoRegister(masm, activation);
|
||||
masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitFP()));
|
||||
|
||||
MIRType typeArray[] = { MIRType_Pointer, // cx
|
||||
MIRType_Pointer, // exitDatum
|
||||
MIRType_Int32, // argc
|
||||
|
@ -6239,11 +6240,16 @@ GenerateFFIInterpreterExit(ModuleCompiler &m, const ModuleCompiler::ExitDescript
|
|||
|
||||
// Fill the argument array.
|
||||
unsigned offsetToCallerStackArgs = AsmJSFrameSize + masm.framePushed();
|
||||
Register scratch = ABIArgGenerator::NonArgReturnVolatileReg1;
|
||||
Register scratch = ABIArgGenerator::NonArgReturnVolatileReg0;
|
||||
FillArgumentArray(m, exit.sig().args(), offsetToArgv, offsetToCallerStackArgs, scratch);
|
||||
|
||||
// Prepare the arguments for the call to InvokeFromAsmJS_*.
|
||||
ABIArgMIRTypeIter i(invokeArgTypes);
|
||||
Register activation = ABIArgGenerator::NonArgReturnVolatileReg1;
|
||||
LoadAsmJSActivationIntoRegister(masm, activation);
|
||||
|
||||
// Record sp in the AsmJSActivation for stack-walking.
|
||||
masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitSP()));
|
||||
|
||||
// argument 0: cx
|
||||
if (i->kind() == ABIArg::GPR) {
|
||||
|
@ -6284,16 +6290,16 @@ GenerateFFIInterpreterExit(ModuleCompiler &m, const ModuleCompiler::ExitDescript
|
|||
AssertStackAlignment(masm);
|
||||
switch (exit.sig().retType().which()) {
|
||||
case RetType::Void:
|
||||
masm.call(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_Ignore));
|
||||
masm.callExit(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_Ignore), i.stackBytesConsumedSoFar());
|
||||
masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
|
||||
break;
|
||||
case RetType::Signed:
|
||||
masm.call(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_ToInt32));
|
||||
masm.callExit(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_ToInt32), i.stackBytesConsumedSoFar());
|
||||
masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
|
||||
masm.unboxInt32(argv, ReturnReg);
|
||||
break;
|
||||
case RetType::Double:
|
||||
masm.call(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_ToNumber));
|
||||
masm.callExit(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_ToNumber), i.stackBytesConsumedSoFar());
|
||||
masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
|
||||
masm.loadDouble(argv, ReturnDoubleReg);
|
||||
break;
|
||||
|
@ -6305,11 +6311,6 @@ GenerateFFIInterpreterExit(ModuleCompiler &m, const ModuleCompiler::ExitDescript
|
|||
// Note: the caller is IonMonkey code which means there are no non-volatile
|
||||
// registers to restore.
|
||||
masm.freeStack(stackDec);
|
||||
|
||||
// Clear exitFP before the frame is destroyed.
|
||||
LoadAsmJSActivationIntoRegister(masm, activation);
|
||||
masm.storePtr(ImmWord(0), Address(activation, AsmJSActivation::offsetOfExitFP()));
|
||||
|
||||
masm.ret();
|
||||
}
|
||||
|
||||
|
@ -6334,6 +6335,9 @@ GenerateOOLConvert(ModuleCompiler &m, RetType retType, Label *throwLabel)
|
|||
Register activation = ABIArgGenerator::NonArgReturnVolatileReg1;
|
||||
LoadAsmJSActivationIntoRegister(masm, activation);
|
||||
|
||||
// Record sp in the AsmJSActivation for stack-walking.
|
||||
masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitSP()));
|
||||
|
||||
// Store real arguments
|
||||
ABIArgMIRTypeIter i(callArgTypes);
|
||||
|
||||
|
@ -6361,12 +6365,12 @@ GenerateOOLConvert(ModuleCompiler &m, RetType retType, Label *throwLabel)
|
|||
AssertStackAlignment(masm);
|
||||
switch (retType.which()) {
|
||||
case RetType::Signed:
|
||||
masm.call(AsmJSImmPtr(AsmJSImm_CoerceInPlace_ToInt32));
|
||||
masm.callExit(AsmJSImmPtr(AsmJSImm_CoerceInPlace_ToInt32), i.stackBytesConsumedSoFar());
|
||||
masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
|
||||
masm.unboxInt32(Address(StackPointer, offsetToArgv), ReturnReg);
|
||||
break;
|
||||
case RetType::Double:
|
||||
masm.call(AsmJSImmPtr(AsmJSImm_CoerceInPlace_ToNumber));
|
||||
masm.callExit(AsmJSImmPtr(AsmJSImm_CoerceInPlace_ToNumber), i.stackBytesConsumedSoFar());
|
||||
masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
|
||||
masm.loadDouble(Address(StackPointer, offsetToArgv), ReturnDoubleReg);
|
||||
break;
|
||||
|
@ -6384,22 +6388,19 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit
|
|||
m.setIonExitOffset(exitIndex);
|
||||
masm.setFramePushed(0);
|
||||
|
||||
// See AsmJSFrameSize comment in Assembler-shared.h.
|
||||
#if defined(JS_CODEGEN_ARM)
|
||||
masm.push(lr);
|
||||
#elif defined(JS_CODEGEN_MIPS)
|
||||
masm.push(ra);
|
||||
#endif
|
||||
|
||||
// Store the frame pointer in AsmJSActivation::exitFP for stack unwinding.
|
||||
Register activation = ABIArgGenerator::NonArgReturnVolatileReg0;
|
||||
LoadAsmJSActivationIntoRegister(masm, activation);
|
||||
masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitFP()));
|
||||
|
||||
// Ion does not preserve nonvolatile registers, so we have to preserve them.
|
||||
// See AsmJSFrameSize comment in Assembler-*.h.
|
||||
#if defined(JS_CODEGEN_X64)
|
||||
masm.Push(HeapReg);
|
||||
#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
|
||||
#elif defined(JS_CODEGEN_ARM)
|
||||
masm.push(lr);
|
||||
|
||||
// The GlobalReg (r10) and HeapReg (r11) also need to be restored before
|
||||
// returning to asm.js code.
|
||||
// The NANReg also needs to be restored, but is a constant and is reloaded before
|
||||
// returning to asm.js code.
|
||||
masm.PushRegsInMask(GeneralRegisterSet((1<<GlobalReg.code()) | (1<<HeapReg.code())));
|
||||
#elif defined(JS_CODEGEN_MIPS)
|
||||
masm.push(ra);
|
||||
masm.PushRegsInMask(GeneralRegisterSet((1<<GlobalReg.code()) | (1<<HeapReg.code())));
|
||||
#endif
|
||||
|
||||
|
@ -6497,6 +6498,19 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit
|
|||
Register reg2 = AsmJSIonExitRegE2;
|
||||
Register reg3 = AsmJSIonExitRegE3;
|
||||
|
||||
LoadAsmJSActivationIntoRegister(masm, reg0);
|
||||
|
||||
// Record sp in the AsmJSActivation for stack-walking.
|
||||
#if defined(JS_CODEGEN_MIPS)
|
||||
// Add a flag to indicate to AsmJSFrameIterator that we are calling
|
||||
// into Ion, since the offset from SP to the return address is
|
||||
// different when calling Ion vs. the native ABI.
|
||||
masm.ma_or(reg1, StackPointer, Imm32(0x1));
|
||||
masm.storePtr(reg1, Address(reg0, AsmJSActivation::offsetOfExitSP()));
|
||||
#else
|
||||
masm.storePtr(StackPointer, Address(reg0, AsmJSActivation::offsetOfExitSP()));
|
||||
#endif
|
||||
|
||||
// The following is inlined:
|
||||
// JSContext *cx = activation->cx();
|
||||
// Activation *act = cx->mainThread().activation();
|
||||
|
@ -6510,7 +6524,6 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit
|
|||
size_t offsetOfJitTop = offsetof(JSRuntime, mainThread) + offsetof(PerThreadData, jitTop);
|
||||
size_t offsetOfJitJSContext = offsetof(JSRuntime, mainThread) +
|
||||
offsetof(PerThreadData, jitJSContext);
|
||||
LoadAsmJSActivationIntoRegister(masm, reg0);
|
||||
masm.loadPtr(Address(reg0, AsmJSActivation::offsetOfContext()), reg3);
|
||||
masm.loadPtr(Address(reg3, JSContext::offsetOfRuntime()), reg0);
|
||||
masm.loadPtr(Address(reg0, offsetOfActivation), reg1);
|
||||
|
@ -6582,19 +6595,13 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit
|
|||
|
||||
masm.bind(&done);
|
||||
masm.freeStack(stackDec);
|
||||
|
||||
// Restore non-volatile registers saved in the prologue.
|
||||
#if defined(JS_CODEGEN_X64)
|
||||
masm.Pop(HeapReg);
|
||||
#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
|
||||
#endif
|
||||
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
|
||||
masm.loadConstantDouble(GenericNaN(), NANReg);
|
||||
masm.PopRegsInMask(GeneralRegisterSet((1<<GlobalReg.code()) | (1<<HeapReg.code())));
|
||||
#endif
|
||||
|
||||
// Clear exitFP before the frame is destroyed.
|
||||
LoadAsmJSActivationIntoRegister(masm, activation);
|
||||
masm.storePtr(ImmWord(0), Address(activation, AsmJSActivation::offsetOfExitFP()));
|
||||
|
||||
masm.ret();
|
||||
JS_ASSERT(masm.framePushed() == 0);
|
||||
|
||||
|
@ -6635,20 +6642,18 @@ GenerateStackOverflowExit(ModuleCompiler &m, Label *throwLabel)
|
|||
masm.align(CodeAlignment);
|
||||
masm.bind(&m.stackOverflowLabel());
|
||||
|
||||
// The stack-overflow is checked before bumping the stack.
|
||||
masm.setFramePushed(0);
|
||||
|
||||
// Store the frame pointer in AsmJSActivation::exitFP for stack unwinding.
|
||||
Register activation = ABIArgGenerator::NonArgReturnVolatileReg0;
|
||||
LoadAsmJSActivationIntoRegister(masm, activation);
|
||||
masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitFP()));
|
||||
|
||||
MIRTypeVector argTypes(m.cx());
|
||||
argTypes.infallibleAppend(MIRType_Pointer); // cx
|
||||
|
||||
unsigned stackDec = StackDecrementForCall(masm, argTypes, MaybeRetAddr);
|
||||
masm.reserveStack(stackDec);
|
||||
|
||||
Register activation = ABIArgGenerator::NonArgReturnVolatileReg0;
|
||||
LoadAsmJSActivationIntoRegister(masm, activation);
|
||||
|
||||
// Record sp in the AsmJSActivation for stack-walking.
|
||||
masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitSP()));
|
||||
|
||||
ABIArgMIRTypeIter i(argTypes);
|
||||
|
||||
// argument 0: cx
|
||||
|
@ -6663,11 +6668,7 @@ GenerateStackOverflowExit(ModuleCompiler &m, Label *throwLabel)
|
|||
JS_ASSERT(i.done());
|
||||
|
||||
AssertStackAlignment(masm);
|
||||
masm.call(AsmJSImmPtr(AsmJSImm_ReportOverRecursed));
|
||||
|
||||
// Clear exitFP before the frame is destroyed.
|
||||
LoadAsmJSActivationIntoRegister(masm, activation);
|
||||
masm.storePtr(ImmWord(0), Address(activation, AsmJSActivation::offsetOfExitFP()));
|
||||
masm.callExit(AsmJSImmPtr(AsmJSImm_ReportOverRecursed), i.stackBytesConsumedSoFar());
|
||||
|
||||
// Don't worry about restoring the stack; throwLabel will pop everything.
|
||||
masm.jump(throwLabel);
|
||||
|
@ -6866,10 +6867,10 @@ static bool
|
|||
GenerateStubs(ModuleCompiler &m)
|
||||
{
|
||||
for (unsigned i = 0; i < m.module().numExportedFunctions(); i++) {
|
||||
m.startGeneratingEntry(i);
|
||||
m.setEntryOffset(i);
|
||||
if (!GenerateEntry(m, m.module().exportedFunction(i)))
|
||||
return false;
|
||||
if (m.masm().oom() || !m.finishGeneratingEntry(i))
|
||||
if (m.masm().oom())
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "jit/AsmJSFrameIterator.h"
|
||||
|
||||
#include "jit/AsmJS.h"
|
||||
#include "jit/AsmJSModule.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
||||
static void *
|
||||
ReturnAddressFromFP(uint8_t *fp)
|
||||
{
|
||||
// In asm.js code, the "frame" consists of a single word: the saved
|
||||
// return address of the caller.
|
||||
static_assert(AsmJSFrameSize == sizeof(void*), "Frame size mismatch");
|
||||
return *(uint8_t**)fp;
|
||||
}
|
||||
|
||||
AsmJSFrameIterator::AsmJSFrameIterator(const AsmJSActivation &activation)
|
||||
: module_(&activation.module()),
|
||||
fp_(activation.exitFP())
|
||||
{
|
||||
if (!fp_)
|
||||
return;
|
||||
settle(ReturnAddressFromFP(fp_));
|
||||
}
|
||||
|
||||
void
|
||||
AsmJSFrameIterator::operator++()
|
||||
{
|
||||
JS_ASSERT(!done());
|
||||
fp_ += callsite_->stackDepth();
|
||||
settle(ReturnAddressFromFP(fp_));
|
||||
}
|
||||
|
||||
void
|
||||
AsmJSFrameIterator::settle(void *returnAddress)
|
||||
{
|
||||
const AsmJSModule::CodeRange *codeRange = module_->lookupCodeRange(ReturnAddressFromFP(fp_));
|
||||
JS_ASSERT(codeRange);
|
||||
codeRange_ = codeRange;
|
||||
|
||||
switch (codeRange->kind()) {
|
||||
case AsmJSModule::CodeRange::Entry:
|
||||
fp_ = nullptr;
|
||||
JS_ASSERT(done());
|
||||
return;
|
||||
case AsmJSModule::CodeRange::Function:
|
||||
callsite_ = module_->lookupCallSite(returnAddress);
|
||||
JS_ASSERT(callsite_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
JSAtom *
|
||||
AsmJSFrameIterator::functionDisplayAtom() const
|
||||
{
|
||||
JS_ASSERT(!done());
|
||||
return reinterpret_cast<const AsmJSModule::CodeRange*>(codeRange_)->functionName(*module_);
|
||||
}
|
||||
|
||||
unsigned
|
||||
AsmJSFrameIterator::computeLine(uint32_t *column) const
|
||||
{
|
||||
JS_ASSERT(!done());
|
||||
if (column)
|
||||
*column = callsite_->column();
|
||||
return callsite_->line();
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef jit_AsmJSFrameIterator_h
|
||||
#define jit_AsmJSFrameIterator_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
class JSAtom;
|
||||
|
||||
namespace js {
|
||||
|
||||
class AsmJSActivation;
|
||||
class AsmJSModule;
|
||||
namespace jit { struct CallSite; }
|
||||
|
||||
// Iterates over the frames of a single AsmJSActivation.
|
||||
class AsmJSFrameIterator
|
||||
{
|
||||
const AsmJSModule *module_;
|
||||
const jit::CallSite *callsite_;
|
||||
uint8_t *fp_;
|
||||
|
||||
// Really, a const AsmJSModule::CodeRange*, but no forward declarations of
|
||||
// nested classes, so use void* to avoid pulling in all of AsmJSModule.h.
|
||||
const void *codeRange_;
|
||||
|
||||
void settle(void *returnAddress);
|
||||
|
||||
public:
|
||||
explicit AsmJSFrameIterator() : module_(nullptr) {}
|
||||
explicit AsmJSFrameIterator(const AsmJSActivation &activation);
|
||||
void operator++();
|
||||
bool done() const { return !fp_; }
|
||||
JSAtom *functionDisplayAtom() const;
|
||||
unsigned computeLine(uint32_t *column) const;
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif // jit_AsmJSFrameIterator_h
|
|
@ -34,6 +34,101 @@ using namespace js::jit;
|
|||
using mozilla::IsNaN;
|
||||
using mozilla::PodZero;
|
||||
|
||||
static uint8_t *
|
||||
ReturnAddressForExitCall(uint8_t **psp)
|
||||
{
|
||||
uint8_t *sp = *psp;
|
||||
#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
|
||||
// For calls to Ion/C++ on x86/x64, the exitSP is the SP right before the call
|
||||
// to C++. Since the call instruction pushes the return address, we know
|
||||
// that the return address is 1 word below exitSP.
|
||||
return *(uint8_t**)(sp - sizeof(void*));
|
||||
#elif defined(JS_CODEGEN_ARM)
|
||||
// For calls to Ion/C++ on ARM, the *caller* pushes the return address on
|
||||
// the stack. For Ion, this is just part of the ABI. For C++, the return
|
||||
// address is explicitly pushed before the call since we cannot expect the
|
||||
// callee to immediately push lr. This means that exitSP points to the
|
||||
// return address.
|
||||
return *(uint8_t**)sp;
|
||||
#elif defined(JS_CODEGEN_MIPS)
|
||||
// On MIPS we have two cases: an exit to C++ will store the return address
|
||||
// at ShadowStackSpace above sp; an exit to Ion will store the return
|
||||
// address at sp. To distinguish the two cases, the low bit of sp (which is
|
||||
// aligned and therefore zero) is set for Ion exits.
|
||||
if (uintptr_t(sp) & 0x1) {
|
||||
sp = *psp -= 0x1; // Clear the low bit
|
||||
return *(uint8_t**)sp;
|
||||
}
|
||||
return *(uint8_t**)(sp + ShadowStackSpace);
|
||||
#else
|
||||
# error "Unknown architecture!"
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint8_t *
|
||||
ReturnAddressForJitCall(uint8_t *sp)
|
||||
{
|
||||
// Once inside JIT code, sp always points to the word before the return
|
||||
// address.
|
||||
return *(uint8_t**)(sp - sizeof(void*));
|
||||
}
|
||||
|
||||
AsmJSFrameIterator::AsmJSFrameIterator(const AsmJSActivation *activation)
|
||||
: module_(nullptr)
|
||||
{
|
||||
if (!activation || activation->isInterruptedSP())
|
||||
return;
|
||||
|
||||
module_ = &activation->module();
|
||||
sp_ = activation->exitSP();
|
||||
|
||||
settle(ReturnAddressForExitCall(&sp_));
|
||||
}
|
||||
|
||||
void
|
||||
AsmJSFrameIterator::operator++()
|
||||
{
|
||||
settle(ReturnAddressForJitCall(sp_));
|
||||
}
|
||||
|
||||
void
|
||||
AsmJSFrameIterator::settle(uint8_t *returnAddress)
|
||||
{
|
||||
callsite_ = module_->lookupCallSite(returnAddress);
|
||||
if (!callsite_ || callsite_->isEntry()) {
|
||||
module_ = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (callsite_->isEntry()) {
|
||||
module_ = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
sp_ += callsite_->stackDepth();
|
||||
|
||||
if (callsite_->isExit())
|
||||
return settle(ReturnAddressForJitCall(sp_));
|
||||
|
||||
JS_ASSERT(callsite_->isNormal());
|
||||
}
|
||||
|
||||
JSAtom *
|
||||
AsmJSFrameIterator::functionDisplayAtom() const
|
||||
{
|
||||
JS_ASSERT(!done());
|
||||
return module_->functionName(callsite_->functionNameIndex());
|
||||
}
|
||||
|
||||
unsigned
|
||||
AsmJSFrameIterator::computeLine(uint32_t *column) const
|
||||
{
|
||||
JS_ASSERT(!done());
|
||||
if (column)
|
||||
*column = callsite_->column();
|
||||
return callsite_->line();
|
||||
}
|
||||
|
||||
static bool
|
||||
CloneModule(JSContext *cx, MutableHandle<AsmJSModuleObject*> moduleObj)
|
||||
{
|
||||
|
|
|
@ -9,8 +9,31 @@
|
|||
|
||||
#include "NamespaceImports.h"
|
||||
|
||||
class JSAtom;
|
||||
|
||||
namespace js {
|
||||
|
||||
class AsmJSActivation;
|
||||
class AsmJSModule;
|
||||
namespace jit { struct CallSite; }
|
||||
|
||||
// Iterates over the frames of a single AsmJSActivation.
|
||||
class AsmJSFrameIterator
|
||||
{
|
||||
const AsmJSModule *module_;
|
||||
const jit::CallSite *callsite_;
|
||||
uint8_t *sp_;
|
||||
|
||||
void settle(uint8_t *returnAddress);
|
||||
|
||||
public:
|
||||
explicit AsmJSFrameIterator(const AsmJSActivation *activation);
|
||||
void operator++();
|
||||
bool done() const { return !module_; }
|
||||
JSAtom *functionDisplayAtom() const;
|
||||
unsigned computeLine(uint32_t *column) const;
|
||||
};
|
||||
|
||||
#ifdef JS_ION
|
||||
|
||||
// Create a new JSFunction to replace originalFun as the representation of the
|
||||
|
|
|
@ -167,7 +167,6 @@ AsmJSModule::addSizeOfMisc(mozilla::MallocSizeOf mallocSizeOf, size_t *asmJSModu
|
|||
exits_.sizeOfExcludingThis(mallocSizeOf) +
|
||||
exports_.sizeOfExcludingThis(mallocSizeOf) +
|
||||
callSites_.sizeOfExcludingThis(mallocSizeOf) +
|
||||
codeRanges_.sizeOfExcludingThis(mallocSizeOf) +
|
||||
functionNames_.sizeOfExcludingThis(mallocSizeOf) +
|
||||
heapAccesses_.sizeOfExcludingThis(mallocSizeOf) +
|
||||
functionCounts_.sizeOfExcludingThis(mallocSizeOf) +
|
||||
|
@ -190,11 +189,11 @@ struct CallSiteRetAddrOffset
|
|||
};
|
||||
|
||||
const CallSite *
|
||||
AsmJSModule::lookupCallSite(void *returnAddress) const
|
||||
AsmJSModule::lookupCallSite(uint8_t *returnAddress) const
|
||||
{
|
||||
JS_ASSERT(isFinished());
|
||||
|
||||
uint32_t target = ((uint8_t*)returnAddress) - code_;
|
||||
uint32_t target = returnAddress - code_;
|
||||
size_t lowerBound = 0;
|
||||
size_t upperBound = callSites_.length();
|
||||
|
||||
|
@ -205,45 +204,6 @@ AsmJSModule::lookupCallSite(void *returnAddress) const
|
|||
return &callSites_[match];
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
// Create an ordering on CodeRange and pc offsets suitable for BinarySearch.
|
||||
// Stick these in the same namespace as AsmJSModule so that argument-dependent
|
||||
// lookup will find it.
|
||||
bool
|
||||
operator==(size_t pcOffset, const AsmJSModule::CodeRange &rhs)
|
||||
{
|
||||
return pcOffset >= rhs.beginOffset() && pcOffset < rhs.endOffset();
|
||||
}
|
||||
bool
|
||||
operator<=(const AsmJSModule::CodeRange &lhs, const AsmJSModule::CodeRange &rhs)
|
||||
{
|
||||
return lhs.beginOffset() <= rhs.beginOffset();
|
||||
}
|
||||
bool
|
||||
operator<(size_t pcOffset, const AsmJSModule::CodeRange &rhs)
|
||||
{
|
||||
return pcOffset < rhs.beginOffset();
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
||||
const AsmJSModule::CodeRange *
|
||||
AsmJSModule::lookupCodeRange(void *pc) const
|
||||
{
|
||||
JS_ASSERT(isFinished());
|
||||
|
||||
uint32_t target = ((uint8_t*)pc) - code_;
|
||||
size_t lowerBound = 0;
|
||||
size_t upperBound = codeRanges_.length();
|
||||
|
||||
size_t match;
|
||||
if (!BinarySearch(codeRanges_, lowerBound, upperBound, target, &match))
|
||||
return nullptr;
|
||||
|
||||
return &codeRanges_[match];
|
||||
}
|
||||
|
||||
struct HeapAccessOffset
|
||||
{
|
||||
const AsmJSHeapAccessVector &accesses;
|
||||
|
@ -254,12 +214,12 @@ struct HeapAccessOffset
|
|||
};
|
||||
|
||||
const AsmJSHeapAccess *
|
||||
AsmJSModule::lookupHeapAccess(void *pc) const
|
||||
AsmJSModule::lookupHeapAccess(uint8_t *pc) const
|
||||
{
|
||||
JS_ASSERT(isFinished());
|
||||
JS_ASSERT(containsPC(pc));
|
||||
|
||||
uint32_t target = ((uint8_t*)pc) - code_;
|
||||
uint32_t target = pc - code_;
|
||||
size_t lowerBound = 0;
|
||||
size_t upperBound = heapAccesses_.length();
|
||||
|
||||
|
@ -333,11 +293,6 @@ AsmJSModule::finish(ExclusiveContext *cx, TokenStream &tokenStream, MacroAssembl
|
|||
CallSite &c = callSites_[i];
|
||||
c.setReturnAddressOffset(masm.actualOffset(c.returnAddressOffset()));
|
||||
}
|
||||
for (size_t i = 0; i < codeRanges_.length(); i++) {
|
||||
CodeRange &c = codeRanges_[i];
|
||||
c.beginOffset_ = masm.actualOffset(c.beginOffset_);
|
||||
c.endOffset_ = masm.actualOffset(c.endOffset_);
|
||||
}
|
||||
#endif
|
||||
JS_ASSERT(pod.functionBytes_ % AsmJSPageSize == 0);
|
||||
|
||||
|
@ -1129,7 +1084,6 @@ AsmJSModule::serializedSize() const
|
|||
SerializedVectorSize(exits_) +
|
||||
SerializedVectorSize(exports_) +
|
||||
SerializedPodVectorSize(callSites_) +
|
||||
SerializedPodVectorSize(codeRanges_) +
|
||||
SerializedVectorSize(functionNames_) +
|
||||
SerializedPodVectorSize(heapAccesses_) +
|
||||
#if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
|
||||
|
@ -1150,7 +1104,6 @@ AsmJSModule::serialize(uint8_t *cursor) const
|
|||
cursor = SerializeVector(cursor, exits_);
|
||||
cursor = SerializeVector(cursor, exports_);
|
||||
cursor = SerializePodVector(cursor, callSites_);
|
||||
cursor = SerializePodVector(cursor, codeRanges_);
|
||||
cursor = SerializeVector(cursor, functionNames_);
|
||||
cursor = SerializePodVector(cursor, heapAccesses_);
|
||||
#if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
|
||||
|
@ -1177,7 +1130,6 @@ AsmJSModule::deserialize(ExclusiveContext *cx, const uint8_t *cursor)
|
|||
(cursor = DeserializeVector(cx, cursor, &exits_)) &&
|
||||
(cursor = DeserializeVector(cx, cursor, &exports_)) &&
|
||||
(cursor = DeserializePodVector(cx, cursor, &callSites_)) &&
|
||||
(cursor = DeserializePodVector(cx, cursor, &codeRanges_)) &&
|
||||
(cursor = DeserializeVector(cx, cursor, &functionNames_)) &&
|
||||
(cursor = DeserializePodVector(cx, cursor, &heapAccesses_)) &&
|
||||
#if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
|
||||
|
@ -1248,7 +1200,6 @@ AsmJSModule::clone(JSContext *cx, ScopedJSDeletePtr<AsmJSModule> *moduleOut) con
|
|||
!CloneVector(cx, exits_, &out.exits_) ||
|
||||
!CloneVector(cx, exports_, &out.exports_) ||
|
||||
!ClonePodVector(cx, callSites_, &out.callSites_) ||
|
||||
!ClonePodVector(cx, codeRanges_, &out.codeRanges_) ||
|
||||
!CloneVector(cx, functionNames_, &out.functionNames_) ||
|
||||
!ClonePodVector(cx, heapAccesses_, &out.heapAccesses_) ||
|
||||
!staticLinkData_.clone(cx, &out.staticLinkData_))
|
||||
|
|
|
@ -313,33 +313,6 @@ class AsmJSModule
|
|||
bool clone(ExclusiveContext *cx, ExportedFunction *out) const;
|
||||
};
|
||||
|
||||
class CodeRange
|
||||
{
|
||||
public:
|
||||
enum Kind { Entry, Function };
|
||||
|
||||
private:
|
||||
Kind kind_;
|
||||
uint32_t beginOffset_;
|
||||
uint32_t endOffset_;
|
||||
uint32_t functionNameIndex_;
|
||||
|
||||
friend class AsmJSModule;
|
||||
CodeRange(Kind kind, uint32_t beginOffset, uint32_t endOffset)
|
||||
: kind_(kind), beginOffset_(beginOffset), endOffset_(endOffset)
|
||||
{}
|
||||
|
||||
public:
|
||||
CodeRange() {}
|
||||
Kind kind() const { return kind_; }
|
||||
uint32_t beginOffset() const { return beginOffset_; }
|
||||
uint32_t endOffset() const { return endOffset_; }
|
||||
PropertyName *functionName(const AsmJSModule &module) const {
|
||||
JS_ASSERT(kind_ == Function);
|
||||
return module.functionNames_[functionNameIndex_].name();
|
||||
}
|
||||
};
|
||||
|
||||
class Name
|
||||
{
|
||||
PropertyName *name_;
|
||||
|
@ -506,7 +479,6 @@ class AsmJSModule
|
|||
Vector<Exit, 0, SystemAllocPolicy> exits_;
|
||||
Vector<ExportedFunction, 0, SystemAllocPolicy> exports_;
|
||||
Vector<jit::CallSite, 0, SystemAllocPolicy> callSites_;
|
||||
Vector<CodeRange, 0, SystemAllocPolicy> codeRanges_;
|
||||
Vector<Name, 0, SystemAllocPolicy> functionNames_;
|
||||
Vector<jit::AsmJSHeapAccess, 0, SystemAllocPolicy> heapAccesses_;
|
||||
Vector<jit::IonScriptCounts*, 0, SystemAllocPolicy> functionCounts_;
|
||||
|
@ -694,21 +666,17 @@ class AsmJSModule
|
|||
if (len > pod.minHeapLength_)
|
||||
pod.minHeapLength_ = len;
|
||||
}
|
||||
bool addFunctionCodeRange(PropertyName *name, uint32_t beginOffset, uint32_t endOffset) {
|
||||
bool addFunctionName(PropertyName *name, uint32_t *nameIndex) {
|
||||
JS_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies());
|
||||
JS_ASSERT(name->isTenured());
|
||||
JS_ASSERT(beginOffset <= endOffset);
|
||||
JS_ASSERT_IF(!codeRanges_.empty(), codeRanges_.back().endOffset() <= beginOffset);
|
||||
if (functionNames_.length() >= UINT32_MAX)
|
||||
if (functionNames_.length() > jit::CallSiteDesc::FUNCTION_NAME_INDEX_MAX)
|
||||
return false;
|
||||
CodeRange codeRange(CodeRange::Function, beginOffset, endOffset);
|
||||
codeRange.functionNameIndex_ = functionNames_.length();
|
||||
return functionNames_.append(name) && codeRanges_.append(codeRange);
|
||||
*nameIndex = functionNames_.length();
|
||||
return functionNames_.append(name);
|
||||
}
|
||||
bool addEntryCodeRange(unsigned exportIndex, uint32_t endOffset) {
|
||||
uint32_t beginOffset = exports_[exportIndex].pod.codeOffset_;
|
||||
CodeRange codeRange(CodeRange::Entry, beginOffset, endOffset);
|
||||
return codeRanges_.append(codeRange);
|
||||
PropertyName *functionName(uint32_t i) const {
|
||||
JS_ASSERT(isFinished());
|
||||
return functionNames_[i].name();
|
||||
}
|
||||
bool addExit(unsigned ffiIndex, unsigned *exitIndex) {
|
||||
JS_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies());
|
||||
|
@ -884,15 +852,11 @@ class AsmJSModule
|
|||
|
||||
// Lookup a callsite by the return pc (from the callee to the caller).
|
||||
// Return null if no callsite was found.
|
||||
const jit::CallSite *lookupCallSite(void *returnAddress) const;
|
||||
|
||||
// Lookup the name the code range containing the given pc. Return null if no
|
||||
// code range was found.
|
||||
const CodeRange *lookupCodeRange(void *pc) const;
|
||||
const jit::CallSite *lookupCallSite(uint8_t *returnAddress) const;
|
||||
|
||||
// Lookup a heap access site by the pc which performs the access. Return
|
||||
// null if no heap access was found.
|
||||
const jit::AsmJSHeapAccess *lookupHeapAccess(void *pc) const;
|
||||
const jit::AsmJSHeapAccess *lookupHeapAccess(uint8_t *pc) const;
|
||||
|
||||
// The global data section is placed after the executable code (i.e., at
|
||||
// offset codeBytes_) in the module's linear allocation. The global data
|
||||
|
|
|
@ -356,7 +356,7 @@ HandleSimulatorInterrupt(JSRuntime *rt, AsmJSActivation *activation, void *fault
|
|||
if (module.containsPC((void *)rt->mainThread.simulator()->get_pc()) &&
|
||||
module.containsPC(faultingAddress))
|
||||
{
|
||||
activation->setResumePC(nullptr);
|
||||
activation->setInterrupted(nullptr);
|
||||
int32_t nextpc = int32_t(module.interruptExit());
|
||||
rt->mainThread.simulator()->set_resume_pc(nextpc);
|
||||
return true;
|
||||
|
@ -465,7 +465,7 @@ HandleException(PEXCEPTION_POINTERS exception)
|
|||
// The trampoline will jump to activation->resumePC if execution isn't
|
||||
// interrupted.
|
||||
if (module.containsPC(faultingAddress)) {
|
||||
activation->setResumePC(pc);
|
||||
activation->setInterrupted(pc);
|
||||
*ppc = module.interruptExit();
|
||||
|
||||
JSRuntime::AutoLockForInterrupt lock(rt);
|
||||
|
@ -668,7 +668,7 @@ HandleMachException(JSRuntime *rt, const ExceptionRequest &request)
|
|||
// The trampoline will jump to activation->resumePC if execution isn't
|
||||
// interrupted.
|
||||
if (module.containsPC(faultingAddress)) {
|
||||
activation->setResumePC(pc);
|
||||
activation->setInterrupted(pc);
|
||||
*ppc = module.interruptExit();
|
||||
|
||||
JSRuntime::AutoLockForInterrupt lock(rt);
|
||||
|
@ -918,7 +918,7 @@ HandleSignal(int signum, siginfo_t *info, void *ctx)
|
|||
// The trampoline will jump to activation->resumePC if execution isn't
|
||||
// interrupted.
|
||||
if (module.containsPC(faultingAddress)) {
|
||||
activation->setResumePC(pc);
|
||||
activation->setInterrupted(pc);
|
||||
*ppc = module.interruptExit();
|
||||
|
||||
JSRuntime::AutoLockForInterrupt lock(rt);
|
||||
|
|
|
@ -8573,7 +8573,7 @@ CodeGenerator::visitAsmJSCall(LAsmJSCall *ins)
|
|||
masm.call(mir->desc(), ToRegister(ins->getOperand(mir->dynamicCalleeOperandIndex())));
|
||||
break;
|
||||
case MAsmJSCall::Callee::Builtin:
|
||||
masm.call(AsmJSImmPtr(callee.builtin()));
|
||||
masm.call(mir->desc(), AsmJSImmPtr(callee.builtin()));
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -141,6 +141,12 @@ static const uint32_t StackAlignment = 8;
|
|||
static const uint32_t CodeAlignment = 8;
|
||||
static const bool StackKeptAligned = true;
|
||||
|
||||
// As an invariant across architectures, within asm.js code:
|
||||
// $sp % StackAlignment = (AsmJSFrameSize + masm.framePushed) % StackAlignment
|
||||
// To achieve this on ARM, the first instruction of the asm.js prologue pushes
|
||||
// lr without incrementing masm.framePushed.
|
||||
static const uint32_t AsmJSFrameSize = sizeof(void*);
|
||||
|
||||
static const Scale ScalePointer = TimesFour;
|
||||
|
||||
class Instruction;
|
||||
|
|
|
@ -53,7 +53,7 @@ CodeGeneratorARM::generateAsmJSPrologue(Label *stackOverflowLabel)
|
|||
{
|
||||
JS_ASSERT(gen->compilingAsmJS());
|
||||
|
||||
// See comment in Assembler-shared.h about AsmJSFrameSize.
|
||||
// See comment in Assembler-arm.h about AsmJSFrameSize.
|
||||
masm.push(lr);
|
||||
|
||||
// The asm.js over-recursed handler wants to be able to assume that SP
|
||||
|
|
|
@ -1789,17 +1789,6 @@ MacroAssemblerARMCompat::callIon(Register callee)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerARMCompat::callIonFromAsmJS(Register callee)
|
||||
{
|
||||
ma_callIonNoPush(callee);
|
||||
|
||||
// The Ion ABI has the callee pop the return address off the stack.
|
||||
// The asm.js caller assumes that the call leaves sp unchanged, so bump
|
||||
// the stack.
|
||||
subPtr(Imm32(sizeof(void*)), sp);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerARMCompat::reserveStack(uint32_t amount)
|
||||
{
|
||||
|
@ -3635,6 +3624,19 @@ MacroAssemblerARM::ma_call(ImmPtr dest)
|
|||
as_blx(CallReg);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerARM::ma_callAndStoreRet(const Register r, uint32_t stackArgBytes)
|
||||
{
|
||||
// Note: this function stores the return address to sp[0]. The caller must
|
||||
// anticipate this by pushing additional space on the stack. The ABI does
|
||||
// not provide space for a return address so this function may only be
|
||||
// called if no argument are passed.
|
||||
JS_ASSERT(stackArgBytes == 0);
|
||||
AutoForbidPools afp(this);
|
||||
as_dtr(IsStore, 32, Offset, pc, DTRAddr(sp, DtrOffImm(0)));
|
||||
as_blx(r);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerARMCompat::breakpoint()
|
||||
{
|
||||
|
|
|
@ -397,6 +397,9 @@ class MacroAssemblerARM : public Assembler
|
|||
|
||||
void ma_call(ImmPtr dest);
|
||||
|
||||
// calls reg, storing the return address into sp[0]
|
||||
void ma_callAndStoreRet(const Register reg, uint32_t stackArgBytes);
|
||||
|
||||
// Float registers can only be loaded/stored in continuous runs
|
||||
// when using vstm/vldm.
|
||||
// This function breaks set into continuous runs and loads/stores
|
||||
|
@ -563,13 +566,38 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
|||
ma_movPatchable(ImmPtr(c->raw()), ScratchRegister, Always, rs);
|
||||
ma_callIonHalfPush(ScratchRegister);
|
||||
}
|
||||
|
||||
void appendCallSite(const CallSiteDesc &desc) {
|
||||
// Add an extra sizeof(void*) to include the return address that was
|
||||
// pushed by the call instruction (see CallSite::stackDepth).
|
||||
enoughMemory_ &= append(CallSite(desc, currentOffset(), framePushed_ + AsmJSFrameSize));
|
||||
}
|
||||
|
||||
void call(const CallSiteDesc &desc, const Register reg) {
|
||||
call(reg);
|
||||
enoughMemory_ &= append(desc, currentOffset(), framePushed_);
|
||||
appendCallSite(desc);
|
||||
}
|
||||
void call(const CallSiteDesc &desc, Label *label) {
|
||||
call(label);
|
||||
enoughMemory_ &= append(desc, currentOffset(), framePushed_);
|
||||
appendCallSite(desc);
|
||||
}
|
||||
void call(const CallSiteDesc &desc, AsmJSImmPtr imm) {
|
||||
call(imm);
|
||||
appendCallSite(desc);
|
||||
}
|
||||
void callExit(AsmJSImmPtr imm, uint32_t stackArgBytes) {
|
||||
movePtr(imm, CallReg);
|
||||
ma_callAndStoreRet(CallReg, stackArgBytes);
|
||||
appendCallSite(CallSiteDesc::Exit());
|
||||
}
|
||||
void callIonFromAsmJS(const Register reg) {
|
||||
ma_callIonNoPush(reg);
|
||||
appendCallSite(CallSiteDesc::Exit());
|
||||
|
||||
// The Ion ABI has the callee pop the return address off the stack.
|
||||
// The asm.js caller assumes that the call leaves sp unchanged, so bump
|
||||
// the stack.
|
||||
subPtr(Imm32(sizeof(void*)), sp);
|
||||
}
|
||||
|
||||
void branch(JitCode *c) {
|
||||
|
@ -1259,7 +1287,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
|||
// Makes an Ion call using the only two methods that it is sane for
|
||||
// indep code to make a call
|
||||
void callIon(Register callee);
|
||||
void callIonFromAsmJS(Register callee);
|
||||
|
||||
void reserveStack(uint32_t amount);
|
||||
void freeStack(uint32_t amount);
|
||||
|
|
|
@ -4070,7 +4070,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());
|
||||
activation->setInterrupted((void *)get_pc());
|
||||
set_pc(rpc);
|
||||
resume_pc_ = 0;
|
||||
}
|
||||
|
|
|
@ -152,6 +152,12 @@ static const uint32_t StackAlignment = 8;
|
|||
static const uint32_t CodeAlignment = 4;
|
||||
static const bool StackKeptAligned = true;
|
||||
|
||||
// As an invariant across architectures, within asm.js code:
|
||||
// $sp % StackAlignment = (AsmJSFrameSize + masm.framePushed) % StackAlignment
|
||||
// To achieve this on MIPS, the first instruction of the asm.js prologue pushes
|
||||
// ra without incrementing masm.framePushed.
|
||||
static const uint32_t AsmJSFrameSize = sizeof(void*);
|
||||
|
||||
static const Scale ScalePointer = TimesFour;
|
||||
|
||||
// MIPS instruction types
|
||||
|
|
|
@ -52,7 +52,7 @@ CodeGeneratorMIPS::generateAsmJSPrologue(Label *stackOverflowLabel)
|
|||
{
|
||||
JS_ASSERT(gen->compilingAsmJS());
|
||||
|
||||
// See comment in Assembler-shared.h about AsmJSFrameSize.
|
||||
// See comment in Assembler-mips.h about AsmJSFrameSize.
|
||||
masm.push(ra);
|
||||
|
||||
// The asm.js over-recursed handler wants to be able to assume that SP
|
||||
|
|
|
@ -1525,16 +1525,6 @@ MacroAssemblerMIPSCompat::callIon(Register callee)
|
|||
ma_callIon(callee);
|
||||
}
|
||||
}
|
||||
void
|
||||
MacroAssemblerMIPSCompat::callIonFromAsmJS(Register callee)
|
||||
{
|
||||
ma_callIonNoPush(reg);
|
||||
|
||||
// The Ion ABI has the callee pop the return address off the stack.
|
||||
// The asm.js caller assumes that the call leaves sp unchanged, so bump
|
||||
// the stack.
|
||||
subPtr(Imm32(sizeof(void*)), StackPointer);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::reserveStack(uint32_t amount)
|
||||
|
@ -2970,6 +2960,21 @@ MacroAssemblerMIPS::ma_callIonHalfPush(const Register r)
|
|||
as_sw(ra, StackPointer, 0);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPS::ma_callAndStoreRet(const Register r, uint32_t stackArgBytes)
|
||||
{
|
||||
// Note: this function stores the return address to sp[16]. The caller
|
||||
// must anticipate this by reserving additional space on the stack.
|
||||
// The ABI does not provide space for a return address so this function
|
||||
// stores 'ra' before any ABI arguments.
|
||||
// This function may only be called if there are 4 or less arguments.
|
||||
JS_ASSERT(stackArgBytes == 4 * sizeof(uintptr_t));
|
||||
|
||||
// This is a MIPS hack to push return address during jalr delay slot.
|
||||
as_jalr(r);
|
||||
as_sw(ra, StackPointer, 4 * sizeof(uintptr_t));
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPS::ma_call(ImmPtr dest)
|
||||
{
|
||||
|
|
|
@ -301,6 +301,9 @@ class MacroAssemblerMIPS : public Assembler
|
|||
// calls an ion function, assuming that the stack is currently not 8 byte aligned
|
||||
void ma_callIonHalfPush(const Register reg);
|
||||
|
||||
// calls reg, storing the return address into sp[stackArgBytes]
|
||||
void ma_callAndStoreRet(const Register reg, uint32_t stackArgBytes);
|
||||
|
||||
void ma_call(ImmPtr dest);
|
||||
|
||||
void ma_jump(ImmPtr dest);
|
||||
|
@ -412,13 +415,38 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS
|
|||
ma_liPatchable(ScratchRegister, Imm32((uint32_t)c->raw()));
|
||||
ma_callIonHalfPush(ScratchRegister);
|
||||
}
|
||||
|
||||
void appendCallSite(const CallSiteDesc &desc) {
|
||||
// Add an extra sizeof(void*) to include the return address that was
|
||||
// pushed by the call instruction (see CallSite::stackDepth).
|
||||
enoughMemory_ &= append(CallSite(desc, currentOffset(), framePushed_ + AsmJSFrameSize));
|
||||
}
|
||||
|
||||
void call(const CallSiteDesc &desc, const Register reg) {
|
||||
call(reg);
|
||||
enoughMemory_ &= append(desc, currentOffset(), framePushed_);
|
||||
appendCallSite(desc);
|
||||
}
|
||||
void call(const CallSiteDesc &desc, Label *label) {
|
||||
call(label);
|
||||
enoughMemory_ &= append(desc, currentOffset(), framePushed_);
|
||||
appendCallSite(desc);
|
||||
}
|
||||
void call(const CallSiteDesc &desc, AsmJSImmPtr imm) {
|
||||
call(imm);
|
||||
appendCallSite(desc);
|
||||
}
|
||||
void callExit(AsmJSImmPtr imm, uint32_t stackArgBytes) {
|
||||
movePtr(imm, CallReg);
|
||||
ma_callAndStoreRet(CallReg, stackArgBytes);
|
||||
appendCallSite(CallSiteDesc::Exit());
|
||||
}
|
||||
void callIonFromAsmJS(const Register reg) {
|
||||
ma_callIonNoPush(reg);
|
||||
appendCallSite(CallSiteDesc::Exit());
|
||||
|
||||
// The Ion ABI has the callee pop the return address off the stack.
|
||||
// The asm.js caller assumes that the call leaves sp unchanged, so bump
|
||||
// the stack.
|
||||
subPtr(Imm32(sizeof(void*)), StackPointer);
|
||||
}
|
||||
|
||||
void branch(JitCode *c) {
|
||||
|
@ -965,7 +993,6 @@ public:
|
|||
// Makes an Ion call using the only two methods that it is sane for
|
||||
// indep code to make a call
|
||||
void callIon(Register callee);
|
||||
void callIonFromAsmJS(Register callee);
|
||||
|
||||
void reserveStack(uint32_t amount);
|
||||
void freeStack(uint32_t amount);
|
||||
|
|
|
@ -577,19 +577,48 @@ class CodeLocationLabel
|
|||
}
|
||||
};
|
||||
|
||||
// While the frame-pointer chain allows the stack to be unwound without
|
||||
// metadata, Error.stack still needs to know the line/column of every call in
|
||||
// the chain. A CallSiteDesc describes the line/column of a single callsite.
|
||||
// A CallSiteDesc is created by callers of MacroAssembler.
|
||||
// Describes the user-visible properties of a callsite.
|
||||
//
|
||||
// A few general notes about the stack-walking supported by CallSite(Desc):
|
||||
// - This information facilitates stack-walking performed by FrameIter which
|
||||
// is used by Error.stack and other user-visible stack-walking functions.
|
||||
// - Ion/asm.js calling conventions do not maintain a frame-pointer so
|
||||
// stack-walking must lookup the stack depth based on the PC.
|
||||
// - Stack-walking only occurs from C++ after a synchronous calls (JS-to-JS and
|
||||
// JS-to-C++). Thus, we do not need to map arbitrary PCs to stack-depths,
|
||||
// just the return address at callsites.
|
||||
// - An exception to the above rule is the interrupt callback which can happen
|
||||
// at arbitrary PCs. In such cases, we drop frames from the stack-walk. In
|
||||
// the future when a full PC->stack-depth map is maintained, we handle this
|
||||
// case.
|
||||
class CallSiteDesc
|
||||
{
|
||||
uint32_t line_;
|
||||
uint32_t column_;
|
||||
uint32_t functionNameIndex_;
|
||||
|
||||
static const uint32_t sEntryTrampoline = UINT32_MAX;
|
||||
static const uint32_t sExit = UINT32_MAX - 1;
|
||||
|
||||
public:
|
||||
static const uint32_t FUNCTION_NAME_INDEX_MAX = UINT32_MAX - 2;
|
||||
|
||||
CallSiteDesc() {}
|
||||
CallSiteDesc(uint32_t line, uint32_t column) : line_(line), column_(column) {}
|
||||
uint32_t line() const { return line_; }
|
||||
uint32_t column() const { return column_; }
|
||||
|
||||
CallSiteDesc(uint32_t line, uint32_t column, uint32_t functionNameIndex)
|
||||
: line_(line), column_(column), functionNameIndex_(functionNameIndex)
|
||||
{}
|
||||
|
||||
static CallSiteDesc Entry() { return CallSiteDesc(0, 0, sEntryTrampoline); }
|
||||
static CallSiteDesc Exit() { return CallSiteDesc(0, 0, sExit); }
|
||||
|
||||
bool isEntry() const { return functionNameIndex_ == sEntryTrampoline; }
|
||||
bool isExit() const { return functionNameIndex_ == sExit; }
|
||||
bool isNormal() const { return !(isEntry() || isExit()); }
|
||||
|
||||
uint32_t line() const { JS_ASSERT(isNormal()); return line_; }
|
||||
uint32_t column() const { JS_ASSERT(isNormal()); return column_; }
|
||||
uint32_t functionNameIndex() const { JS_ASSERT(isNormal()); return functionNameIndex_; }
|
||||
};
|
||||
|
||||
// Adds to CallSiteDesc the metadata necessary to walk the stack given an
|
||||
|
@ -612,21 +641,13 @@ struct CallSite : public CallSiteDesc
|
|||
uint32_t returnAddressOffset() const { return returnAddressOffset_; }
|
||||
|
||||
// The stackDepth measures the amount of stack space pushed since the
|
||||
// function was called. In particular, this includes the pushed return
|
||||
// address on all archs (whether or not the call instruction pushes the
|
||||
// return address (x86/x64) or the prologue does (ARM/MIPS).
|
||||
uint32_t stackDepth() const { return stackDepth_; }
|
||||
// function was called. In particular, this includes the word pushed by the
|
||||
// call instruction on x86/x64.
|
||||
uint32_t stackDepth() const { JS_ASSERT(!isEntry()); return stackDepth_; }
|
||||
};
|
||||
|
||||
typedef Vector<CallSite, 0, SystemAllocPolicy> CallSiteVector;
|
||||
|
||||
// As an invariant across architectures, within asm.js code:
|
||||
// $sp % StackAlignment = (AsmJSFrameSize + masm.framePushed) % StackAlignment
|
||||
// AsmJSFrameSize is 1 word, for the return address pushed by the call (or, in
|
||||
// the case of ARM/MIPS, by the first instruction of the prologue). This means
|
||||
// masm.framePushed never includes the pushed return address.
|
||||
static const uint32_t AsmJSFrameSize = sizeof(void*);
|
||||
|
||||
// Summarizes a heap access made by asm.js code that needs to be patched later
|
||||
// and/or looked up by the asm.js signal handlers. Different architectures need
|
||||
// to know different things (x64: offset and length, ARM: where to patch in
|
||||
|
@ -800,11 +821,7 @@ class AssemblerShared
|
|||
return !enoughMemory_;
|
||||
}
|
||||
|
||||
bool append(const CallSiteDesc &desc, size_t currentOffset, size_t framePushed) {
|
||||
// framePushed does not include AsmJSFrameSize, so add it in here (see
|
||||
// CallSite::stackDepth).
|
||||
return callsites_.append(CallSite(desc, currentOffset, framePushed + AsmJSFrameSize));
|
||||
}
|
||||
bool append(CallSite callsite) { return callsites_.append(callsite); }
|
||||
CallSiteVector &&extractCallSites() { return Move(callsites_); }
|
||||
|
||||
bool append(AsmJSHeapAccess access) { return asmJSHeapAccesses_.append(access); }
|
||||
|
|
|
@ -667,23 +667,26 @@ class MacroAssemblerX86Shared : public Assembler
|
|||
bool buildFakeExitFrame(Register scratch, uint32_t *offset);
|
||||
void callWithExitFrame(JitCode *target);
|
||||
|
||||
void call(const CallSiteDesc &desc, Label *label) {
|
||||
call(label);
|
||||
enoughMemory_ &= append(desc, currentOffset(), framePushed_);
|
||||
}
|
||||
void call(const CallSiteDesc &desc, Register reg) {
|
||||
call(reg);
|
||||
enoughMemory_ &= append(desc, currentOffset(), framePushed_);
|
||||
}
|
||||
void callIon(Register callee) {
|
||||
call(callee);
|
||||
}
|
||||
void callIonFromAsmJS(Register callee) {
|
||||
call(callee);
|
||||
|
||||
void appendCallSite(const CallSiteDesc &desc) {
|
||||
// Add an extra sizeof(void*) to include the return address that was
|
||||
// pushed by the call instruction (see CallSite::stackDepth).
|
||||
enoughMemory_ &= append(CallSite(desc, currentOffset(), framePushed_ + AsmJSFrameSize));
|
||||
}
|
||||
void call(AsmJSImmPtr target) {
|
||||
mov(target, eax);
|
||||
call(eax);
|
||||
|
||||
void call(const CallSiteDesc &desc, Label *label) {
|
||||
call(label);
|
||||
appendCallSite(desc);
|
||||
}
|
||||
void call(const CallSiteDesc &desc, Register reg) {
|
||||
call(reg);
|
||||
appendCallSite(desc);
|
||||
}
|
||||
void callIonFromAsmJS(Register reg) {
|
||||
call(CallSiteDesc::Exit(), reg);
|
||||
}
|
||||
|
||||
void checkStackAlignment() {
|
||||
|
|
|
@ -185,6 +185,13 @@ static const uint32_t StackAlignment = 16;
|
|||
static const bool StackKeptAligned = false;
|
||||
static const uint32_t CodeAlignment = 8;
|
||||
|
||||
// As an invariant across architectures, within asm.js code:
|
||||
// $sp % StackAlignment = (AsmJSFrameSize + masm.framePushed) % StackAlignment
|
||||
// On x64, this naturally falls out of the fact that the 'call' instruction
|
||||
// pushes the return address on the stack and masm.framePushed = 0 at the first
|
||||
// instruction of the prologue.
|
||||
static const uint32_t AsmJSFrameSize = sizeof(void*);
|
||||
|
||||
static const Scale ScalePointer = TimesEight;
|
||||
|
||||
} // namespace jit
|
||||
|
|
|
@ -100,6 +100,18 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
|||
void call(ImmPtr target) {
|
||||
call(ImmWord(uintptr_t(target.value)));
|
||||
}
|
||||
void call(AsmJSImmPtr target) {
|
||||
mov(target, rax);
|
||||
call(rax);
|
||||
}
|
||||
|
||||
void call(const CallSiteDesc &desc, AsmJSImmPtr target) {
|
||||
call(target);
|
||||
appendCallSite(desc);
|
||||
}
|
||||
void callExit(AsmJSImmPtr target, uint32_t stackArgBytes) {
|
||||
call(CallSiteDesc::Exit(), target);
|
||||
}
|
||||
|
||||
// Refers to the upper 32 bits of a 64-bit Value operand.
|
||||
// On x86_64, the upper 32 bits do not necessarily only contain the type.
|
||||
|
|
|
@ -113,6 +113,13 @@ static const uint32_t StackAlignment = 4;
|
|||
static const bool StackKeptAligned = false;
|
||||
static const uint32_t CodeAlignment = 8;
|
||||
|
||||
// As an invariant across architectures, within asm.js code:
|
||||
// $sp % StackAlignment = (AsmJSFrameSize + masm.framePushed) % StackAlignment
|
||||
// On x86, this naturally falls out of the fact that the 'call' instruction
|
||||
// pushes the return address on the stack and masm.framePushed = 0 at the first
|
||||
// instruction of the prologue.
|
||||
static const uint32_t AsmJSFrameSize = sizeof(void*);
|
||||
|
||||
struct ImmTag : public Imm32
|
||||
{
|
||||
ImmTag(JSValueTag mask)
|
||||
|
@ -375,6 +382,13 @@ class Assembler : public AssemblerX86Shared
|
|||
JmpSrc src = masm.call();
|
||||
addPendingJump(src, target, Relocation::HARDCODED);
|
||||
}
|
||||
void call(AsmJSImmPtr target) {
|
||||
// Moving to a register is suboptimal. To fix (use a single
|
||||
// call-immediate instruction) we'll need to distinguish a new type of
|
||||
// relative patch to an absolute address in AsmJSAbsoluteLink.
|
||||
mov(target, eax);
|
||||
call(eax);
|
||||
}
|
||||
|
||||
// Emit a CALL or CMP (nop) instruction. ToggleCall can be used to patch
|
||||
// this instruction.
|
||||
|
|
|
@ -1114,6 +1114,13 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
|||
Push(dynStack);
|
||||
call(target);
|
||||
}
|
||||
void call(const CallSiteDesc &desc, AsmJSImmPtr target) {
|
||||
call(target);
|
||||
appendCallSite(desc);
|
||||
}
|
||||
void callExit(AsmJSImmPtr target, uint32_t stackArgBytes) {
|
||||
call(CallSiteDesc::Exit(), target);
|
||||
}
|
||||
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
void branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label *label);
|
||||
|
|
|
@ -54,6 +54,8 @@ using namespace js::frontend;
|
|||
|
||||
using mozilla::ArrayLength;
|
||||
using mozilla::PodCopy;
|
||||
using mozilla::Range;
|
||||
using mozilla::RangedPtr;
|
||||
|
||||
static bool
|
||||
fun_getProperty(JSContext *cx, HandleObject obj_, HandleId id, MutableHandleValue vp)
|
||||
|
@ -763,7 +765,7 @@ js::FindBody(JSContext *cx, HandleFunction fun, HandleLinearString src, size_t *
|
|||
if (!stableChars.initTwoByte(cx, src))
|
||||
return false;
|
||||
|
||||
const mozilla::Range<const jschar> srcChars = stableChars.twoByteRange();
|
||||
const Range<const jschar> srcChars = stableChars.twoByteRange();
|
||||
TokenStream ts(cx, options, srcChars.start().get(), srcChars.length(), nullptr);
|
||||
int nest = 0;
|
||||
bool onward = true;
|
||||
|
@ -799,7 +801,7 @@ js::FindBody(JSContext *cx, HandleFunction fun, HandleLinearString src, size_t *
|
|||
*bodyStart = ts.currentToken().pos.begin;
|
||||
if (braced)
|
||||
*bodyStart += 1;
|
||||
mozilla::RangedPtr<const jschar> end = srcChars.end();
|
||||
RangedPtr<const jschar> end = srcChars.end();
|
||||
if (end[-1] == '}') {
|
||||
end--;
|
||||
} else {
|
||||
|
@ -1739,7 +1741,7 @@ FunctionConstructor(JSContext *cx, unsigned argc, Value *vp, GeneratorKind gener
|
|||
if (!stableChars.initTwoByte(cx, str))
|
||||
return false;
|
||||
|
||||
mozilla::Range<const jschar> chars = stableChars.twoByteRange();
|
||||
Range<const jschar> chars = stableChars.twoByteRange();
|
||||
SourceBufferHolder::Ownership ownership = stableChars.maybeGiveOwnershipToCaller()
|
||||
? SourceBufferHolder::GiveOwnership
|
||||
: SourceBufferHolder::NoOwnership;
|
||||
|
|
|
@ -247,7 +247,6 @@ if CONFIG['ENABLE_ION']:
|
|||
'irregexp/NativeRegExpMacroAssembler.cpp',
|
||||
'jit/AliasAnalysis.cpp',
|
||||
'jit/AsmJS.cpp',
|
||||
'jit/AsmJSFrameIterator.cpp',
|
||||
'jit/AsmJSLink.cpp',
|
||||
'jit/AsmJSModule.cpp',
|
||||
'jit/AsmJSSignalHandlers.cpp',
|
||||
|
|
|
@ -586,7 +586,7 @@ FrameIter::settleOnActivation()
|
|||
}
|
||||
|
||||
if (activation->isAsmJS()) {
|
||||
data_.asmJSFrames_ = AsmJSFrameIterator(*data_.activations_->asAsmJS());
|
||||
data_.asmJSFrames_ = AsmJSFrameIterator(data_.activations_->asAsmJS());
|
||||
|
||||
if (data_.asmJSFrames_.done()) {
|
||||
++data_.activations_;
|
||||
|
@ -638,7 +638,7 @@ FrameIter::Data::Data(ThreadSafeContext *cx, SavedOption savedOption,
|
|||
#ifdef JS_ION
|
||||
, jitFrames_((uint8_t *)nullptr, SequentialExecution)
|
||||
, ionInlineFrameNo_(0)
|
||||
, asmJSFrames_()
|
||||
, asmJSFrames_(nullptr)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
@ -1683,7 +1683,7 @@ AsmJSActivation::AsmJSActivation(JSContext *cx, AsmJSModule &module)
|
|||
errorRejoinSP_(nullptr),
|
||||
profiler_(nullptr),
|
||||
resumePC_(nullptr),
|
||||
exitFP_(nullptr)
|
||||
exitSP_(nullptr)
|
||||
{
|
||||
if (cx->runtime()->spsProfiler.enabled()) {
|
||||
// Use a profiler string that matches jsMatch regex in
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include "jsfun.h"
|
||||
#include "jsscript.h"
|
||||
|
||||
#include "jit/AsmJSFrameIterator.h"
|
||||
#include "jit/AsmJSLink.h"
|
||||
#include "jit/JitFrameIterator.h"
|
||||
#ifdef CHECK_OSIPOINT_REGISTERS
|
||||
#include "jit/Registers.h" // for RegisterDump
|
||||
|
@ -1511,7 +1511,9 @@ class AsmJSActivation : public Activation
|
|||
void *errorRejoinSP_;
|
||||
SPSProfiler *profiler_;
|
||||
void *resumePC_;
|
||||
uint8_t *exitFP_;
|
||||
uint8_t *exitSP_;
|
||||
|
||||
static const intptr_t InterruptedSP = -1;
|
||||
|
||||
public:
|
||||
AsmJSActivation(JSContext *cx, AsmJSModule &module);
|
||||
|
@ -1527,18 +1529,16 @@ class AsmJSActivation : public Activation
|
|||
|
||||
// Initialized by JIT code:
|
||||
static unsigned offsetOfErrorRejoinSP() { return offsetof(AsmJSActivation, errorRejoinSP_); }
|
||||
static unsigned offsetOfExitFP() { return offsetof(AsmJSActivation, exitFP_); }
|
||||
static unsigned offsetOfExitSP() { return offsetof(AsmJSActivation, exitSP_); }
|
||||
|
||||
// Set from SIGSEGV handler:
|
||||
void setResumePC(void *pc) { resumePC_ = pc; }
|
||||
void setInterrupted(void *pc) { resumePC_ = pc; exitSP_ = (uint8_t*)InterruptedSP; }
|
||||
bool isInterruptedSP() const { return exitSP_ == (uint8_t*)InterruptedSP; }
|
||||
|
||||
// If pc is in C++/Ion code, exitFP points to the innermost asm.js frame
|
||||
// (the one that called into C++). While in asm.js code, exitFP is either
|
||||
// null or points to the innermost asm.js frame. Thus, it is always valid to
|
||||
// unwind a non-null exitFP. The only way C++ can observe a null exitFP is
|
||||
// asychronous interruption of asm.js execution (viz., via the profiler,
|
||||
// a signal handler, or the interrupt exit).
|
||||
uint8_t *exitFP() const { return exitFP_; }
|
||||
// Note: exitSP is the sp right before the call instruction. On x86, this
|
||||
// means before the return address is pushed on the stack, on ARM, this
|
||||
// means after.
|
||||
uint8_t *exitSP() const { JS_ASSERT(!isInterruptedSP()); return exitSP_; }
|
||||
};
|
||||
|
||||
// A FrameIter walks over the runtime's stack of JS script activations,
|
||||
|
|
|
@ -41,10 +41,7 @@ BinarySearch(const Container& aContainer, size_t aBegin, size_t aEnd,
|
|||
size_t high = aEnd;
|
||||
while (low != high) {
|
||||
size_t middle = low + (high - low) / 2;
|
||||
|
||||
// Allow any intermediate type so long as it provides a suitable ordering
|
||||
// relation.
|
||||
const auto& middleValue = aContainer[middle];
|
||||
const T& middleValue = aContainer[middle];
|
||||
|
||||
MOZ_ASSERT(aContainer[low] <= aContainer[middle]);
|
||||
MOZ_ASSERT(aContainer[middle] <= aContainer[high - 1]);
|
||||
|
|
Загрузка…
Ссылка в новой задаче