Bug 1001346 - IonMonkey MIPS: Adding MIPS OdinMonkey code part 2 (shared code). r=luke

This commit is contained in:
Branislav Rankov 2014-06-05 12:56:57 +02:00
parent b74b3c6b14
commit 59f1d2895e
12 changed files with 257 additions and 37 deletions

View File

@ -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();

View File

@ -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();

View File

@ -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

View File

@ -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 {

View File

@ -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));
} }

View File

@ -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)

View File

@ -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();
} }

View File

@ -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.

View File

@ -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)
{ {

View File

@ -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();

View File

@ -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)
{} {}

View File

@ -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;
} }