mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-06 00:55:37 +00:00
Bug 1001346 - IonMonkey MIPS: Adding MIPS OdinMonkey code part 2 (shared code). r=luke
This commit is contained in:
parent
b74b3c6b14
commit
59f1d2895e
@ -1574,12 +1574,14 @@ class MOZ_STACK_CLASS ModuleCompiler
|
|||||||
// instruction.
|
// instruction.
|
||||||
while (labelOffset != LabelBase::INVALID_OFFSET) {
|
while (labelOffset != LabelBase::INVALID_OFFSET) {
|
||||||
size_t patchAtOffset = masm_.labelOffsetToPatchOffset(labelOffset);
|
size_t patchAtOffset = masm_.labelOffsetToPatchOffset(labelOffset);
|
||||||
AsmJSModule::RelativeLink link;
|
AsmJSModule::RelativeLink link(AsmJSModule::RelativeLink::CodeLabel);
|
||||||
link.patchAtOffset = patchAtOffset;
|
link.patchAtOffset = patchAtOffset;
|
||||||
link.targetOffset = targetOffset;
|
link.targetOffset = targetOffset;
|
||||||
if (!module_->addRelativeLink(link))
|
if (!module_->addRelativeLink(link))
|
||||||
return false;
|
return false;
|
||||||
labelOffset = *(uintptr_t *)(module_->codeBase() + patchAtOffset);
|
|
||||||
|
labelOffset = Assembler::extractCodeLabelOffset(module_->codeBase() +
|
||||||
|
patchAtOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1588,7 +1590,7 @@ class MOZ_STACK_CLASS ModuleCompiler
|
|||||||
FuncPtrTable &table = funcPtrTables_[tableIndex];
|
FuncPtrTable &table = funcPtrTables_[tableIndex];
|
||||||
unsigned tableBaseOffset = module_->offsetOfGlobalData() + table.globalDataOffset();
|
unsigned tableBaseOffset = module_->offsetOfGlobalData() + table.globalDataOffset();
|
||||||
for (unsigned elemIndex = 0; elemIndex < table.numElems(); elemIndex++) {
|
for (unsigned elemIndex = 0; elemIndex < table.numElems(); elemIndex++) {
|
||||||
AsmJSModule::RelativeLink link;
|
AsmJSModule::RelativeLink link(AsmJSModule::RelativeLink::RawPointer);
|
||||||
link.patchAtOffset = tableBaseOffset + elemIndex * sizeof(uint8_t*);
|
link.patchAtOffset = tableBaseOffset + elemIndex * sizeof(uint8_t*);
|
||||||
link.targetOffset = masm_.actualOffset(table.elem(elemIndex).code()->offset());
|
link.targetOffset = masm_.actualOffset(table.elem(elemIndex).code()->offset());
|
||||||
if (!module_->addRelativeLink(link))
|
if (!module_->addRelativeLink(link))
|
||||||
@ -1602,7 +1604,7 @@ class MOZ_STACK_CLASS ModuleCompiler
|
|||||||
// code section so we can just use an RelativeLink.
|
// code section so we can just use an RelativeLink.
|
||||||
for (unsigned i = 0; i < masm_.numAsmJSGlobalAccesses(); i++) {
|
for (unsigned i = 0; i < masm_.numAsmJSGlobalAccesses(); i++) {
|
||||||
AsmJSGlobalAccess a = masm_.asmJSGlobalAccess(i);
|
AsmJSGlobalAccess a = masm_.asmJSGlobalAccess(i);
|
||||||
AsmJSModule::RelativeLink link;
|
AsmJSModule::RelativeLink link(AsmJSModule::RelativeLink::InstructionImmediate);
|
||||||
link.patchAtOffset = masm_.labelOffsetToPatchOffset(a.patchAt.offset());
|
link.patchAtOffset = masm_.labelOffsetToPatchOffset(a.patchAt.offset());
|
||||||
link.targetOffset = module_->offsetOfGlobalData() + a.globalDataOffset;
|
link.targetOffset = module_->offsetOfGlobalData() + a.globalDataOffset;
|
||||||
if (!module_->addRelativeLink(link))
|
if (!module_->addRelativeLink(link))
|
||||||
@ -1620,6 +1622,24 @@ class MOZ_STACK_CLASS ModuleCompiler
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(JS_CODEGEN_MIPS)
|
||||||
|
// On MIPS we need to update all the long jumps because they contain an
|
||||||
|
// absolute adress.
|
||||||
|
for (size_t i = 0; i < masm_.numLongJumps(); i++) {
|
||||||
|
uint32_t patchAtOffset = masm_.longJump(i);
|
||||||
|
|
||||||
|
AsmJSModule::RelativeLink link(AsmJSModule::RelativeLink::InstructionImmediate);
|
||||||
|
link.patchAtOffset = patchAtOffset;
|
||||||
|
|
||||||
|
InstImm *inst = (InstImm *)(module_->codeBase() + patchAtOffset);
|
||||||
|
link.targetOffset = Assembler::extractLuiOriValue(inst, inst->next()) -
|
||||||
|
(uint32_t)module_->codeBase();
|
||||||
|
|
||||||
|
if (!module_->addRelativeLink(link))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Absolute links
|
// Absolute links
|
||||||
for (size_t i = 0; i < masm_.numAsmJSAbsoluteLinks(); i++) {
|
for (size_t i = 0; i < masm_.numAsmJSAbsoluteLinks(); i++) {
|
||||||
AsmJSAbsoluteLink src = masm_.asmJSAbsoluteLink(i);
|
AsmJSAbsoluteLink src = masm_.asmJSAbsoluteLink(i);
|
||||||
@ -6055,14 +6075,22 @@ StackDecrementForCall(MacroAssembler &masm, const VectorT &argTypes, unsigned ex
|
|||||||
return StackDecrementForCall(masm, StackArgBytes(argTypes) + extraBytes);
|
return StackDecrementForCall(masm, StackArgBytes(argTypes) + extraBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(JS_CODEGEN_MIPS)
|
||||||
|
// Mips is using one more double slot due to stack alignment for double values.
|
||||||
|
// Look at MacroAssembler::PushRegsInMask(RegisterSet set)
|
||||||
|
static const unsigned FramePushedAfterSave = NonVolatileRegs.gprs().size() * sizeof(intptr_t) +
|
||||||
|
NonVolatileRegs.fpus().size() * sizeof(double) +
|
||||||
|
sizeof(double);
|
||||||
|
#else
|
||||||
static const unsigned FramePushedAfterSave = NonVolatileRegs.gprs().size() * sizeof(intptr_t) +
|
static const unsigned FramePushedAfterSave = NonVolatileRegs.gprs().size() * sizeof(intptr_t) +
|
||||||
NonVolatileRegs.fpus().size() * sizeof(double);
|
NonVolatileRegs.fpus().size() * sizeof(double);
|
||||||
|
#endif
|
||||||
|
|
||||||
// On arm, we need to include an extra word of space at the top of the stack so
|
// On ARM/MIPS, we need to include an extra word of space at the top of the
|
||||||
// we can explicitly store the return address before making the call to C++ or
|
// stack so we can explicitly store the return address before making the call
|
||||||
// Ion. On x86/x64, this isn't necessary since the call instruction pushes the
|
// to C++ or Ion. On x86/x64, this isn't necessary since the call instruction
|
||||||
// return address.
|
// pushes the return address.
|
||||||
#ifdef JS_CODEGEN_ARM
|
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
|
||||||
static const unsigned MaybeRetAddr = sizeof(void*);
|
static const unsigned MaybeRetAddr = sizeof(void*);
|
||||||
#else
|
#else
|
||||||
static const unsigned MaybeRetAddr = 0;
|
static const unsigned MaybeRetAddr = 0;
|
||||||
@ -6087,6 +6115,9 @@ GenerateEntry(ModuleCompiler &m, const AsmJSModule::ExportedFunction &exportedFu
|
|||||||
// pop.
|
// pop.
|
||||||
masm.push(lr);
|
masm.push(lr);
|
||||||
#endif // JS_CODEGEN_ARM
|
#endif // JS_CODEGEN_ARM
|
||||||
|
#if defined(JS_CODEGEN_MIPS)
|
||||||
|
masm.push(ra);
|
||||||
|
#endif
|
||||||
|
|
||||||
masm.PushRegsInMask(NonVolatileRegs);
|
masm.PushRegsInMask(NonVolatileRegs);
|
||||||
JS_ASSERT(masm.framePushed() == FramePushedAfterSave);
|
JS_ASSERT(masm.framePushed() == FramePushedAfterSave);
|
||||||
@ -6099,17 +6130,17 @@ GenerateEntry(ModuleCompiler &m, const AsmJSModule::ExportedFunction &exportedFu
|
|||||||
LoadAsmJSActivationIntoRegister(masm, activation);
|
LoadAsmJSActivationIntoRegister(masm, activation);
|
||||||
masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfErrorRejoinSP()));
|
masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfErrorRejoinSP()));
|
||||||
|
|
||||||
// ARM has a globally-pinned GlobalReg (x64 uses RIP-relative addressing,
|
// ARM and MIPS have a globally-pinned GlobalReg (x64 uses RIP-relative
|
||||||
// x86 uses immediates in effective addresses) and NaN register (used as
|
// addressing, x86 uses immediates in effective addresses) and NaN register
|
||||||
// part of the out-of-bounds handling in heap loads/stores).
|
// (used as part of the out-of-bounds handling in heap loads/stores).
|
||||||
#if defined(JS_CODEGEN_ARM)
|
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
|
||||||
masm.movePtr(IntArgReg1, GlobalReg);
|
masm.movePtr(IntArgReg1, GlobalReg);
|
||||||
masm.ma_vimm(GenericNaN(), NANReg);
|
masm.loadConstantDouble(GenericNaN(), NANReg);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ARM and x64 have a globally-pinned HeapReg (x86 uses immediates in
|
// ARM, MIPS and x64 have a globally-pinned HeapReg (x86 uses immediates in
|
||||||
// effective addresses).
|
// effective addresses).
|
||||||
#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM)
|
#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
|
||||||
masm.loadPtr(Address(IntArgReg1, m.module().heapOffset()), HeapReg);
|
masm.loadPtr(Address(IntArgReg1, m.module().heapOffset()), HeapReg);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -6345,6 +6376,9 @@ GenerateFFIInterpreterExit(ModuleCompiler &m, const ModuleCompiler::ExitDescript
|
|||||||
// pop.
|
// pop.
|
||||||
masm.push(lr);
|
masm.push(lr);
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(JS_CODEGEN_MIPS)
|
||||||
|
masm.push(ra);
|
||||||
|
#endif
|
||||||
|
|
||||||
MIRType typeArray[] = { MIRType_Pointer, // cx
|
MIRType typeArray[] = { MIRType_Pointer, // cx
|
||||||
MIRType_Pointer, // exitDatum
|
MIRType_Pointer, // exitDatum
|
||||||
@ -6353,15 +6387,17 @@ GenerateFFIInterpreterExit(ModuleCompiler &m, const ModuleCompiler::ExitDescript
|
|||||||
MIRTypeVector invokeArgTypes(m.cx());
|
MIRTypeVector invokeArgTypes(m.cx());
|
||||||
invokeArgTypes.infallibleAppend(typeArray, ArrayLength(typeArray));
|
invokeArgTypes.infallibleAppend(typeArray, ArrayLength(typeArray));
|
||||||
|
|
||||||
// The stack layout looks like:
|
// At the point of the call, the stack layout shall be (sp grows to the left):
|
||||||
// | return address | stack arguments | array of values |
|
// | retaddr | stack args | padding | Value argv[] | padding | retaddr | caller stack args |
|
||||||
unsigned arraySize = Max<size_t>(1, exit.sig().args().length()) * sizeof(Value);
|
// The first padding ensures double-alignment of argv; the second ensures
|
||||||
unsigned stackDec = StackDecrementForCall(masm, invokeArgTypes, arraySize + MaybeRetAddr);
|
// sp is aligned.
|
||||||
|
unsigned offsetToArgv = AlignBytes(StackArgBytes(invokeArgTypes) + MaybeRetAddr, StackAlignment);
|
||||||
|
unsigned argvBytes = Max<size_t>(1, exit.sig().args().length()) * sizeof(Value);
|
||||||
|
unsigned stackDec = StackDecrementForCall(masm, offsetToArgv + argvBytes);
|
||||||
masm.reserveStack(stackDec);
|
masm.reserveStack(stackDec);
|
||||||
|
|
||||||
// Fill the argument array.
|
// Fill the argument array.
|
||||||
unsigned offsetToCallerStackArgs = AlignmentAtAsmJSPrologue + masm.framePushed();
|
unsigned offsetToCallerStackArgs = AlignmentAtAsmJSPrologue + masm.framePushed();
|
||||||
unsigned offsetToArgv = StackArgBytes(invokeArgTypes) + MaybeRetAddr;
|
|
||||||
Register scratch = ABIArgGenerator::NonArgReturnVolatileReg0;
|
Register scratch = ABIArgGenerator::NonArgReturnVolatileReg0;
|
||||||
FillArgumentArray(m, exit.sig().args(), offsetToArgv, offsetToCallerStackArgs, scratch);
|
FillArgumentArray(m, exit.sig().args(), offsetToArgv, offsetToCallerStackArgs, scratch);
|
||||||
|
|
||||||
@ -6523,6 +6559,9 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit
|
|||||||
// The NANReg also needs to be restored, but is a constant and is reloaded before
|
// The NANReg also needs to be restored, but is a constant and is reloaded before
|
||||||
// returning to asm.js code.
|
// returning to asm.js code.
|
||||||
masm.PushRegsInMask(GeneralRegisterSet((1<<GlobalReg.code()) | (1<<HeapReg.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
|
#endif
|
||||||
|
|
||||||
// The stack frame is used for the call into Ion and also for calls into C for OOL
|
// The stack frame is used for the call into Ion and also for calls into C for OOL
|
||||||
@ -6625,7 +6664,15 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit
|
|||||||
LoadAsmJSActivationIntoRegister(masm, reg0);
|
LoadAsmJSActivationIntoRegister(masm, reg0);
|
||||||
|
|
||||||
// Record sp in the AsmJSActivation for stack-walking.
|
// 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()));
|
masm.storePtr(StackPointer, Address(reg0, AsmJSActivation::offsetOfExitSP()));
|
||||||
|
#endif
|
||||||
|
|
||||||
// The following is inlined:
|
// The following is inlined:
|
||||||
// JSContext *cx = activation->cx();
|
// JSContext *cx = activation->cx();
|
||||||
@ -6719,8 +6766,8 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit
|
|||||||
#if defined(JS_CODEGEN_X64)
|
#if defined(JS_CODEGEN_X64)
|
||||||
masm.Pop(HeapReg);
|
masm.Pop(HeapReg);
|
||||||
#endif
|
#endif
|
||||||
#if defined(JS_CODEGEN_ARM)
|
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
|
||||||
masm.ma_vimm(GenericNaN(), NANReg);
|
masm.loadConstantDouble(GenericNaN(), NANReg);
|
||||||
masm.PopRegsInMask(GeneralRegisterSet((1<<GlobalReg.code()) | (1<<HeapReg.code())));
|
masm.PopRegsInMask(GeneralRegisterSet((1<<GlobalReg.code()) | (1<<HeapReg.code())));
|
||||||
#endif
|
#endif
|
||||||
masm.ret();
|
masm.ret();
|
||||||
@ -6811,7 +6858,7 @@ GenerateInterruptExit(ModuleCompiler &m, Label *throwLabel)
|
|||||||
masm.align(CodeAlignment);
|
masm.align(CodeAlignment);
|
||||||
masm.bind(&m.interruptLabel());
|
masm.bind(&m.interruptLabel());
|
||||||
|
|
||||||
#ifndef JS_CODEGEN_ARM
|
#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
|
||||||
// Be very careful here not to perturb the machine state before saving it
|
// Be very careful here not to perturb the machine state before saving it
|
||||||
// to the stack. In particular, add/sub instructions may set conditions in
|
// to the stack. In particular, add/sub instructions may set conditions in
|
||||||
// the flags register.
|
// the flags register.
|
||||||
@ -6857,7 +6904,47 @@ GenerateInterruptExit(ModuleCompiler &m, Label *throwLabel)
|
|||||||
masm.PopRegsInMask(AllRegsExceptSP); // restore all GP/FP registers (except SP)
|
masm.PopRegsInMask(AllRegsExceptSP); // restore all GP/FP registers (except SP)
|
||||||
masm.popFlags(); // after this, nothing that sets conditions
|
masm.popFlags(); // after this, nothing that sets conditions
|
||||||
masm.ret(); // pop resumePC into PC
|
masm.ret(); // pop resumePC into PC
|
||||||
#else
|
#elif defined(JS_CODEGEN_MIPS)
|
||||||
|
// Reserve space to store resumePC.
|
||||||
|
masm.subPtr(Imm32(sizeof(intptr_t)), StackPointer);
|
||||||
|
// set to zero so we can use masm.framePushed() below.
|
||||||
|
masm.setFramePushed(0);
|
||||||
|
// save all registers,except sp. After this stack is alligned.
|
||||||
|
masm.PushRegsInMask(AllRegsExceptSP);
|
||||||
|
|
||||||
|
// Save the stack pointer in a non-volatile register.
|
||||||
|
masm.movePtr(StackPointer, s0);
|
||||||
|
// Align the stack.
|
||||||
|
masm.ma_and(StackPointer, StackPointer, Imm32(~(StackAlignment - 1)));
|
||||||
|
|
||||||
|
// Store resumePC into the reserved space.
|
||||||
|
LoadAsmJSActivationIntoRegister(masm, IntArgReg0);
|
||||||
|
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);
|
||||||
|
|
||||||
|
masm.call(AsmJSImm_HandleExecutionInterrupt);
|
||||||
|
|
||||||
|
masm.addPtr(Imm32(4 * sizeof(intptr_t)), StackPointer);
|
||||||
|
|
||||||
|
masm.branchIfFalseBool(ReturnReg, throwLabel);
|
||||||
|
|
||||||
|
// This will restore stack to the address before the call.
|
||||||
|
masm.movePtr(s0, StackPointer);
|
||||||
|
masm.PopRegsInMask(AllRegsExceptSP);
|
||||||
|
|
||||||
|
// Pop resumePC into PC. Clobber HeapReg to make the jump and restore it
|
||||||
|
// during jump delay slot.
|
||||||
|
JS_ASSERT(Imm16::isInSignedRange(m.module().heapOffset()));
|
||||||
|
masm.pop(HeapReg);
|
||||||
|
masm.as_jr(HeapReg);
|
||||||
|
masm.loadPtr(Address(GlobalReg, m.module().heapOffset()), HeapReg);
|
||||||
|
#elif defined(JS_CODEGEN_ARM)
|
||||||
masm.setFramePushed(0); // set to zero so we can use masm.framePushed() below
|
masm.setFramePushed(0); // set to zero so we can use masm.framePushed() below
|
||||||
masm.PushRegsInMask(RegisterSet(GeneralRegisterSet(Registers::AllMask & ~(1<<Registers::sp)), FloatRegisterSet(uint32_t(0)))); // save all GP registers,excep sp
|
masm.PushRegsInMask(RegisterSet(GeneralRegisterSet(Registers::AllMask & ~(1<<Registers::sp)), FloatRegisterSet(uint32_t(0)))); // save all GP registers,excep sp
|
||||||
|
|
||||||
@ -6905,6 +6992,8 @@ GenerateInterruptExit(ModuleCompiler &m, Label *throwLabel)
|
|||||||
masm.finishDataTransfer();
|
masm.finishDataTransfer();
|
||||||
masm.ret();
|
masm.ret();
|
||||||
|
|
||||||
|
#else
|
||||||
|
# error "Unknown architecture!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return !masm.oom();
|
return !masm.oom();
|
||||||
|
@ -52,13 +52,29 @@ AsmJSFrameIterator::AsmJSFrameIterator(const AsmJSActivation *activation)
|
|||||||
// to C++. Since the call instruction pushes the return address, we know
|
// to C++. Since the call instruction pushes the return address, we know
|
||||||
// that the return address is 1 word below exitSP.
|
// that the return address is 1 word below exitSP.
|
||||||
returnAddress_ = *(uint8_t**)(sp_ - sizeof(void*));
|
returnAddress_ = *(uint8_t**)(sp_ - sizeof(void*));
|
||||||
#else
|
#elif defined(JS_CODEGEN_ARM)
|
||||||
// For calls to Ion/C++ on ARM, the *caller* pushes the return address on
|
// 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
|
// 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
|
// address is explicitly pushed before the call since we cannot expect the
|
||||||
// callee to immediately push lr. This means that exitSP points to the
|
// callee to immediately push lr. This means that exitSP points to the
|
||||||
// return address.
|
// return address.
|
||||||
returnAddress_ = *(uint8_t**)sp_;
|
returnAddress_ = *(uint8_t**)sp_;
|
||||||
|
#elif defined(JS_CODEGEN_MIPS)
|
||||||
|
// On MIPS we have two cases. Exit to C++ will store return addres at
|
||||||
|
// sp + 16, While on exits to Ion, the return address will be stored at
|
||||||
|
// sp + 0. We indicate exits to ion by setting the lowest bit of stored sp.
|
||||||
|
|
||||||
|
// Check if this is the exit to Ion.
|
||||||
|
if (uint32_t(sp_) & 0x1) {
|
||||||
|
// Clear the low bit.
|
||||||
|
sp_ -= 0x1;
|
||||||
|
returnAddress_ = *(uint8_t**)sp_;
|
||||||
|
} else {
|
||||||
|
// This is exit to C++
|
||||||
|
returnAddress_ = *(uint8_t**)(sp_ + ShadowStackSpace);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# error "Unknown architecture!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
settle();
|
settle();
|
||||||
|
@ -313,7 +313,12 @@ AsmJSModule::staticallyLink(ExclusiveContext *cx)
|
|||||||
|
|
||||||
for (size_t i = 0; i < staticLinkData_.relativeLinks.length(); i++) {
|
for (size_t i = 0; i < staticLinkData_.relativeLinks.length(); i++) {
|
||||||
RelativeLink link = staticLinkData_.relativeLinks[i];
|
RelativeLink link = staticLinkData_.relativeLinks[i];
|
||||||
*(void **)(code_ + link.patchAtOffset) = code_ + link.targetOffset;
|
uint8_t *patchAt = code_ + link.patchAtOffset;
|
||||||
|
uint8_t *target = code_ + link.targetOffset;
|
||||||
|
if (link.isRawPointerPatch())
|
||||||
|
*(uint8_t **)(patchAt) = target;
|
||||||
|
else
|
||||||
|
Assembler::patchInstructionImmediate(patchAt, PatchedImmPtr(target));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < staticLinkData_.absoluteLinks.length(); i++) {
|
for (size_t i = 0; i < staticLinkData_.absoluteLinks.length(); i++) {
|
||||||
@ -1013,7 +1018,8 @@ GetCPUID(uint32_t *cpuId)
|
|||||||
X86 = 0x1,
|
X86 = 0x1,
|
||||||
X64 = 0x2,
|
X64 = 0x2,
|
||||||
ARM = 0x3,
|
ARM = 0x3,
|
||||||
ARCH_BITS = 2
|
MIPS = 0x4,
|
||||||
|
ARCH_BITS = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(JS_CODEGEN_X86)
|
#if defined(JS_CODEGEN_X86)
|
||||||
@ -1028,6 +1034,10 @@ GetCPUID(uint32_t *cpuId)
|
|||||||
JS_ASSERT(GetARMFlags() <= (UINT32_MAX >> ARCH_BITS));
|
JS_ASSERT(GetARMFlags() <= (UINT32_MAX >> ARCH_BITS));
|
||||||
*cpuId = ARM | (GetARMFlags() << ARCH_BITS);
|
*cpuId = ARM | (GetARMFlags() << ARCH_BITS);
|
||||||
return true;
|
return true;
|
||||||
|
#elif defined(JS_CODEGEN_MIPS)
|
||||||
|
JS_ASSERT(GetMIPSFlags() <= (UINT32_MAX >> ARCH_BITS));
|
||||||
|
*cpuId = MIPS | (GetMIPSFlags() << ARCH_BITS);
|
||||||
|
return true;
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
@ -370,6 +370,39 @@ class AsmJSModule
|
|||||||
|
|
||||||
struct RelativeLink
|
struct RelativeLink
|
||||||
{
|
{
|
||||||
|
enum Kind
|
||||||
|
{
|
||||||
|
RawPointer,
|
||||||
|
CodeLabel,
|
||||||
|
InstructionImmediate
|
||||||
|
};
|
||||||
|
|
||||||
|
RelativeLink()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
RelativeLink(Kind kind)
|
||||||
|
{
|
||||||
|
#if defined(JS_CODEGEN_MIPS)
|
||||||
|
kind_ = kind;
|
||||||
|
#elif defined(JS_CODEGEN_ARM)
|
||||||
|
// On ARM, CodeLabels are only used to label raw pointers, so in
|
||||||
|
// all cases on ARM, a RelativePatch means patching a raw pointer.
|
||||||
|
JS_ASSERT(kind == CodeLabel || kind == RawPointer);
|
||||||
|
#endif
|
||||||
|
// On X64 and X86, all RelativePatch-es are patched as raw pointers.
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isRawPointerPatch() {
|
||||||
|
#if defined(JS_CODEGEN_MIPS)
|
||||||
|
return kind_ == RawPointer;
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef JS_CODEGEN_MIPS
|
||||||
|
Kind kind_;
|
||||||
|
#endif
|
||||||
uint32_t patchAtOffset;
|
uint32_t patchAtOffset;
|
||||||
uint32_t targetOffset;
|
uint32_t targetOffset;
|
||||||
};
|
};
|
||||||
@ -727,7 +760,8 @@ class AsmJSModule
|
|||||||
// The global data section is placed after the executable code (i.e., at
|
// The global data section is placed after the executable code (i.e., at
|
||||||
// offset codeBytes_) in the module's linear allocation. The global data
|
// offset codeBytes_) in the module's linear allocation. The global data
|
||||||
// are laid out in this order:
|
// are laid out in this order:
|
||||||
// 0. a pointer/descriptor for the heap that was linked to the module
|
// 0. a pointer (padded up to 8 bytes to ensure double-alignment of
|
||||||
|
// globals) for the heap that was linked to the module.
|
||||||
// 1. global variable state (elements are sizeof(uint64_t))
|
// 1. global variable state (elements are sizeof(uint64_t))
|
||||||
// 2. interleaved function-pointer tables and exits. These are allocated
|
// 2. interleaved function-pointer tables and exits. These are allocated
|
||||||
// while type checking function bodies (as exits and uses of
|
// while type checking function bodies (as exits and uses of
|
||||||
@ -740,7 +774,7 @@ class AsmJSModule
|
|||||||
return code_ + offsetOfGlobalData();
|
return code_ + offsetOfGlobalData();
|
||||||
}
|
}
|
||||||
size_t globalDataBytes() const {
|
size_t globalDataBytes() const {
|
||||||
return sizeof(void*) +
|
return sizeof(uint64_t) +
|
||||||
pod.numGlobalVars_ * sizeof(uint64_t) +
|
pod.numGlobalVars_ * sizeof(uint64_t) +
|
||||||
pod.funcPtrTableAndExitBytes_;
|
pod.funcPtrTableAndExitBytes_;
|
||||||
}
|
}
|
||||||
@ -752,7 +786,7 @@ class AsmJSModule
|
|||||||
}
|
}
|
||||||
unsigned globalVarIndexToGlobalDataOffset(unsigned i) const {
|
unsigned globalVarIndexToGlobalDataOffset(unsigned i) const {
|
||||||
JS_ASSERT(i < pod.numGlobalVars_);
|
JS_ASSERT(i < pod.numGlobalVars_);
|
||||||
return sizeof(void*) +
|
return sizeof(uint64_t) +
|
||||||
i * sizeof(uint64_t);
|
i * sizeof(uint64_t);
|
||||||
}
|
}
|
||||||
void *globalVarIndexToGlobalDatum(unsigned i) const {
|
void *globalVarIndexToGlobalDatum(unsigned i) const {
|
||||||
|
@ -86,6 +86,11 @@ using JS::GenericNaN;
|
|||||||
# else
|
# else
|
||||||
# define R15_sig(p) ((p)->uc_mcontext.gregs[REG_R15])
|
# define R15_sig(p) ((p)->uc_mcontext.gregs[REG_R15])
|
||||||
# endif
|
# endif
|
||||||
|
# if defined(__linux__) && defined(__mips__)
|
||||||
|
# define EPC_sig(p) ((p)->uc_mcontext.pc)
|
||||||
|
# define RSP_sig(p) ((p)->uc_mcontext.gregs[29])
|
||||||
|
# define RFP_sig(p) ((p)->uc_mcontext.gregs[30])
|
||||||
|
# endif
|
||||||
#elif defined(__NetBSD__)
|
#elif defined(__NetBSD__)
|
||||||
# define XMM_sig(p,i) (((struct fxsave64 *)(p)->uc_mcontext.__fpregs)->fx_xmm[i])
|
# define XMM_sig(p,i) (((struct fxsave64 *)(p)->uc_mcontext.__fpregs)->fx_xmm[i])
|
||||||
# define EIP_sig(p) ((p)->uc_mcontext.__gregs[_REG_EIP])
|
# define EIP_sig(p) ((p)->uc_mcontext.__gregs[_REG_EIP])
|
||||||
@ -282,6 +287,37 @@ typedef struct ucontext {
|
|||||||
// Other fields are not used so don't define them here.
|
// Other fields are not used so don't define them here.
|
||||||
} ucontext_t;
|
} ucontext_t;
|
||||||
|
|
||||||
|
# elif defined(__mips__)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t regmask;
|
||||||
|
uint32_t status;
|
||||||
|
uint64_t pc;
|
||||||
|
uint64_t gregs[32];
|
||||||
|
uint64_t fpregs[32];
|
||||||
|
uint32_t acx;
|
||||||
|
uint32_t fpc_csr;
|
||||||
|
uint32_t fpc_eir;
|
||||||
|
uint32_t used_math;
|
||||||
|
uint32_t dsp;
|
||||||
|
uint64_t mdhi;
|
||||||
|
uint64_t mdlo;
|
||||||
|
uint32_t hi1;
|
||||||
|
uint32_t lo1;
|
||||||
|
uint32_t hi2;
|
||||||
|
uint32_t lo2;
|
||||||
|
uint32_t hi3;
|
||||||
|
uint32_t lo3;
|
||||||
|
} mcontext_t;
|
||||||
|
|
||||||
|
typedef struct ucontext {
|
||||||
|
uint32_t uc_flags;
|
||||||
|
struct ucontext* uc_link;
|
||||||
|
stack_t uc_stack;
|
||||||
|
mcontext_t uc_mcontext;
|
||||||
|
// Other fields are not used so don't define them here.
|
||||||
|
} ucontext_t;
|
||||||
|
|
||||||
# elif defined(__i386__)
|
# elif defined(__i386__)
|
||||||
// x86 version for Android.
|
// x86 version for Android.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -326,6 +362,8 @@ static bool IsSignalHandlingBroken() { return false; }
|
|||||||
# define PC_sig(p) EIP_sig(p)
|
# define PC_sig(p) EIP_sig(p)
|
||||||
#elif defined(JS_CPU_ARM)
|
#elif defined(JS_CPU_ARM)
|
||||||
# define PC_sig(p) R15_sig(p)
|
# define PC_sig(p) R15_sig(p)
|
||||||
|
#elif defined(JS_CPU_MIPS)
|
||||||
|
# define PC_sig(p) EPC_sig(p)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
@ -355,7 +393,6 @@ HandleSimulatorInterrupt(JSRuntime *rt, AsmJSActivation *activation, void *fault
|
|||||||
static uint8_t **
|
static uint8_t **
|
||||||
ContextToPC(CONTEXT *context)
|
ContextToPC(CONTEXT *context)
|
||||||
{
|
{
|
||||||
JS_STATIC_ASSERT(sizeof(PC_sig(context)) == sizeof(void*));
|
|
||||||
return reinterpret_cast<uint8_t**>(&PC_sig(context));
|
return reinterpret_cast<uint8_t**>(&PC_sig(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,10 +15,10 @@
|
|||||||
|
|
||||||
#include "jit/arm/Assembler-arm.h"
|
#include "jit/arm/Assembler-arm.h"
|
||||||
|
|
||||||
#define HWCAP_USE_HARDFP_ABI (1 << 28)
|
#define HWCAP_USE_HARDFP_ABI (1 << 27)
|
||||||
|
|
||||||
#if !(defined(ANDROID) || defined(MOZ_B2G)) && !defined(JS_ARM_SIMULATOR)
|
#if !(defined(ANDROID) || defined(MOZ_B2G)) && !defined(JS_ARM_SIMULATOR)
|
||||||
#define HWCAP_ARMv7 (1 << 29)
|
#define HWCAP_ARMv7 (1 << 28)
|
||||||
#include <asm/hwcap.h>
|
#include <asm/hwcap.h>
|
||||||
#else
|
#else
|
||||||
#define HWCAP_VFP (1<<0)
|
#define HWCAP_VFP (1<<0)
|
||||||
|
@ -1798,6 +1798,11 @@ class Assembler : public AssemblerShared
|
|||||||
static void patchDataWithValueCheck(CodeLocationLabel label, ImmPtr newValue,
|
static void patchDataWithValueCheck(CodeLocationLabel label, ImmPtr newValue,
|
||||||
ImmPtr expectedValue);
|
ImmPtr expectedValue);
|
||||||
static void patchWrite_Imm32(CodeLocationLabel label, Imm32 imm);
|
static void patchWrite_Imm32(CodeLocationLabel label, Imm32 imm);
|
||||||
|
|
||||||
|
static void patchInstructionImmediate(uint8_t *code, PatchedImmPtr imm) {
|
||||||
|
MOZ_ASSUME_UNREACHABLE("Unused.");
|
||||||
|
}
|
||||||
|
|
||||||
static uint32_t alignDoubleArg(uint32_t offset) {
|
static uint32_t alignDoubleArg(uint32_t offset) {
|
||||||
return (offset+1)&~1;
|
return (offset+1)&~1;
|
||||||
}
|
}
|
||||||
@ -1811,6 +1816,10 @@ class Assembler : public AssemblerShared
|
|||||||
|
|
||||||
static void updateBoundsCheck(uint32_t logHeapSize, Instruction *inst);
|
static void updateBoundsCheck(uint32_t logHeapSize, Instruction *inst);
|
||||||
void processCodeLabels(uint8_t *rawCode);
|
void processCodeLabels(uint8_t *rawCode);
|
||||||
|
static int32_t extractCodeLabelOffset(uint8_t *code) {
|
||||||
|
return *(uintptr_t *)code;
|
||||||
|
}
|
||||||
|
|
||||||
bool bailed() {
|
bool bailed() {
|
||||||
return m_buffer.bail();
|
return m_buffer.bail();
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ namespace js {
|
|||||||
namespace jit {
|
namespace jit {
|
||||||
|
|
||||||
// Shadow stack space is not required on MIPS.
|
// Shadow stack space is not required on MIPS.
|
||||||
static const uint32_t ShadowStackSpace = 0;
|
static const uint32_t ShadowStackSpace = 4 * sizeof(uintptr_t);
|
||||||
|
|
||||||
// These offsets are specific to nunboxing, and capture offsets into the
|
// These offsets are specific to nunboxing, and capture offsets into the
|
||||||
// components of a js::Value.
|
// components of a js::Value.
|
||||||
|
@ -329,6 +329,12 @@ Assembler::processCodeLabels(uint8_t *rawCode)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t
|
||||||
|
Assembler::extractCodeLabelOffset(uint8_t *code) {
|
||||||
|
InstImm *inst = (InstImm *)code;
|
||||||
|
return Assembler::extractLuiOriValue(inst, inst->next());
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Assembler::Bind(uint8_t *rawCode, AbsoluteLabel *label, const void *address)
|
Assembler::Bind(uint8_t *rawCode, AbsoluteLabel *label, const void *address)
|
||||||
{
|
{
|
||||||
@ -1450,6 +1456,13 @@ Assembler::patchWrite_Imm32(CodeLocationLabel label, Imm32 imm)
|
|||||||
*(raw - 1) = imm.value;
|
*(raw - 1) = imm.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Assembler::patchInstructionImmediate(uint8_t *code, PatchedImmPtr imm)
|
||||||
|
{
|
||||||
|
InstImm *inst = (InstImm *)code;
|
||||||
|
Assembler::updateLuiOriValue(inst, inst->next(), (uint32_t)imm.value);
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t *
|
uint8_t *
|
||||||
Assembler::nextInstruction(uint8_t *inst_, uint32_t *count)
|
Assembler::nextInstruction(uint8_t *inst_, uint32_t *count)
|
||||||
{
|
{
|
||||||
|
@ -89,7 +89,7 @@ class ABIArgGenerator
|
|||||||
|
|
||||||
uint32_t stackBytesConsumedSoFar() const {
|
uint32_t stackBytesConsumedSoFar() const {
|
||||||
if (usedArgSlots_ <= 4)
|
if (usedArgSlots_ <= 4)
|
||||||
return 4 * sizeof(intptr_t);
|
return ShadowStackSpace;
|
||||||
|
|
||||||
return usedArgSlots_ * sizeof(intptr_t);
|
return usedArgSlots_ * sizeof(intptr_t);
|
||||||
}
|
}
|
||||||
@ -1033,6 +1033,9 @@ class Assembler : public AssemblerShared
|
|||||||
static void patchDataWithValueCheck(CodeLocationLabel label, ImmPtr newValue,
|
static void patchDataWithValueCheck(CodeLocationLabel label, ImmPtr newValue,
|
||||||
ImmPtr expectedValue);
|
ImmPtr expectedValue);
|
||||||
static void patchWrite_Imm32(CodeLocationLabel label, Imm32 imm);
|
static void patchWrite_Imm32(CodeLocationLabel label, Imm32 imm);
|
||||||
|
|
||||||
|
static void patchInstructionImmediate(uint8_t *code, PatchedImmPtr imm);
|
||||||
|
|
||||||
static uint32_t alignDoubleArg(uint32_t offset) {
|
static uint32_t alignDoubleArg(uint32_t offset) {
|
||||||
return (offset + 1U) &~ 1U;
|
return (offset + 1U) &~ 1U;
|
||||||
}
|
}
|
||||||
@ -1046,6 +1049,7 @@ class Assembler : public AssemblerShared
|
|||||||
|
|
||||||
static void updateBoundsCheck(uint32_t logHeapSize, Instruction *inst);
|
static void updateBoundsCheck(uint32_t logHeapSize, Instruction *inst);
|
||||||
void processCodeLabels(uint8_t *rawCode);
|
void processCodeLabels(uint8_t *rawCode);
|
||||||
|
static int32_t extractCodeLabelOffset(uint8_t *code);
|
||||||
|
|
||||||
bool bailed() {
|
bool bailed() {
|
||||||
return m_buffer.bail();
|
return m_buffer.bail();
|
||||||
|
@ -691,7 +691,7 @@ class AsmJSHeapAccess
|
|||||||
isFloat32Load_(false),
|
isFloat32Load_(false),
|
||||||
loadedReg_(UINT8_MAX)
|
loadedReg_(UINT8_MAX)
|
||||||
{}
|
{}
|
||||||
#elif defined(JS_CODEGEN_ARM)
|
#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
|
||||||
explicit AsmJSHeapAccess(uint32_t offset)
|
explicit AsmJSHeapAccess(uint32_t offset)
|
||||||
: offset_(offset)
|
: offset_(offset)
|
||||||
{}
|
{}
|
||||||
|
@ -288,6 +288,9 @@ class AssemblerX86Shared : public AssemblerShared
|
|||||||
|
|
||||||
void executableCopy(void *buffer);
|
void executableCopy(void *buffer);
|
||||||
void processCodeLabels(uint8_t *rawCode);
|
void processCodeLabels(uint8_t *rawCode);
|
||||||
|
static int32_t extractCodeLabelOffset(uint8_t *code) {
|
||||||
|
return *(uintptr_t *)code;
|
||||||
|
}
|
||||||
void copyJumpRelocationTable(uint8_t *dest);
|
void copyJumpRelocationTable(uint8_t *dest);
|
||||||
void copyDataRelocationTable(uint8_t *dest);
|
void copyDataRelocationTable(uint8_t *dest);
|
||||||
void copyPreBarrierTable(uint8_t *dest);
|
void copyPreBarrierTable(uint8_t *dest);
|
||||||
@ -1677,6 +1680,11 @@ class AssemblerX86Shared : public AssemblerShared
|
|||||||
static void patchDataWithValueCheck(CodeLocationLabel data, ImmPtr newData, ImmPtr expectedData) {
|
static void patchDataWithValueCheck(CodeLocationLabel data, ImmPtr newData, ImmPtr expectedData) {
|
||||||
patchDataWithValueCheck(data, PatchedImmPtr(newData.value), PatchedImmPtr(expectedData.value));
|
patchDataWithValueCheck(data, PatchedImmPtr(newData.value), PatchedImmPtr(expectedData.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void patchInstructionImmediate(uint8_t *code, PatchedImmPtr imm) {
|
||||||
|
MOZ_ASSUME_UNREACHABLE("Unused.");
|
||||||
|
}
|
||||||
|
|
||||||
static uint32_t nopSize() {
|
static uint32_t nopSize() {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user