mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Backout merge.
This commit is contained in:
commit
b7fa67c098
@ -320,8 +320,6 @@ CPPSRCS += Assertions.cpp \
|
||||
PolyIC.cpp \
|
||||
ImmutableSync.cpp \
|
||||
InvokeHelpers.cpp \
|
||||
Retcon.cpp \
|
||||
TrampolineCompiler.cpp \
|
||||
$(NULL)
|
||||
# PICStubCompiler.cpp \
|
||||
|
||||
|
@ -341,9 +341,6 @@ public:
|
||||
};
|
||||
|
||||
X86Assembler()
|
||||
#ifdef DEBUG
|
||||
: isOOLPath(false)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -128,10 +128,6 @@ namespace JSC {
|
||||
|
||||
namespace js {
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
struct VMFrame;
|
||||
#endif
|
||||
|
||||
/* Tracer constants. */
|
||||
static const size_t MONITOR_N_GLOBAL_STATES = 4;
|
||||
static const size_t FRAGMENT_TABLE_SIZE = 512;
|
||||
@ -228,12 +224,6 @@ struct TracerState
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
namespace mjit {
|
||||
struct Trampolines
|
||||
{
|
||||
void (* forceReturn)();
|
||||
JSC::ExecutablePool *forceReturnPool;
|
||||
};
|
||||
|
||||
struct ThreadData
|
||||
{
|
||||
JSC::ExecutableAllocator *execPool;
|
||||
@ -242,11 +232,6 @@ namespace mjit {
|
||||
typedef js::HashSet<JSScript*, DefaultHasher<JSScript*>, js::SystemAllocPolicy> ScriptSet;
|
||||
ScriptSet picScripts;
|
||||
|
||||
// Trampolines for JIT code.
|
||||
Trampolines trampolines;
|
||||
|
||||
VMFrame *activeFrame;
|
||||
|
||||
bool Initialize();
|
||||
void Finish();
|
||||
|
||||
@ -359,7 +344,8 @@ class CallStack
|
||||
: cx(NULL), previousInContext(NULL), previousInThread(NULL),
|
||||
initialFrame(NULL), suspendedFrame(NULL),
|
||||
suspendedRegsAndSaved(NULL, false), initialArgEnd(NULL),
|
||||
initialVarObj(NULL) { }
|
||||
initialVarObj(NULL)
|
||||
{}
|
||||
|
||||
/* Safe casts guaranteed by the contiguous-stack layout. */
|
||||
|
||||
@ -667,6 +653,9 @@ class StackSpace
|
||||
inline Value *firstUnused() const;
|
||||
|
||||
inline void assertIsCurrent(JSContext *cx) const;
|
||||
#ifdef DEBUG
|
||||
CallStack *getCurrentCallStack() const { return currentCallStack; }
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Allocate nvals on the top of the stack, report error on failure.
|
||||
@ -793,9 +782,6 @@ class StackSpace
|
||||
/* Our privates leak into xpconnect, which needs a public symbol. */
|
||||
JS_REQUIRES_STACK
|
||||
JS_FRIEND_API(bool) pushInvokeArgsFriendAPI(JSContext *, uintN, InvokeArgsGuard &);
|
||||
|
||||
CallStack
|
||||
*getCurrentCallStack() const { return currentCallStack; }
|
||||
};
|
||||
|
||||
JS_STATIC_ASSERT(StackSpace::CAPACITY_VALS % StackSpace::COMMIT_VALS == 0);
|
||||
|
@ -69,11 +69,6 @@
|
||||
|
||||
#include "jsautooplen.h"
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
# include "methodjit/MethodJIT.h"
|
||||
# include "methodjit/Retcon.h"
|
||||
#endif
|
||||
|
||||
using namespace js;
|
||||
|
||||
typedef struct JSTrap {
|
||||
@ -195,15 +190,6 @@ JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
DBG_UNLOCK(rt);
|
||||
if (junk)
|
||||
cx->free(junk);
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
if (script->ncode != NULL && script->ncode != JS_UNJITTABLE_METHOD) {
|
||||
mjit::Recompiler recompiler(cx, script);
|
||||
if (!recompiler.recompile())
|
||||
return JS_FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
@ -248,13 +234,6 @@ JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
DestroyTrapAndUnlock(cx, trap);
|
||||
else
|
||||
DBG_UNLOCK(cx->runtime);
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
if (script->ncode != NULL && script->ncode != JS_UNJITTABLE_METHOD) {
|
||||
mjit::Recompiler recompiler(cx, script);
|
||||
recompiler.recompile();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
|
@ -169,7 +169,6 @@ namespace ic {
|
||||
struct MICInfo;
|
||||
# endif
|
||||
}
|
||||
union CallSite;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -227,14 +226,14 @@ struct JSScript {
|
||||
# if defined JS_MONOIC
|
||||
js::mjit::ic::MICInfo *mics; /* MICs in this script. */
|
||||
# endif
|
||||
js::mjit::CallSite *callSites;
|
||||
uint32 inlineLength; /* length of inline JIT'd code */
|
||||
uint32 outOfLineLength; /* length of out of line JIT'd code */
|
||||
# ifdef DEBUG
|
||||
uint32 jitLength; /* length of JIT'd code */
|
||||
|
||||
inline bool isValidJitCode(void *jcode) {
|
||||
return (char*)jcode >= (char*)nmap[-1] &&
|
||||
(char*)jcode < (char*)nmap[-1] + inlineLength + outOfLineLength;
|
||||
return (char*)jcode >= (char*)ncode &&
|
||||
(char*)jcode < (char*)ncode + jitLength;
|
||||
}
|
||||
# endif
|
||||
|
||||
# if defined JS_POLYIC
|
||||
inline uint32 numPICs() {
|
||||
|
@ -186,7 +186,6 @@ class BaseAssembler : public JSC::MacroAssembler
|
||||
STUB_CALL_TYPE(JSObjStub);
|
||||
STUB_CALL_TYPE(VoidPtrStubUInt32);
|
||||
STUB_CALL_TYPE(VoidStubUInt32);
|
||||
STUB_CALL_TYPE(VoidStub);
|
||||
|
||||
#undef STUB_CALL_TYPE
|
||||
|
||||
|
@ -40,7 +40,6 @@
|
||||
#include "BytecodeAnalyzer.h"
|
||||
#include "jsautooplen.h"
|
||||
#include "jsemit.h"
|
||||
#include "Retcon.h"
|
||||
|
||||
using namespace js;
|
||||
|
||||
@ -69,7 +68,6 @@ BytecodeAnalyzer::addEdge(jsbytecode *pc, int32 offset, uint32 stackDepth)
|
||||
bool
|
||||
BytecodeAnalyzer::analyze(uint32 index)
|
||||
{
|
||||
mjit::AutoScriptRetrapper trapper(cx, script);
|
||||
jsbytecode *pc = doList[index];
|
||||
uint32 stackDepth = ops[pc - script->code].stackDepth;
|
||||
|
||||
@ -83,13 +81,6 @@ BytecodeAnalyzer::analyze(uint32 index)
|
||||
status.visited = true;
|
||||
status.stackDepth = stackDepth;
|
||||
|
||||
if (op == JSOP_TRAP) {
|
||||
status.trap = true;
|
||||
if (!trapper.untrap(pc))
|
||||
return false;
|
||||
op = JSOp(pc[0]);
|
||||
}
|
||||
|
||||
uint32 nuses, ndefs;
|
||||
if (js_CodeSpec[op].nuses == -1)
|
||||
nuses = js_GetVariableStackUses(op, pc);
|
||||
|
@ -52,7 +52,6 @@ namespace js
|
||||
bool visited; /* flag for CFG traversal */
|
||||
bool exceptionEntry; /* true iff this is a catch/finally entry point */
|
||||
bool safePoint; /* false by default */
|
||||
bool trap; /* It's a trap! */
|
||||
bool inTryBlock; /* true if in try block */
|
||||
uint32 nincoming; /* number of CFG inedges here */
|
||||
uint32 stackDepth; /* stack depth before this opcode */
|
||||
|
@ -44,7 +44,6 @@
|
||||
#include "Compiler.h"
|
||||
#include "StubCalls.h"
|
||||
#include "MonoIC.h"
|
||||
#include "Retcon.h"
|
||||
#include "assembler/jit/ExecutableAllocator.h"
|
||||
#include "assembler/assembler/LinkBuffer.h"
|
||||
#include "FrameState-inl.h"
|
||||
@ -55,8 +54,6 @@
|
||||
using namespace js;
|
||||
using namespace js::mjit;
|
||||
|
||||
#define ADD_CALLSITE(stub) addCallSite(__LINE__, (stub))
|
||||
|
||||
#if defined(JS_METHODJIT_SPEW)
|
||||
static const char *OpcodeNames[] = {
|
||||
# define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) #name,
|
||||
@ -89,11 +86,14 @@ mjit::Compiler::Compiler(JSContext *cx, JSScript *script, JSFunction *fun, JSObj
|
||||
#if defined JS_POLYIC
|
||||
pics(ContextAllocPolicy(cx)),
|
||||
#endif
|
||||
callSites(ContextAllocPolicy(cx)), stubcc(cx, *this, frame, script)
|
||||
stubcc(cx, *this, frame, script)
|
||||
#if defined JS_TRACER
|
||||
,addTraceHints(cx->jitEnabled)
|
||||
#endif
|
||||
{
|
||||
#ifdef DEBUG
|
||||
masm.setSpewPath(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define CHECK_STATUS(expr) \
|
||||
@ -349,28 +349,11 @@ mjit::Compiler::finishThisUp()
|
||||
JSC::ExecutableAllocator::cacheFlush(result, masm.size() + stubcc.size());
|
||||
|
||||
script->ncode = (uint8 *)(result + masm.distanceOf(invokeLabel));
|
||||
script->inlineLength = masm.size();
|
||||
script->outOfLineLength = stubcc.size();
|
||||
#ifdef DEBUG
|
||||
script->jitLength = masm.size() + stubcc.size();
|
||||
#endif
|
||||
script->execPool = execPool;
|
||||
|
||||
/* Build the table of call sites. */
|
||||
CallSite *callSiteList = (CallSite *)cx->calloc(sizeof(CallSite) * (callSites.length() + 1));
|
||||
if (!callSiteList) {
|
||||
execPool->release();
|
||||
return Compile_Error;
|
||||
}
|
||||
|
||||
(callSiteList++)->nCallSites = callSites.length();
|
||||
for (size_t i = 0; i < callSites.length(); i++) {
|
||||
if (callSites[i].stub)
|
||||
callSiteList[i].c.codeOffset = masm.size() + stubcc.masm.distanceOf(callSites[i].location);
|
||||
else
|
||||
callSiteList[i].c.codeOffset = masm.distanceOf(callSites[i].location);
|
||||
callSiteList[i].c.pcOffset = callSites[i].pc - script->code;
|
||||
callSiteList[i].c.id = callSites[i].id;
|
||||
}
|
||||
script->callSites = callSiteList;
|
||||
|
||||
return Compile_Okay;
|
||||
}
|
||||
|
||||
@ -397,26 +380,19 @@ mjit::Compiler::finishThisUp()
|
||||
CompileStatus
|
||||
mjit::Compiler::generateMethod()
|
||||
{
|
||||
mjit::AutoScriptRetrapper trapper(cx, script);
|
||||
PC = script->code;
|
||||
|
||||
for (;;) {
|
||||
JSOp op = JSOp(*PC);
|
||||
|
||||
OpcodeStatus &opinfo = analysis[PC];
|
||||
if (opinfo.nincoming || opinfo.trap) {
|
||||
if (opinfo.nincoming) {
|
||||
frame.forgetEverything(opinfo.stackDepth);
|
||||
opinfo.safePoint = true;
|
||||
}
|
||||
frame.setInTryBlock(opinfo.inTryBlock);
|
||||
jumpMap[uint32(PC - script->code)] = masm.label();
|
||||
|
||||
if (opinfo.trap) {
|
||||
if (!trapper.untrap(PC))
|
||||
return Compile_Error;
|
||||
op = JSOp(*PC);
|
||||
}
|
||||
|
||||
if (!opinfo.visited) {
|
||||
if (op == JSOP_STOP)
|
||||
break;
|
||||
@ -430,13 +406,6 @@ mjit::Compiler::generateMethod()
|
||||
SPEW_OPCODE();
|
||||
JS_ASSERT(frame.stackDepth() == opinfo.stackDepth);
|
||||
|
||||
if (opinfo.trap) {
|
||||
prepareStubCall(Uses(0));
|
||||
masm.move(ImmPtr(PC), Registers::ArgReg1);
|
||||
stubCall(stubs::Trap);
|
||||
}
|
||||
ADD_CALLSITE(false);
|
||||
|
||||
/**********************
|
||||
* BEGIN COMPILER OPS *
|
||||
**********************/
|
||||
@ -1314,9 +1283,7 @@ mjit::Compiler::generateMethod()
|
||||
frame.freeReg(cxreg);
|
||||
stubcc.linkExit(jump, Uses(0));
|
||||
stubcc.leave();
|
||||
stubcc.masm.move(ImmPtr(PC), Registers::ArgReg1);
|
||||
stubcc.call(stubs::Interrupt);
|
||||
ADD_CALLSITE(true);
|
||||
stubcc.rejoin(Changes(0));
|
||||
}
|
||||
}
|
||||
@ -1439,28 +1406,6 @@ mjit::Compiler::knownJump(jsbytecode *pc)
|
||||
return pc < PC;
|
||||
}
|
||||
|
||||
void *
|
||||
mjit::Compiler::findCallSite(const CallSite &callSite)
|
||||
{
|
||||
JS_ASSERT(callSite.c.pcOffset < script->length);
|
||||
|
||||
for (uint32 i = 0; i < callSites.length(); i++) {
|
||||
if (callSites[i].pc == script->code + callSite.c.pcOffset &&
|
||||
callSites[i].id == callSite.c.id) {
|
||||
if (callSites[i].stub) {
|
||||
return (uint8*)script->nmap[-1] + masm.size() +
|
||||
stubcc.masm.distanceOf(callSites[i].location);
|
||||
}
|
||||
return (uint8*)script->nmap[-1] +
|
||||
stubcc.masm.distanceOf(callSites[i].location);
|
||||
}
|
||||
}
|
||||
|
||||
/* We have no idea where to patch up to. */
|
||||
JS_NOT_REACHED("Call site vanished.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::jumpInScript(Jump j, jsbytecode *pc)
|
||||
{
|
||||
@ -1618,7 +1563,6 @@ mjit::Compiler::inlineCallHelper(uint32 argc, bool callingNew)
|
||||
VoidPtrStubUInt32 stub = callingNew ? stubs::SlowNew : stubs::SlowCall;
|
||||
masm.move(Imm32(argc), Registers::ArgReg1);
|
||||
masm.stubCall(stub, PC, frame.stackDepth() + script->nfixed);
|
||||
ADD_CALLSITE(false);
|
||||
frame.popn(argc + 2);
|
||||
frame.pushSynced();
|
||||
return;
|
||||
@ -1663,7 +1607,6 @@ mjit::Compiler::inlineCallHelper(uint32 argc, bool callingNew)
|
||||
stubcc.leave();
|
||||
stubcc.masm.move(Imm32(argc), Registers::ArgReg1);
|
||||
stubcc.call(callingNew ? stubs::SlowNew : stubs::SlowCall);
|
||||
ADD_CALLSITE(true);
|
||||
|
||||
/* Get function private pointer. */
|
||||
Address funPrivate(data, offsetof(JSObject, fslots) +
|
||||
@ -1691,7 +1634,6 @@ mjit::Compiler::inlineCallHelper(uint32 argc, bool callingNew)
|
||||
stubcc.leave();
|
||||
stubcc.masm.move(Imm32(argc), Registers::ArgReg1);
|
||||
stubcc.call(callingNew ? stubs::SlowNew : stubs::SlowCall);
|
||||
ADD_CALLSITE(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1740,7 +1682,6 @@ mjit::Compiler::inlineCallHelper(uint32 argc, bool callingNew)
|
||||
masm.addPtr(Imm32(sizeof(void*)), Registers::StackPointer);
|
||||
#endif
|
||||
masm.call(Registers::ReturnReg);
|
||||
ADD_CALLSITE(false);
|
||||
|
||||
/*
|
||||
* The scripted call returns a register triplet, containing the jsval and
|
||||
@ -1776,22 +1717,6 @@ mjit::Compiler::inlineCallHelper(uint32 argc, bool callingNew)
|
||||
stubcc.rejoin(Changes(0));
|
||||
}
|
||||
|
||||
/*
|
||||
* This function must be called immediately after any instruction which could
|
||||
* cause a new JSStackFrame to be pushed and could lead to a new debug trap
|
||||
* being set. This includes any API callbacks and any scripted or native call.
|
||||
*/
|
||||
void
|
||||
mjit::Compiler::addCallSite(uint32 id, bool stub)
|
||||
{
|
||||
InternalCallSite site;
|
||||
site.stub = stub;
|
||||
site.location = stub ? stubcc.masm.label() : masm.label();
|
||||
site.pc = PC;
|
||||
site.id = id;
|
||||
callSites.append(site);
|
||||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::restoreFrameRegs(Assembler &masm)
|
||||
{
|
||||
|
@ -181,13 +181,6 @@ class Compiler
|
||||
bool set;
|
||||
};
|
||||
|
||||
struct InternalCallSite {
|
||||
bool stub;
|
||||
Label location;
|
||||
jsbytecode *pc;
|
||||
uint32 id;
|
||||
};
|
||||
|
||||
JSContext *cx;
|
||||
JSScript *script;
|
||||
JSObject *scopeChain;
|
||||
@ -205,7 +198,6 @@ class Compiler
|
||||
#if defined JS_POLYIC
|
||||
js::Vector<PICGenInfo, 64> pics;
|
||||
#endif
|
||||
js::Vector<InternalCallSite, 64> callSites;
|
||||
StubCompiler stubcc;
|
||||
Label invokeLabel;
|
||||
bool addTraceHints;
|
||||
@ -224,7 +216,6 @@ class Compiler
|
||||
Label getLabel() { return masm.label(); }
|
||||
bool knownJump(jsbytecode *pc);
|
||||
Label labelOf(jsbytecode *target);
|
||||
void *findCallSite(const CallSite &callSite);
|
||||
|
||||
private:
|
||||
CompileStatus generatePrologue();
|
||||
@ -237,7 +228,6 @@ class Compiler
|
||||
void jumpInScript(Jump j, jsbytecode *pc);
|
||||
JSC::ExecutablePool *getExecPool(size_t size);
|
||||
bool compareTwoValues(JSContext *cx, JSOp op, const Value &lhs, const Value &rhs);
|
||||
void addCallSite(uint32 id, bool stub);
|
||||
|
||||
/* Emitting helpers. */
|
||||
void restoreFrameRegs(Assembler &masm);
|
||||
@ -339,7 +329,6 @@ class Compiler
|
||||
STUB_CALL_TYPE(VoidStubJSObj);
|
||||
STUB_CALL_TYPE(VoidPtrStubPC);
|
||||
STUB_CALL_TYPE(VoidVpStub);
|
||||
STUB_CALL_TYPE(VoidStubPC);
|
||||
|
||||
#undef STUB_CALL_TYPE
|
||||
void prepareStubCall(Uses uses);
|
||||
|
@ -74,14 +74,14 @@ using namespace JSC;
|
||||
#define THROW() \
|
||||
do { \
|
||||
void *ptr = JS_FUNC_TO_DATA_PTR(void *, JaegerThrowpoline); \
|
||||
*f.returnAddressLocation() = ptr; \
|
||||
f.setReturnAddress(ReturnAddressPtr(FunctionPtr(ptr))); \
|
||||
return; \
|
||||
} while (0)
|
||||
|
||||
#define THROWV(v) \
|
||||
do { \
|
||||
void *ptr = JS_FUNC_TO_DATA_PTR(void *, JaegerThrowpoline); \
|
||||
*f.returnAddressLocation() = ptr; \
|
||||
f.setReturnAddress(ReturnAddressPtr(FunctionPtr(ptr))); \
|
||||
return v; \
|
||||
} while (0)
|
||||
|
||||
@ -863,7 +863,7 @@ RunTracer(VMFrame &f)
|
||||
f.fp = cx->fp;
|
||||
entryFrame->ncode = f.fp->ncode;
|
||||
void *retPtr = JS_FUNC_TO_DATA_PTR(void *, JaegerFromTracer);
|
||||
*f.returnAddressLocation() = retPtr;
|
||||
f.setReturnAddress(ReturnAddressPtr(retPtr));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,6 @@
|
||||
#include "BaseAssembler.h"
|
||||
#include "MonoIC.h"
|
||||
#include "PolyIC.h"
|
||||
#include "TrampolineCompiler.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::mjit;
|
||||
@ -56,8 +55,6 @@ static uint32 StubCallsForOp[STUB_CALLS_FOR_OP_COUNT];
|
||||
extern "C" void JS_FASTCALL
|
||||
SetVMFrameRegs(VMFrame &f)
|
||||
{
|
||||
f.previous = JS_METHODJIT_DATA(f.cx).activeFrame;
|
||||
JS_METHODJIT_DATA(f.cx).activeFrame = &f;
|
||||
f.oldRegs = f.cx->regs;
|
||||
f.cx->setCurrentRegs(&f.regs);
|
||||
}
|
||||
@ -65,8 +62,6 @@ SetVMFrameRegs(VMFrame &f)
|
||||
extern "C" void JS_FASTCALL
|
||||
UnsetVMFrameRegs(VMFrame &f)
|
||||
{
|
||||
JS_ASSERT(JS_METHODJIT_DATA(f.cx).activeFrame);
|
||||
JS_METHODJIT_DATA(f.cx).activeFrame = JS_METHODJIT_DATA(f.cx).activeFrame->previous;
|
||||
*f.oldRegs = f.regs;
|
||||
f.cx->setCurrentRegs(f.oldRegs);
|
||||
}
|
||||
@ -543,12 +538,6 @@ ThreadData::Initialize()
|
||||
if (!execPool)
|
||||
return false;
|
||||
|
||||
TrampolineCompiler tc(execPool, &trampolines);
|
||||
if (!tc.compile()) {
|
||||
delete execPool;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!picScripts.init()) {
|
||||
delete execPool;
|
||||
return false;
|
||||
@ -559,15 +548,12 @@ ThreadData::Initialize()
|
||||
StubCallsForOp[i] = 0;
|
||||
#endif
|
||||
|
||||
activeFrame = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ThreadData::Finish()
|
||||
{
|
||||
TrampolineCompiler::release(&trampolines);
|
||||
delete execPool;
|
||||
#ifdef JS_METHODJIT_PROFILE_STUBS
|
||||
FILE *fp = fopen("/tmp/stub-profiling", "wt");
|
||||
@ -686,15 +672,13 @@ void
|
||||
mjit::ReleaseScriptCode(JSContext *cx, JSScript *script)
|
||||
{
|
||||
if (script->execPool) {
|
||||
#if defined DEBUG && (defined JS_CPU_X86 || defined JS_CPU_X64)
|
||||
memset(script->nmap[-1], 0xcc, script->inlineLength + script->outOfLineLength);
|
||||
#endif
|
||||
script->execPool->release();
|
||||
script->execPool = NULL;
|
||||
// Releasing the execPool takes care of releasing the code.
|
||||
script->ncode = NULL;
|
||||
script->inlineLength = 0;
|
||||
script->outOfLineLength = 0;
|
||||
#ifdef DEBUG
|
||||
script->jitLength = 0;
|
||||
#endif
|
||||
|
||||
#if defined JS_POLYIC
|
||||
if (script->pics) {
|
||||
@ -713,10 +697,6 @@ mjit::ReleaseScriptCode(JSContext *cx, JSScript *script)
|
||||
cx->free(script->nmap - 1);
|
||||
script->nmap = NULL;
|
||||
}
|
||||
if (script->callSites) {
|
||||
cx->free(script->callSites - 1);
|
||||
script->callSites = NULL;
|
||||
}
|
||||
#if defined JS_MONOIC
|
||||
if (script->mics) {
|
||||
cx->free(script->mics);
|
||||
|
@ -65,6 +65,8 @@ struct VMFrame
|
||||
void *scriptedReturn;
|
||||
|
||||
#if defined(JS_CPU_X86)
|
||||
uintptr_t padding[2];
|
||||
#elif defined(JS_CPU_ARM)
|
||||
uintptr_t padding;
|
||||
#endif
|
||||
|
||||
@ -75,7 +77,6 @@ struct VMFrame
|
||||
} x;
|
||||
} u;
|
||||
|
||||
VMFrame *previous;
|
||||
JSFrameRegs *oldRegs;
|
||||
JSFrameRegs regs;
|
||||
JSStackFrame *fp;
|
||||
@ -90,12 +91,20 @@ struct VMFrame
|
||||
void *savedEIP;
|
||||
|
||||
#ifdef JS_NO_FASTCALL
|
||||
inline void** returnAddressLocation() {
|
||||
return reinterpret_cast<void**>(this) - 3;
|
||||
inline void setReturnAddress(JSC::ReturnAddressPtr addr) {
|
||||
*(reinterpret_cast<JSC::ReturnAddressPtr*>(this)-3) = addr;
|
||||
}
|
||||
|
||||
inline JSC::ReturnAddressPtr getReturnAddress() const {
|
||||
return *(reinterpret_cast<const JSC::ReturnAddressPtr*>(this)-3);
|
||||
}
|
||||
#else
|
||||
inline void** returnAddressLocation() {
|
||||
return reinterpret_cast<void**>(this) - 1;
|
||||
inline void setReturnAddress(JSC::ReturnAddressPtr addr) {
|
||||
*(reinterpret_cast<JSC::ReturnAddressPtr*>(this)-1) = addr;
|
||||
}
|
||||
|
||||
inline JSC::ReturnAddressPtr getReturnAddress() const {
|
||||
return *(reinterpret_cast<const JSC::ReturnAddressPtr*>(this)-1);
|
||||
}
|
||||
#endif
|
||||
#elif defined(JS_CPU_X64)
|
||||
@ -112,12 +121,20 @@ struct VMFrame
|
||||
void *savedRIP;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
inline void** returnAddressLocation() {
|
||||
return reinterpret_cast<void**>(this) - 5;
|
||||
inline void setReturnAddress(JSC::ReturnAddressPtr addr) {
|
||||
*(reinterpret_cast<JSC::ReturnAddressPtr*>(this)-5) = addr;
|
||||
}
|
||||
|
||||
inline JSC::ReturnAddressPtr getReturnAddress() const {
|
||||
return *(reinterpret_cast<const JSC::ReturnAddressPtr*>(this)-5);
|
||||
}
|
||||
#else
|
||||
inline void** returnAddressLocation() {
|
||||
return reinterpret_cast<void**>(this) - 1;
|
||||
inline void setReturnAddress(JSC::ReturnAddressPtr addr) {
|
||||
*(reinterpret_cast<JSC::ReturnAddressPtr*>(this)-1) = addr;
|
||||
}
|
||||
|
||||
inline JSC::ReturnAddressPtr getReturnAddress() const {
|
||||
return *(reinterpret_cast<const JSC::ReturnAddressPtr*>(this)-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -132,9 +149,14 @@ struct VMFrame
|
||||
void *savedR11;
|
||||
void *savedLR;
|
||||
|
||||
inline void** returnAddressLocation() {
|
||||
return reinterpret_cast<void**>(&this->veneerReturn);
|
||||
inline void setReturnAddress(JSC::ReturnAddressPtr addr) {
|
||||
this->veneerReturn = addr;
|
||||
}
|
||||
|
||||
inline JSC::ReturnAddressPtr getReturnAddress() {
|
||||
return this->veneerReturn;
|
||||
}
|
||||
|
||||
#else
|
||||
# error "The VMFrame layout isn't defined for your processor architecture!"
|
||||
#endif
|
||||
@ -162,7 +184,6 @@ typedef void (JS_FASTCALL *VoidStubAtom)(VMFrame &, JSAtom *);
|
||||
typedef JSString * (JS_FASTCALL *JSStrStub)(VMFrame &);
|
||||
typedef JSString * (JS_FASTCALL *JSStrStubUInt32)(VMFrame &, uint32);
|
||||
typedef void (JS_FASTCALL *VoidStubJSObj)(VMFrame &, JSObject *);
|
||||
typedef void (JS_FASTCALL *VoidStubPC)(VMFrame &, jsbytecode *);
|
||||
|
||||
#define JS_UNJITTABLE_METHOD (reinterpret_cast<void*>(1))
|
||||
|
||||
@ -200,16 +221,6 @@ CanMethodJIT(JSContext *cx, JSScript *script, JSFunction *fun, JSObject *scopeCh
|
||||
void
|
||||
PurgeShapeDependencies(JSContext *cx);
|
||||
|
||||
union CallSite
|
||||
{
|
||||
struct {
|
||||
uint32 codeOffset;
|
||||
uint32 pcOffset;
|
||||
uint32 id;
|
||||
} c;
|
||||
uint32 nCallSites;
|
||||
};
|
||||
|
||||
} /* namespace mjit */
|
||||
|
||||
} /* namespace js */
|
||||
|
@ -1,209 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=4 sw=4 et tw=99:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Jaegermonkey.
|
||||
*
|
||||
* The Initial Developer of the Original Code is the Mozilla Foundation.
|
||||
*
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Andrew Drake <drakedevel@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#if defined JS_METHODJIT
|
||||
|
||||
#include "Retcon.h"
|
||||
#include "MethodJIT.h"
|
||||
#include "Compiler.h"
|
||||
#include "jsdbgapi.h"
|
||||
#include "jsnum.h"
|
||||
|
||||
#include "jscntxtinlines.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::mjit;
|
||||
|
||||
namespace js {
|
||||
namespace mjit {
|
||||
|
||||
AutoScriptRetrapper::~AutoScriptRetrapper()
|
||||
{
|
||||
while (!traps.empty()) {
|
||||
jsbytecode *pc = traps.back();
|
||||
traps.popBack();
|
||||
*pc = JSOP_TRAP;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
AutoScriptRetrapper::untrap(jsbytecode *pc)
|
||||
{
|
||||
if (!traps.append(pc))
|
||||
return false;
|
||||
*pc = JS_GetTrapOpcode(cx, script, pc);
|
||||
return true;
|
||||
}
|
||||
|
||||
Recompiler::PatchableAddress
|
||||
Recompiler::findPatch(void **location)
|
||||
{
|
||||
for (uint32 i = 0; i < script->callSites[-1].nCallSites; i++) {
|
||||
if (script->callSites[i].c.codeOffset + (uint8*)script->nmap[-1] == *location) {
|
||||
PatchableAddress result;
|
||||
result.location = location;
|
||||
result.callSite = script->callSites[i];
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
JS_NOT_REACHED("failed to find call site");
|
||||
return PatchableAddress();
|
||||
}
|
||||
|
||||
void
|
||||
Recompiler::applyPatch(Compiler& c, PatchableAddress& toPatch)
|
||||
{
|
||||
void *result = c.findCallSite(toPatch.callSite);
|
||||
JS_ASSERT(result);
|
||||
*toPatch.location = result;
|
||||
}
|
||||
|
||||
Recompiler::Recompiler(JSContext *cx, JSScript *script) : cx(cx), script(script)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* The strategy for this goes as follows:
|
||||
*
|
||||
* 1) Scan the stack, looking at all return addresses that could go into JIT
|
||||
* code.
|
||||
* 2) If an address corresponds to a call site registered by |callSite| during
|
||||
* the last compilation, remember it.
|
||||
* 3) Purge the old compiled state and return if there were no active frames of
|
||||
* this script on the stack.
|
||||
* 4) Fix up the stack by replacing all saved addresses with the addresses the
|
||||
* new compiler gives us for the call sites.
|
||||
*/
|
||||
bool
|
||||
Recompiler::recompile()
|
||||
{
|
||||
JS_ASSERT(script->ncode && script->ncode != JS_UNJITTABLE_METHOD);
|
||||
|
||||
Vector<PatchableAddress> toPatch(cx);
|
||||
|
||||
/* Scan the stack, saving the ncode elements of the frames. */
|
||||
JSStackFrame *firstFrame = NULL;
|
||||
for (CallStackIterator cs(cx); !cs.done(); ++cs) {
|
||||
FrameIterator fp = cs.top();
|
||||
for (FrameIterator fp = cs.top(); fp != cs.bottom(); ++fp) {
|
||||
if (!firstFrame && fp.fp()->script == script)
|
||||
firstFrame = fp.fp();
|
||||
if (script->isValidJitCode(fp.fp()->ncode)) {
|
||||
if (!toPatch.append(findPatch(&fp.fp()->ncode)))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Iterate over VMFrames saving the machine and scripted return. */
|
||||
for (VMFrame *f = JS_METHODJIT_DATA(cx).activeFrame;
|
||||
f != NULL;
|
||||
f = f->previous) {
|
||||
|
||||
if (script->isValidJitCode(f->scriptedReturn)) {
|
||||
if (!toPatch.append(findPatch(&f->scriptedReturn)))
|
||||
return false;
|
||||
}
|
||||
|
||||
void **machineReturn = f->returnAddressLocation();
|
||||
if (script->isValidJitCode(*machineReturn))
|
||||
if (!toPatch.append(findPatch(machineReturn)))
|
||||
return false;
|
||||
}
|
||||
|
||||
ReleaseScriptCode(cx, script);
|
||||
|
||||
/* No need to actually compile or fixup if no frames on the stack */
|
||||
if (!firstFrame)
|
||||
return true;
|
||||
|
||||
Compiler c(cx, script, firstFrame->fun, firstFrame->scopeChain);
|
||||
if (c.Compile() != Compile_Okay)
|
||||
return false;
|
||||
|
||||
/* Perform the earlier scanned patches */
|
||||
for (uint32 i = 0; i < toPatch.length(); i++)
|
||||
applyPatch(c, toPatch[i]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FrameIterator&
|
||||
FrameIterator::operator++() {
|
||||
JS_ASSERT(curfp);
|
||||
curfp = curfp->down;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool
|
||||
FrameIterator::operator==(const FrameIterator& other) const {
|
||||
return curfp == other.curfp;
|
||||
}
|
||||
|
||||
bool
|
||||
FrameIterator::operator!=(const FrameIterator& other) const {
|
||||
return curfp != other.curfp;
|
||||
}
|
||||
|
||||
CallStackIterator&
|
||||
CallStackIterator::operator++() {
|
||||
JS_ASSERT(curcs);
|
||||
curcs = curcs->getPreviousInThread();
|
||||
return *this;
|
||||
}
|
||||
|
||||
FrameIterator
|
||||
CallStackIterator::top() const {
|
||||
JS_ASSERT(curcs);
|
||||
return FrameIterator(curcs->getCurrentFrame());
|
||||
}
|
||||
|
||||
FrameIterator
|
||||
CallStackIterator::bottom() const {
|
||||
JS_ASSERT(curcs);
|
||||
return FrameIterator(curcs->getInitialFrame()->down);
|
||||
}
|
||||
|
||||
} /* mjit */
|
||||
} /* js */
|
||||
|
||||
#endif /* JS_METHODJIT */
|
||||
|
@ -1,143 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=4 sw=4 et tw=99:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Jaegermonkey.
|
||||
*
|
||||
* The Initial Developer of the Original Code is the Mozilla Foundation.
|
||||
*
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Andrew Drake <drakedevel@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*
|
||||
* Retroactive continuity ("retcon") refers to the retroactive modification
|
||||
* or reinterpretation of established facts.
|
||||
*/
|
||||
|
||||
#if !defined jsjaeger_retcon_h__ && defined JS_METHODJIT
|
||||
#define jsjaeger_retcon_h__
|
||||
|
||||
#include "jscntxt.h"
|
||||
#include "jsscript.h"
|
||||
#include "MethodJIT.h"
|
||||
#include "Compiler.h"
|
||||
|
||||
namespace js {
|
||||
namespace mjit {
|
||||
|
||||
/*
|
||||
* A problem often arises where, for one reason or another, a piece of code
|
||||
* wants to touch the script->code, but isn't expecting JSOP_TRAP. This allows
|
||||
* one to temporarily remove JSOP_TRAPs from the instruction stream (without
|
||||
* copying) and automatically re-add them on scope exit.
|
||||
*/
|
||||
class AutoScriptRetrapper
|
||||
{
|
||||
public:
|
||||
AutoScriptRetrapper(JSContext *cx1, JSScript *script1) :
|
||||
cx(cx1), script(script1), traps(cx) {};
|
||||
~AutoScriptRetrapper();
|
||||
|
||||
bool untrap(jsbytecode *pc);
|
||||
|
||||
private:
|
||||
JSContext *cx;
|
||||
JSScript *script;
|
||||
Vector<jsbytecode*> traps;
|
||||
};
|
||||
|
||||
/*
|
||||
* This class is responsible for sanely re-JITing a script and fixing up
|
||||
* the world. If you ever change the code associated with a JSScript, or
|
||||
* otherwise would cause existing JITed code to be incorrect, you /must/ use
|
||||
* this to invalidate and potentially re-compile the existing JITed code,
|
||||
* fixing up the stack in the process.
|
||||
*/
|
||||
class Recompiler {
|
||||
struct PatchableAddress {
|
||||
void **location;
|
||||
CallSite callSite;
|
||||
};
|
||||
|
||||
public:
|
||||
Recompiler(JSContext *cx, JSScript *script);
|
||||
|
||||
bool recompile();
|
||||
|
||||
private:
|
||||
JSContext *cx;
|
||||
JSScript *script;
|
||||
|
||||
PatchableAddress findPatch(void **location);
|
||||
void applyPatch(Compiler& c, PatchableAddress& toPatch);
|
||||
};
|
||||
|
||||
/*
|
||||
* Utility classes to make iteration over the stack clean.
|
||||
*/
|
||||
class FrameIterator
|
||||
{
|
||||
public:
|
||||
FrameIterator(JSStackFrame *frame) : curfp(frame) { };
|
||||
|
||||
bool done() const { return curfp == NULL; }
|
||||
FrameIterator& operator++();
|
||||
bool operator==(const FrameIterator& other) const;
|
||||
bool operator!=(const FrameIterator& other) const;
|
||||
|
||||
JSStackFrame *fp() const { return curfp; }
|
||||
|
||||
private:
|
||||
JSStackFrame *curfp;
|
||||
};
|
||||
|
||||
class CallStackIterator
|
||||
{
|
||||
public:
|
||||
CallStackIterator(JSContext *cx) : curcs(cx->stack().getCurrentCallStack()) { };
|
||||
|
||||
bool done() const { return curcs == NULL; }
|
||||
CallStackIterator& operator++();
|
||||
FrameIterator top() const;
|
||||
FrameIterator bottom() const;
|
||||
|
||||
CallStack *cs() const { return curcs; }
|
||||
|
||||
private:
|
||||
CallStack *curcs;
|
||||
};
|
||||
|
||||
} /* mjit */
|
||||
} /* js */
|
||||
|
||||
#endif
|
||||
|
@ -47,14 +47,14 @@ namespace mjit {
|
||||
#define THROW() \
|
||||
do { \
|
||||
void *ptr = JS_FUNC_TO_DATA_PTR(void *, JaegerThrowpoline); \
|
||||
*f.returnAddressLocation() = ptr; \
|
||||
f.setReturnAddress(ReturnAddressPtr(FunctionPtr(ptr))); \
|
||||
return; \
|
||||
} while (0)
|
||||
|
||||
#define THROWV(v) \
|
||||
do { \
|
||||
void *ptr = JS_FUNC_TO_DATA_PTR(void *, JaegerThrowpoline); \
|
||||
*f.returnAddressLocation() = ptr; \
|
||||
f.setReturnAddress(ReturnAddressPtr(FunctionPtr(ptr))); \
|
||||
return v; \
|
||||
} while (0)
|
||||
|
||||
|
@ -50,7 +50,6 @@
|
||||
#include "assembler/assembler/MacroAssemblerCodeRef.h"
|
||||
#include "jsiter.h"
|
||||
#include "jstypes.h"
|
||||
#include "methodjit/Compiler.h"
|
||||
#include "methodjit/StubCalls.h"
|
||||
#include "jstracer.h"
|
||||
#include "jspropertycache.h"
|
||||
@ -1313,36 +1312,10 @@ stubs::NewArray(VMFrame &f, uint32 len)
|
||||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
stubs::Interrupt(VMFrame &f, jsbytecode *pc)
|
||||
stubs::Interrupt(VMFrame &f)
|
||||
{
|
||||
if (!js_HandleExecutionInterrupt(f.cx))
|
||||
if (!js_HandleExecutionInterrupt(f.cx)) {
|
||||
THROW();
|
||||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
stubs::Trap(VMFrame &f, jsbytecode *pc)
|
||||
{
|
||||
Value rval;
|
||||
|
||||
switch (JS_HandleTrap(f.cx, f.cx->fp->script, pc, Jsvalify(&rval))) {
|
||||
case JSTRAP_THROW:
|
||||
f.cx->throwing = JS_TRUE;
|
||||
f.cx->exception = rval;
|
||||
THROW();
|
||||
|
||||
case JSTRAP_RETURN:
|
||||
f.cx->throwing = JS_FALSE;
|
||||
f.cx->fp->rval = rval;
|
||||
*f.returnAddressLocation() = JS_FUNC_TO_DATA_PTR(void *,
|
||||
JS_METHODJIT_DATA(f.cx).trampolines.forceReturn);
|
||||
break;
|
||||
|
||||
case JSTRAP_ERROR:
|
||||
f.cx->throwing = JS_FALSE;
|
||||
THROW();
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,8 +52,7 @@ void JS_FASTCALL ComputeThis(VMFrame &f);
|
||||
JSObject * JS_FASTCALL NewInitArray(VMFrame &f);
|
||||
JSObject * JS_FASTCALL NewInitObject(VMFrame &f, uint32 empty);
|
||||
JSObject * JS_FASTCALL NewArray(VMFrame &f, uint32 len);
|
||||
void JS_FASTCALL Trap(VMFrame &f, jsbytecode *pc);
|
||||
void JS_FASTCALL Interrupt(VMFrame &f, jsbytecode *pc);
|
||||
void JS_FASTCALL Interrupt(VMFrame &f);
|
||||
void JS_FASTCALL InitElem(VMFrame &f, uint32 last);
|
||||
void JS_FASTCALL InitProp(VMFrame &f, JSAtom *atom);
|
||||
void JS_FASTCALL InitMethod(VMFrame &f, JSAtom *atom);
|
||||
|
@ -121,7 +121,6 @@ class StubCompiler
|
||||
STUB_CALL_TYPE(VoidPtrStub);
|
||||
STUB_CALL_TYPE(BoolStub);
|
||||
STUB_CALL_TYPE(VoidStubAtom);
|
||||
STUB_CALL_TYPE(VoidStubPC);
|
||||
|
||||
#undef STUB_CALL_TYPE
|
||||
|
||||
|
@ -1,165 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=4 sw=4 et tw=99:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Jaegermonkey.
|
||||
*
|
||||
* The Initial Developer of the Original Code is the Mozilla Foundation.
|
||||
*
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Andrew Drake <drakedevel@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#if defined JS_METHODJIT
|
||||
|
||||
#include "TrampolineCompiler.h"
|
||||
#include "StubCalls.h"
|
||||
#include "assembler/assembler/LinkBuffer.h"
|
||||
|
||||
namespace js {
|
||||
namespace mjit {
|
||||
|
||||
#define CHECK_RESULT(x) if (!(x)) return false
|
||||
#define COMPILE(which, pool, how) CHECK_RESULT(compileTrampoline((void **)(&(which)), &pool, how))
|
||||
#define RELEASE(which, pool) JS_BEGIN_MACRO \
|
||||
which = NULL; \
|
||||
if (pool) \
|
||||
pool->release(); \
|
||||
pool = NULL; \
|
||||
JS_END_MACRO
|
||||
|
||||
#ifdef JS_CPU_X86
|
||||
static const JSC::MacroAssembler::RegisterID JSReturnReg_Type = JSC::X86Registers::ecx;
|
||||
static const JSC::MacroAssembler::RegisterID JSReturnReg_Data = JSC::X86Registers::edx;
|
||||
#elif defined(JS_CPU_ARM)
|
||||
static const JSC::MacroAssembler::RegisterID JSReturnReg_Type = JSC::ARMRegisters::r2;
|
||||
static const JSC::MacroAssembler::RegisterID JSReturnReg_Data = JSC::ARMRegisters::r1;
|
||||
#endif
|
||||
|
||||
bool
|
||||
TrampolineCompiler::compile()
|
||||
{
|
||||
#ifdef JS_METHODJIT_SPEW
|
||||
JMCheckLogging();
|
||||
#endif
|
||||
|
||||
COMPILE(trampolines->forceReturn, trampolines->forceReturnPool, generateForceReturn);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TrampolineCompiler::release(Trampolines *tramps)
|
||||
{
|
||||
RELEASE(tramps->forceReturn, tramps->forceReturnPool);
|
||||
}
|
||||
|
||||
bool
|
||||
TrampolineCompiler::compileTrampoline(void **where, JSC::ExecutablePool **pool,
|
||||
TrampolineGenerator generator)
|
||||
{
|
||||
Assembler masm;
|
||||
|
||||
Label entry = masm.label();
|
||||
CHECK_RESULT(generator(masm));
|
||||
JS_ASSERT(entry.isValid());
|
||||
|
||||
*pool = execPool->poolForSize(masm.size());
|
||||
if (!*pool)
|
||||
return false;
|
||||
|
||||
JSC::LinkBuffer buffer(&masm, *pool);
|
||||
uint8 *result = (uint8*)buffer.finalizeCodeAddendum().dataLocation();
|
||||
masm.finalize(result);
|
||||
*where = result + masm.distanceOf(entry);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is shamelessly copied from emitReturn, but with several changes:
|
||||
* - There was always at least one inline call.
|
||||
* - We don't know if there is a call object, so we always check.
|
||||
* - We don't know where we came from, so we don't know frame depth or PC.
|
||||
* - There is no stub buffer.
|
||||
*/
|
||||
bool
|
||||
TrampolineCompiler::generateForceReturn(Assembler &masm)
|
||||
{
|
||||
/* if (!callobj) stubs::PutCallObject */
|
||||
Jump noCallObj = masm.branchPtr(Assembler::Equal,
|
||||
Address(JSFrameReg, offsetof(JSStackFrame, callobj)),
|
||||
ImmPtr(0));
|
||||
masm.stubCall(stubs::PutCallObject, NULL, 0);
|
||||
noCallObj.linkTo(masm.label(), &masm);
|
||||
|
||||
/* if (arguments) stubs::PutArgsObject */
|
||||
Jump noArgsObj = masm.branchPtr(Assembler::Equal,
|
||||
Address(JSFrameReg, offsetof(JSStackFrame, argsobj)),
|
||||
ImmIntPtr(0));
|
||||
masm.stubCall(stubs::PutArgsObject, NULL, 0);
|
||||
noArgsObj.linkTo(masm.label(), &masm);
|
||||
|
||||
/*
|
||||
* r = fp->down
|
||||
* a1 = f.cx
|
||||
* f.fp = r
|
||||
* cx->fp = r
|
||||
*/
|
||||
masm.loadPtr(Address(JSFrameReg, offsetof(JSStackFrame, down)), Registers::ReturnReg);
|
||||
masm.loadPtr(FrameAddress(offsetof(VMFrame, cx)), Registers::ArgReg1);
|
||||
masm.storePtr(Registers::ReturnReg, FrameAddress(offsetof(VMFrame, fp)));
|
||||
masm.storePtr(Registers::ReturnReg, Address(Registers::ArgReg1, offsetof(JSContext, fp)));
|
||||
masm.subPtr(ImmIntPtr(1), FrameAddress(offsetof(VMFrame, inlineCallCount)));
|
||||
|
||||
Address rval(JSFrameReg, offsetof(JSStackFrame, rval));
|
||||
masm.load32(masm.payloadOf(rval), JSReturnReg_Data);
|
||||
masm.load32(masm.tagOf(rval), JSReturnReg_Type);
|
||||
masm.move(Registers::ReturnReg, JSFrameReg);
|
||||
masm.loadPtr(Address(JSFrameReg, offsetof(JSStackFrame, ncode)), Registers::ReturnReg);
|
||||
#ifdef DEBUG
|
||||
masm.storePtr(ImmPtr(JSStackFrame::sInvalidPC),
|
||||
Address(JSFrameReg, offsetof(JSStackFrame, savedPC)));
|
||||
#endif
|
||||
|
||||
#if defined(JS_CPU_ARM)
|
||||
masm.loadPtr(FrameAddress(offsetof(VMFrame, scriptedReturn)), JSC::ARMRegisters::lr);
|
||||
#endif
|
||||
|
||||
masm.ret();
|
||||
return true;
|
||||
}
|
||||
|
||||
} /* mjit */
|
||||
} /* js */
|
||||
|
||||
#endif /* JS_METHOJIT */
|
||||
|
@ -1,81 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=4 sw=4 et tw=99:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Jaegermonkey.
|
||||
*
|
||||
* The Initial Developer of the Original Code is the Mozilla Foundation.
|
||||
*
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Andrew Drake <drakedevel@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#if !defined jsjaeger_trampolinecompiler_h__ && defined JS_METHODJIT
|
||||
#define jsjaeger_trampolinecompiler_h__
|
||||
|
||||
#include "assembler/jit/ExecutableAllocator.h"
|
||||
#include "CodeGenIncludes.h"
|
||||
|
||||
namespace js {
|
||||
namespace mjit {
|
||||
|
||||
class TrampolineCompiler
|
||||
{
|
||||
typedef Assembler::Label Label;
|
||||
typedef Assembler::Jump Jump;
|
||||
typedef Assembler::ImmPtr ImmPtr;
|
||||
typedef Assembler::Address Address;
|
||||
typedef bool (*TrampolineGenerator)(Assembler &masm);
|
||||
|
||||
public:
|
||||
TrampolineCompiler(JSC::ExecutableAllocator *pool, Trampolines *tramps)
|
||||
: execPool(pool), trampolines(tramps)
|
||||
{ }
|
||||
|
||||
bool compile();
|
||||
static void release(Trampolines *tramps);
|
||||
|
||||
private:
|
||||
bool compileTrampoline(void **where, JSC::ExecutablePool **pool,
|
||||
TrampolineGenerator generator);
|
||||
|
||||
/* Generators for trampolines. */
|
||||
static bool generateForceReturn(Assembler &masm);
|
||||
|
||||
JSC::ExecutableAllocator *execPool;
|
||||
Trampolines *trampolines;
|
||||
};
|
||||
|
||||
} /* mjit */
|
||||
} /* js */
|
||||
|
||||
#endif
|
||||
|
@ -1,8 +0,0 @@
|
||||
var x = "failure";
|
||||
function main() { x = "success"; }
|
||||
|
||||
/* The JSOP_STOP in a. */
|
||||
trap(main, 8, "");
|
||||
main();
|
||||
|
||||
assertEq(x, "success");
|
@ -1,9 +0,0 @@
|
||||
var x = "notset";
|
||||
function main() { x = "failure"; }
|
||||
function success() { x = "success"; }
|
||||
|
||||
/* The JSOP_STOP in a. */
|
||||
trap(main, 8, "success()");
|
||||
main();
|
||||
|
||||
assertEq(x, "success");
|
@ -1,10 +0,0 @@
|
||||
var x = "notset";
|
||||
function main() { x = "success"; }
|
||||
function failure() { x = "failure"; }
|
||||
|
||||
/* The JSOP_STOP in a. */
|
||||
trap(main, 8, "failure()");
|
||||
untrap(main, 8);
|
||||
main();
|
||||
|
||||
assertEq(x, "success");
|
@ -1,6 +0,0 @@
|
||||
function main() {
|
||||
return "failure";
|
||||
}
|
||||
/* JSOP_RETURN in main. */
|
||||
trap(main, 4, "'success'");
|
||||
assertEq(main(), "success");
|
@ -1,6 +0,0 @@
|
||||
function main() {
|
||||
return 1;
|
||||
}
|
||||
/* JSOP_RETURN in main. */
|
||||
trap(main, 2, "0");
|
||||
assertEq(main(), 0);
|
@ -1,14 +0,0 @@
|
||||
x = "notset";
|
||||
function myparent(nested) {
|
||||
if (nested) {
|
||||
/* myparent call in myparent. */
|
||||
trap(myparent, 40, "failure()");
|
||||
} else {
|
||||
x = "success";
|
||||
myparent(true);
|
||||
}
|
||||
}
|
||||
function failure() { x = "failure"; }
|
||||
|
||||
myparent(false);
|
||||
assertEq(x, "success");
|
@ -1,20 +0,0 @@
|
||||
x = "notset";
|
||||
|
||||
function child() {
|
||||
x = "failure1";
|
||||
/* JSOP_STOP in parent. */
|
||||
trap(parent, 11, "success()");
|
||||
}
|
||||
|
||||
function parent() {
|
||||
x = "failure2";
|
||||
}
|
||||
/* First op in parent. */
|
||||
trap(parent, 1, "child()");
|
||||
|
||||
function success() {
|
||||
x = "success";
|
||||
}
|
||||
|
||||
parent();
|
||||
assertEq(x, "success");
|
@ -1,15 +0,0 @@
|
||||
x = "notset";
|
||||
function child() {
|
||||
/* JSOP_STOP in parent. */
|
||||
trap(parent, 19, "success()");
|
||||
}
|
||||
function parent() {
|
||||
child();
|
||||
x = "failure";
|
||||
}
|
||||
function success() {
|
||||
x = "success";
|
||||
}
|
||||
|
||||
parent()
|
||||
assertEq(x, "success");
|
@ -1,17 +0,0 @@
|
||||
x = "notset";
|
||||
|
||||
function myparent(nested) {
|
||||
if (nested) {
|
||||
/* noop call in myparent */
|
||||
trap(myparent, 48, "success()");
|
||||
} else {
|
||||
myparent(true);
|
||||
x = "failure";
|
||||
noop();
|
||||
}
|
||||
}
|
||||
function noop() { }
|
||||
function success() { x = "success"; }
|
||||
|
||||
myparent();
|
||||
assertEq(x, "success");
|
@ -1,22 +0,0 @@
|
||||
x = "notset";
|
||||
|
||||
function doNothing() { }
|
||||
|
||||
function myparent(nested) {
|
||||
if (nested) {
|
||||
/* JSOP_CALL to doNothing in myparent with nested = true. */
|
||||
trap(myparent, 26, "success()");
|
||||
doNothing();
|
||||
} else {
|
||||
doNothing();
|
||||
}
|
||||
}
|
||||
/* JSOP_CALL to doNothing in myparent with nested = false. */
|
||||
trap(myparent, 37, "myparent(true)");
|
||||
|
||||
function success() {
|
||||
x = "success";
|
||||
}
|
||||
|
||||
myparent(false);
|
||||
assertEq(x, "success");
|
@ -1,10 +0,0 @@
|
||||
x = "notset";
|
||||
function main() {
|
||||
/* The JSOP_STOP in a. */
|
||||
trap(main, 27, "success()");
|
||||
x = "failure";
|
||||
}
|
||||
function success() { x = "success"; }
|
||||
|
||||
main();
|
||||
assertEq(x, "success");
|
@ -1,14 +0,0 @@
|
||||
x = "notset";
|
||||
function child() {
|
||||
/* JSOP_STOP in parent */
|
||||
untrap(parent, 11);
|
||||
x = "success";
|
||||
}
|
||||
function parent() {
|
||||
x = "failure";
|
||||
}
|
||||
/* JSOP_STOP in parent */
|
||||
trap(parent, 11, "child()");
|
||||
|
||||
parent();
|
||||
assertEq(x, "success");
|
@ -1,12 +0,0 @@
|
||||
x = "notset";
|
||||
function main() {
|
||||
/* JSOP_STOP in main. */
|
||||
untrap(main, 23);
|
||||
x = "success";
|
||||
}
|
||||
function failure() { x = "failure"; }
|
||||
|
||||
/* JSOP_STOP in main. */
|
||||
trap(main, 23, "failure()");
|
||||
main();
|
||||
assertEq(x, "success");
|
Loading…
Reference in New Issue
Block a user