Bug 1026877 - OdinMonkey: tidy up AsmJSModule, part 1 (r=bbouvier)

--HG--
extra : rebase_source : c0c4face5eb8aa70e1f9cc89fc13e3c7522a1f88
This commit is contained in:
Luke Wagner 2014-06-18 08:57:19 -05:00
parent 8f2b7229d4
commit ffa75d7d08
5 changed files with 202 additions and 223 deletions

View File

@ -1506,86 +1506,15 @@ class MOZ_STACK_CLASS ModuleCompiler
bool finish(ScopedJSDeletePtr<AsmJSModule> *module)
{
module_->initFuncEnd(tokenStream().currentToken().pos.end,
tokenStream().peekTokenPos().end);
masm_.finish();
if (masm_.oom())
return false;
module_->assignCallSites(masm_.extractCallSites());
module_->assignHeapAccesses(masm_.extractAsmJSHeapAccesses());
#if defined(JS_CODEGEN_ARM)
// Now that compilation has finished, we need to update offsets to
// reflect actual offsets (an ARM distinction).
for (unsigned i = 0; i < module_->numHeapAccesses(); i++) {
AsmJSHeapAccess &a = module_->heapAccess(i);
a.setOffset(masm_.actualOffset(a.offset()));
}
for (unsigned i = 0; i < module_->numCallSites(); i++) {
CallSite &c = module_->callSite(i);
c.setReturnAddressOffset(masm_.actualOffset(c.returnAddressOffset()));
}
#endif
// The returned memory is owned by module_.
if (!module_->allocateAndCopyCode(cx_, masm_))
if (!module_->finish(cx_, tokenStream(), masm_, interruptLabel_))
return false;
// c.f. JitCode::copyFrom
JS_ASSERT(masm_.jumpRelocationTableBytes() == 0);
JS_ASSERT(masm_.dataRelocationTableBytes() == 0);
JS_ASSERT(masm_.preBarrierTableBytes() == 0);
JS_ASSERT(!masm_.hasEnteredExitFrame());
#if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
// Fix up the code offsets. Note the endCodeOffset should not be
// filtered through 'actualOffset' as it is generated using 'size()'
// rather than a label.
for (unsigned i = 0; i < module_->numProfiledFunctions(); i++) {
AsmJSModule::ProfiledFunction &func = module_->profiledFunction(i);
func.pod.startCodeOffset = masm_.actualOffset(func.pod.startCodeOffset);
}
#endif
#ifdef JS_ION_PERF
for (unsigned i = 0; i < module_->numPerfBlocksFunctions(); i++) {
AsmJSModule::ProfiledBlocksFunction &func = module_->perfProfiledBlocksFunction(i);
func.pod.startCodeOffset = masm_.actualOffset(func.pod.startCodeOffset);
func.endInlineCodeOffset = masm_.actualOffset(func.endInlineCodeOffset);
BasicBlocksVector &basicBlocks = func.blocks;
for (uint32_t i = 0; i < basicBlocks.length(); i++) {
Record &r = basicBlocks[i];
r.startOffset = masm_.actualOffset(r.startOffset);
r.endOffset = masm_.actualOffset(r.endOffset);
}
}
#endif
module_->setInterruptOffset(masm_.actualOffset(interruptLabel_.offset()));
// CodeLabels produced during codegen
for (size_t i = 0; i < masm_.numCodeLabels(); i++) {
CodeLabel src = masm_.codeLabel(i);
int32_t labelOffset = src.dest()->offset();
int32_t targetOffset = masm_.actualOffset(src.src()->offset());
// The patched uses of a label embed a linked list where the
// to-be-patched immediate is the offset of the next to-be-patched
// instruction.
while (labelOffset != LabelBase::INVALID_OFFSET) {
size_t patchAtOffset = masm_.labelOffsetToPatchOffset(labelOffset);
AsmJSModule::RelativeLink link(AsmJSModule::RelativeLink::CodeLabel);
link.patchAtOffset = patchAtOffset;
link.targetOffset = targetOffset;
if (!module_->addRelativeLink(link))
return false;
labelOffset = Assembler::extractCodeLabelOffset(module_->codeBase() +
patchAtOffset);
}
}
// Function-pointer-table entries
// Finally, convert all the function-pointer table elements into
// RelativeLinks that will be patched by AsmJSModule::staticallyLink.
for (unsigned tableIndex = 0; tableIndex < funcPtrTables_.length(); tableIndex++) {
FuncPtrTable &table = funcPtrTables_[tableIndex];
unsigned tableBaseOffset = module_->offsetOfGlobalData() + table.globalDataOffset();
@ -1598,58 +1527,6 @@ class MOZ_STACK_CLASS ModuleCompiler
}
}
#if defined(JS_CODEGEN_X86)
// Global data accesses in x86 need to be patched with the absolute
// address of the global. Globals are allocated sequentially after the
// code section so we can just use an RelativeLink.
for (unsigned i = 0; i < masm_.numAsmJSGlobalAccesses(); i++) {
AsmJSGlobalAccess a = masm_.asmJSGlobalAccess(i);
AsmJSModule::RelativeLink link(AsmJSModule::RelativeLink::InstructionImmediate);
link.patchAtOffset = masm_.labelOffsetToPatchOffset(a.patchAt.offset());
link.targetOffset = module_->offsetOfGlobalData() + a.globalDataOffset;
if (!module_->addRelativeLink(link))
return false;
}
#endif
#if defined(JS_CODEGEN_X64)
// Global data accesses on x64 use rip-relative addressing and thus do
// not need patching after deserialization.
uint8_t *code = module_->codeBase();
for (unsigned i = 0; i < masm_.numAsmJSGlobalAccesses(); i++) {
AsmJSGlobalAccess a = masm_.asmJSGlobalAccess(i);
masm_.patchAsmJSGlobalAccess(a.patchAt, code, module_->globalData(), a.globalDataOffset);
}
#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
for (size_t i = 0; i < masm_.numAsmJSAbsoluteLinks(); i++) {
AsmJSAbsoluteLink src = masm_.asmJSAbsoluteLink(i);
AsmJSModule::AbsoluteLink link;
link.patchAt = CodeOffsetLabel(masm_.actualOffset(src.patchAt.offset()));
link.target = src.target;
if (!module_->addAbsoluteLink(link))
return false;
}
*module = module_.forget();
return true;
}

View File

@ -6,7 +6,6 @@
#include "jit/AsmJSLink.h"
#include "mozilla/BinarySearch.h"
#include "mozilla/PodOperations.h"
#ifdef MOZ_VTUNE
@ -32,7 +31,6 @@
using namespace js;
using namespace js::jit;
using mozilla::BinarySearch;
using mozilla::IsNaN;
using mozilla::PodZero;
@ -93,30 +91,15 @@ AsmJSFrameIterator::operator++()
settle(ReturnAddressForJitCall(sp_));
}
struct GetCallSite
{
const AsmJSModule &module;
explicit GetCallSite(const AsmJSModule &module) : module(module) {}
uint32_t operator[](size_t index) const {
return module.callSite(index).returnAddressOffset();
}
};
void
AsmJSFrameIterator::settle(uint8_t *returnAddress)
{
uint32_t target = returnAddress - module_->codeBase();
size_t lowerBound = 0;
size_t upperBound = module_->numCallSites();
size_t match;
if (!BinarySearch(GetCallSite(*module_), lowerBound, upperBound, target, &match)) {
callsite_ = module_->lookupCallSite(returnAddress);
if (!callsite_ || callsite_->isEntry()) {
module_ = nullptr;
return;
}
callsite_ = &module_->callSite(match);
if (callsite_->isEntry()) {
module_ = nullptr;
return;

View File

@ -12,6 +12,7 @@
# include <sys/mman.h>
#endif
#include "mozilla/BinarySearch.h"
#include "mozilla/Compression.h"
#include "mozilla/PodOperations.h"
#include "mozilla/TaggedAnonymousMemory.h"
@ -35,6 +36,7 @@
using namespace js;
using namespace jit;
using namespace frontend;
using mozilla::BinarySearch;
using mozilla::PodCopy;
using mozilla::PodEqual;
using mozilla::Compression::LZ4;
@ -70,6 +72,54 @@ AsmJSModule::initHeap(Handle<ArrayBufferObject*> heap, JSContext *cx)
#endif
}
struct CallSiteRetAddrOffset
{
const CallSiteVector &callSites;
explicit CallSiteRetAddrOffset(const CallSiteVector &callSites) : callSites(callSites) {}
uint32_t operator[](size_t index) const {
return callSites[index].returnAddressOffset();
}
};
const CallSite *
AsmJSModule::lookupCallSite(uint8_t *returnAddress) const
{
uint32_t target = returnAddress - code_;
size_t lowerBound = 0;
size_t upperBound = callSites_.length();
size_t match;
if (!BinarySearch(CallSiteRetAddrOffset(callSites_), lowerBound, upperBound, target, &match))
return nullptr;
return &callSites_[match];
}
struct HeapAccessOffset
{
const AsmJSHeapAccessVector &accesses;
explicit HeapAccessOffset(const AsmJSHeapAccessVector &accesses) : accesses(accesses) {}
uintptr_t operator[](size_t index) const {
return accesses[index].offset();
}
};
const AsmJSHeapAccess *
AsmJSModule::lookupHeapAccess(uint8_t *pc) const
{
JS_ASSERT(containsPC(pc));
uint32_t target = pc - code_;
size_t lowerBound = 0;
size_t upperBound = heapAccesses_.length();
size_t match;
if (!BinarySearch(HeapAccessOffset(heapAccesses_), lowerBound, upperBound, target, &match))
return nullptr;
return &heapAccesses_[match];
}
static uint8_t *
AllocateExecutableMemory(ExclusiveContext *cx, size_t totalBytes)
{
@ -105,9 +155,15 @@ DeallocateExecutableMemory(uint8_t *code, size_t totalBytes)
}
bool
AsmJSModule::allocateAndCopyCode(ExclusiveContext *cx, MacroAssembler &masm)
AsmJSModule::finish(ExclusiveContext *cx, TokenStream &tokenStream, MacroAssembler &masm,
const Label &interruptLabel)
{
JS_ASSERT(!code_);
uint32_t endBeforeCurly = tokenStream.currentToken().pos.end;
uint32_t endAfterCurly = tokenStream.peekTokenPos().end;
JS_ASSERT(endBeforeCurly >= offsetToEndOfUseAsm_);
JS_ASSERT(endAfterCurly >= offsetToEndOfUseAsm_);
pod.funcLength_ = endBeforeCurly - funcStart_;
pod.funcLengthWithRightBrace_ = endAfterCurly - funcStart_;
// The global data section sits immediately after the executable (and
// other) data allocated by the MacroAssembler, so ensure it is
@ -118,12 +174,138 @@ AsmJSModule::allocateAndCopyCode(ExclusiveContext *cx, MacroAssembler &masm)
// units of pages.
pod.totalBytes_ = AlignBytes(pod.codeBytes_ + globalDataBytes(), AsmJSPageSize);
JS_ASSERT(!code_);
code_ = AllocateExecutableMemory(cx, pod.totalBytes_);
if (!code_)
return false;
// Copy the code from the MacroAssembler into its final resting place in the
// AsmJSModule.
JS_ASSERT(uintptr_t(code_) % AsmJSPageSize == 0);
masm.executableCopy(code_);
// c.f. JitCode::copyFrom
JS_ASSERT(masm.jumpRelocationTableBytes() == 0);
JS_ASSERT(masm.dataRelocationTableBytes() == 0);
JS_ASSERT(masm.preBarrierTableBytes() == 0);
JS_ASSERT(!masm.hasEnteredExitFrame());
// Copy over metadata, making sure to update all offsets on ARM.
staticLinkData_.interruptExitOffset = masm.actualOffset(interruptLabel.offset());
// Heap-access metadata used for link-time patching and fault-handling.
heapAccesses_ = masm.extractAsmJSHeapAccesses();
// Call-site metadata used for stack unwinding.
callSites_ = masm.extractCallSites();
#if defined(JS_CODEGEN_ARM)
// ARM requires the offsets to be updated.
for (size_t i = 0; i < heapAccesses_.length(); i++) {
AsmJSHeapAccess &a = heapAccesses_[i];
a.setOffset(masm.actualOffset(a.offset()));
}
for (size_t i = 0; i < callSites_.length(); i++) {
CallSite &c = callSites_[i];
c.setReturnAddressOffset(masm.actualOffset(c.returnAddressOffset()));
}
#endif
// Absolute link metadata: absolute addresses that refer to some fixed
// address in the address space.
for (size_t i = 0; i < masm.numAsmJSAbsoluteLinks(); i++) {
AsmJSAbsoluteLink src = masm.asmJSAbsoluteLink(i);
AbsoluteLink link;
link.patchAt = CodeOffsetLabel(masm.actualOffset(src.patchAt.offset()));
link.target = src.target;
if (!staticLinkData_.absoluteLinks.append(link))
return false;
}
// Relative link metadata: absolute addresses that refer to another point within
// the asm.js module.
// CodeLabels are used for switch cases and loads from doubles in the
// constant pool.
for (size_t i = 0; i < masm.numCodeLabels(); i++) {
CodeLabel src = masm.codeLabel(i);
int32_t labelOffset = src.dest()->offset();
int32_t targetOffset = masm.actualOffset(src.src()->offset());
// The patched uses of a label embed a linked list where the
// to-be-patched immediate is the offset of the next to-be-patched
// instruction.
while (labelOffset != LabelBase::INVALID_OFFSET) {
size_t patchAtOffset = masm.labelOffsetToPatchOffset(labelOffset);
RelativeLink link(RelativeLink::CodeLabel);
link.patchAtOffset = patchAtOffset;
link.targetOffset = targetOffset;
if (!staticLinkData_.relativeLinks.append(link))
return false;
labelOffset = Assembler::extractCodeLabelOffset(code_ + patchAtOffset);
}
}
#if defined(JS_CODEGEN_X86)
// Global data accesses in x86 need to be patched with the absolute
// address of the global. Globals are allocated sequentially after the
// code section so we can just use an RelativeLink.
for (size_t i = 0; i < masm.numAsmJSGlobalAccesses(); i++) {
AsmJSGlobalAccess a = masm.asmJSGlobalAccess(i);
RelativeLink link(RelativeLink::InstructionImmediate);
link.patchAtOffset = masm.labelOffsetToPatchOffset(a.patchAt.offset());
link.targetOffset = offsetOfGlobalData() + a.globalDataOffset;
if (!staticLinkData_.relativeLinks.append(link))
return false;
}
#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++) {
RelativeLink link(RelativeLink::InstructionImmediate);
link.patchAtOffset = masm.longJump(i);
InstImm *inst = (InstImm *)(code_ + masm.longJump(i));
link.targetOffset = Assembler::extractLuiOriValue(inst, inst->next()) - (uint32_t)code_;
if (!staticLinkData_.relativeLinks.append(link))
return false;
}
#endif
#if defined(JS_CODEGEN_X64)
// Global data accesses on x64 use rip-relative addressing and thus do
// not need patching after deserialization.
for (size_t i = 0; i < masm.numAsmJSGlobalAccesses(); i++) {
AsmJSGlobalAccess a = masm.asmJSGlobalAccess(i);
masm.patchAsmJSGlobalAccess(a.patchAt, code_, globalData(), a.globalDataOffset);
}
#endif
#if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
// Fix up the code offsets. Note the endCodeOffset should not be
// filtered through 'actualOffset' as it is generated using 'size()'
// rather than a label.
for (size_t i = 0; i < profiledFunctions_.length(); i++) {
ProfiledFunction &pf = profiledFunctions_[i];
pf.pod.startCodeOffset = masm.actualOffset(pf.pod.startCodeOffset);
}
#endif
#ifdef JS_ION_PERF
for (size_t i = 0; i < perfProfiledBlocksFunctions_.length(); i++) {
ProfiledBlocksFunction &pbf = perfProfiledBlocksFunctions_[i];
pbf.pod.startCodeOffset = masm.actualOffset(pbf.pod.startCodeOffset);
pbf.endInlineCodeOffset = masm.actualOffset(pbf.endInlineCodeOffset);
BasicBlocksVector &basicBlocks = pbf.blocks;
for (uint32_t i = 0; i < basicBlocks.length(); i++) {
Record &r = basicBlocks[i];
r.startOffset = masm.actualOffset(r.startOffset);
r.endOffset = masm.actualOffset(r.endOffset);
}
}
#endif
return true;
}

View File

@ -25,6 +25,8 @@
namespace js {
namespace frontend { class TokenStream; }
// These EcmaScript-defined coercions form the basis of the asm.js type system.
enum AsmJSCoercion
{
@ -544,24 +546,16 @@ class AsmJSModule
return scriptSource_;
}
/*
* funcStart() refers to the offset in the ScriptSource to the beginning
* of the function. If the function has been created with the Function
* constructor, this will be the first character in the function source.
* Otherwise, it will be the opening parenthesis of the arguments list.
*/
// funcStart() refers to the offset in the ScriptSource to the beginning
// of the function. If the function has been created with the Function
// constructor, this will be the first character in the function source.
// Otherwise, it will be the opening parenthesis of the arguments list.
uint32_t funcStart() const {
return funcStart_;
}
uint32_t offsetToEndOfUseAsm() const {
return offsetToEndOfUseAsm_;
}
void initFuncEnd(uint32_t endBeforeCurly, uint32_t endAfterCurly) {
JS_ASSERT(endBeforeCurly >= offsetToEndOfUseAsm_);
JS_ASSERT(endAfterCurly >= offsetToEndOfUseAsm_);
pod.funcLength_ = endBeforeCurly - funcStart_;
pod.funcLengthWithRightBrace_ = endAfterCurly - funcStart_;
}
uint32_t funcEndBeforeCurly() const {
return funcStart_ + pod.funcLength_;
}
@ -817,31 +811,8 @@ class AsmJSModule
return pc >= code_ && pc < (code_ + functionBytes());
}
void assignHeapAccesses(jit::AsmJSHeapAccessVector &&accesses) {
heapAccesses_ = Move(accesses);
}
unsigned numHeapAccesses() const {
return heapAccesses_.length();
}
const jit::AsmJSHeapAccess &heapAccess(unsigned i) const {
return heapAccesses_[i];
}
jit::AsmJSHeapAccess &heapAccess(unsigned i) {
return heapAccesses_[i];
}
void assignCallSites(jit::CallSiteVector &&callsites) {
callSites_ = Move(callsites);
}
unsigned numCallSites() const {
return callSites_.length();
}
const jit::CallSite &callSite(unsigned i) const {
return callSites_[i];
}
jit::CallSite &callSite(unsigned i) {
return callSites_[i];
}
const jit::CallSite *lookupCallSite(uint8_t *returnAddress) const;
const jit::AsmJSHeapAccess *lookupHeapAccess(uint8_t *pc) const;
void initHeap(Handle<ArrayBufferObject*> heap, JSContext *cx);
@ -853,19 +824,12 @@ class AsmJSModule
return pod.minHeapLength_;
}
bool allocateAndCopyCode(ExclusiveContext *cx, jit::MacroAssembler &masm);
bool finish(ExclusiveContext *cx, frontend::TokenStream &tokenStream, jit::MacroAssembler &masm,
const jit::Label &interruptLabel);
// StaticLinkData setters (called after finishing compilation, before
// staticLink).
bool addRelativeLink(RelativeLink link) {
return staticLinkData_.relativeLinks.append(link);
}
bool addAbsoluteLink(AbsoluteLink link) {
return staticLinkData_.absoluteLinks.append(link);
}
void setInterruptOffset(uint32_t offset) {
staticLinkData_.interruptExitOffset = offset;
}
void restoreToInitialState(ArrayBufferObject *maybePrevBuffer, ExclusiveContext *cx);
void setAutoFlushICacheRange();

View File

@ -6,8 +6,6 @@
#include "jit/AsmJSSignalHandlers.h"
#include "mozilla/BinarySearch.h"
#include "assembler/assembler/MacroAssembler.h"
#include "jit/AsmJSModule.h"
@ -213,31 +211,6 @@ SetXMMRegToNaN(bool isFloat32, T *xmm_reg)
dbls[1] = 0;
}
}
struct GetHeapAccessOffset
{
const AsmJSModule &module;
explicit GetHeapAccessOffset(const AsmJSModule &module) : module(module) {}
uintptr_t operator[](size_t index) const {
return module.heapAccess(index).offset();
}
};
// Perform a binary search on the projected offsets of the known heap accesses
// in the module.
static const AsmJSHeapAccess *
LookupHeapAccess(const AsmJSModule &module, uint8_t *pc)
{
JS_ASSERT(module.containsPC(pc));
uintptr_t pcOff = pc - module.codeBase();
size_t match;
if (!BinarySearch(GetHeapAccessOffset(module), 0, module.numHeapAccesses(), pcOff, &match))
return nullptr;
return &module.heapAccess(match);
}
#endif
#if defined(XP_WIN)
@ -507,7 +480,7 @@ HandleException(PEXCEPTION_POINTERS exception)
return false;
}
const AsmJSHeapAccess *heapAccess = LookupHeapAccess(module, pc);
const AsmJSHeapAccess *heapAccess = module.lookupHeapAccess(pc);
if (!heapAccess)
return false;
@ -713,7 +686,7 @@ HandleMachException(JSRuntime *rt, const ExceptionRequest &request)
return false;
}
const AsmJSHeapAccess *heapAccess = LookupHeapAccess(module, pc);
const AsmJSHeapAccess *heapAccess = module.lookupHeapAccess(pc);
if (!heapAccess)
return false;
@ -960,7 +933,7 @@ HandleSignal(int signum, siginfo_t *info, void *ctx)
return false;
}
const AsmJSHeapAccess *heapAccess = LookupHeapAccess(module, pc);
const AsmJSHeapAccess *heapAccess = module.lookupHeapAccess(pc);
if (!heapAccess)
return false;