Backout 589b6766b99a (bug 786146) due to test bustage on a CLOSED TREE.

This commit is contained in:
Ryan VanderMeulen 2012-10-25 20:05:13 -04:00
parent 6eb0ddf707
commit f6df03b1a0
24 changed files with 496 additions and 512 deletions

File diff suppressed because it is too large Load Diff

View File

@ -122,29 +122,20 @@ ion::InitializeIon()
return true;
}
IonRuntime::IonRuntime()
IonCompartment::IonCompartment()
: execAlloc_(NULL),
enterJIT_(NULL),
bailoutHandler_(NULL),
argumentsRectifier_(NULL),
invalidator_(NULL),
functionWrappers_(NULL)
functionWrappers_(NULL),
flusher_(NULL)
{
}
IonRuntime::~IonRuntime()
{
js_delete(functionWrappers_);
}
bool
IonRuntime::initialize(JSContext *cx)
IonCompartment::initialize(JSContext *cx)
{
AutoEnterAtomsCompartment ac(cx);
if (!cx->compartment->ensureIonCompartmentExists(cx))
return false;
execAlloc_ = cx->runtime->getExecAlloc(cx);
if (!execAlloc_)
return false;
@ -153,53 +144,9 @@ IonRuntime::initialize(JSContext *cx)
if (!functionWrappers_ || !functionWrappers_->init())
return false;
if (!bailoutTables_.reserve(FrameSizeClass::ClassLimit().classId()))
return false;
for (uint32 id = 0;; id++) {
FrameSizeClass class_ = FrameSizeClass::FromClass(id);
if (class_ == FrameSizeClass::ClassLimit())
break;
bailoutTables_.infallibleAppend(NULL);
bailoutTables_[id] = generateBailoutTable(cx, id);
if (!bailoutTables_[id])
return false;
}
bailoutHandler_ = generateBailoutHandler(cx);
if (!bailoutHandler_)
return false;
argumentsRectifier_ = generateArgumentsRectifier(cx);
if (!argumentsRectifier_)
return false;
invalidator_ = generateInvalidator(cx);
if (!invalidator_)
return false;
enterJIT_ = generateEnterJIT(cx);
if (!enterJIT_)
return false;
preBarrier_ = generatePreBarrier(cx);
if (!preBarrier_)
return false;
for (VMFunction *fun = VMFunction::functions; fun; fun = fun->next) {
if (!generateVMWrapper(cx, *fun))
return false;
}
return true;
}
IonCompartment::IonCompartment(IonRuntime *rt)
: rt(rt),
flusher_(NULL)
{
}
void
ion::FinishOffThreadBuilder(IonBuilder *builder)
{
@ -244,6 +191,11 @@ IonCompartment::mark(JSTracer *trc, JSCompartment *compartment)
mustMarkEnterJIT = true;
}
// These must be available if we could be running JIT code; they are not
// traced as normal through IonCode or IonScript objects
if (mustMarkEnterJIT)
MarkIonCodeRoot(trc, enterJIT_.unsafeGet(), "enterJIT");
// functionWrappers_ are not marked because this is a WeakCache of VM
// function implementations.
@ -255,26 +207,55 @@ IonCompartment::mark(JSTracer *trc, JSCompartment *compartment)
void
IonCompartment::sweep(FreeOp *fop)
{
if (enterJIT_ && !IsIonCodeMarked(enterJIT_.unsafeGet()))
enterJIT_ = NULL;
if (bailoutHandler_ && !IsIonCodeMarked(bailoutHandler_.unsafeGet()))
bailoutHandler_ = NULL;
if (argumentsRectifier_ && !IsIonCodeMarked(argumentsRectifier_.unsafeGet()))
argumentsRectifier_ = NULL;
if (invalidator_ && !IsIonCodeMarked(invalidator_.unsafeGet()))
invalidator_ = NULL;
if (preBarrier_ && !IsIonCodeMarked(preBarrier_.unsafeGet()))
preBarrier_ = NULL;
for (size_t i = 0; i < bailoutTables_.length(); i++) {
if (bailoutTables_[i] && !IsIonCodeMarked(bailoutTables_[i].unsafeGet()))
bailoutTables_[i] = NULL;
}
// Sweep cache of VM function implementations.
functionWrappers_->sweep(fop);
}
IonCode *
IonCompartment::getBailoutTable(const FrameSizeClass &frameClass)
{
JS_ASSERT(frameClass != FrameSizeClass::None());
return rt->bailoutTables_[frameClass.classId()];
return bailoutTables_[frameClass.classId()];
}
IonCode *
IonCompartment::getVMWrapper(const VMFunction &f)
IonCompartment::getBailoutTable(JSContext *cx, const FrameSizeClass &frameClass)
{
typedef MoveResolver::MoveOperand MoveOperand;
uint32 id = frameClass.classId();
JS_ASSERT(rt->functionWrappers_);
JS_ASSERT(rt->functionWrappers_->initialized());
IonRuntime::VMWrapperMap::Ptr p = rt->functionWrappers_->lookup(&f);
JS_ASSERT(p);
if (id >= bailoutTables_.length()) {
size_t numToPush = id - bailoutTables_.length() + 1;
if (!bailoutTables_.reserve(bailoutTables_.length() + numToPush))
return NULL;
for (size_t i = 0; i < numToPush; i++)
bailoutTables_.infallibleAppend(NULL);
}
return p->value;
if (!bailoutTables_[id])
bailoutTables_[id] = generateBailoutTable(cx, id);
return bailoutTables_[id];
}
IonCompartment::~IonCompartment()
{
js_delete(functionWrappers_);
}
IonActivation::IonActivation(JSContext *cx, StackFrame *fp)
@ -346,8 +327,15 @@ IonCode::trace(JSTracer *trc)
{
// Note that we cannot mark invalidated scripts, since we've basically
// corrupted the code stream by injecting bailouts.
if (invalidated())
if (invalidated()) {
// Note that since we're invalidated, we won't mark the precious
// invalidator thunk referenced in the epilogue. We don't move
// executable code so the actual reference is okay, we just need to
// make sure it says alive before we return.
IonCompartment *ion = compartment()->ionCompartment();
MarkIonCodeUnbarriered(trc, ion->getInvalidationThunkAddr(), "invalidator");
return;
}
if (jumpRelocTableBytes_) {
uint8 *start = code_ + jumpRelocTableOffset();
@ -1001,7 +989,6 @@ AttachFinishedCompilations(JSContext *cx)
CodeGenerator codegen(builder, *builder->backgroundCompiledLir);
types::AutoEnterTypeInference enterTypes(cx);
types::AutoEnterCompilation enterCompiler(cx, types::AutoEnterCompilation::Ion);
enterCompiler.initExisting(builder->recompileInfo);
@ -1294,6 +1281,13 @@ ion::CanEnterAtBranch(JSContext *cx, HandleScript script, StackFrame *fp, jsbyte
if (script->ion->osrPc() != pc)
return Method_Skipped;
// This can GC, so afterward, script->ion is not guaranteed to be valid.
if (!cx->compartment->ionCompartment()->enterJIT(cx))
return Method_Error;
if (!script->ion)
return Method_Skipped;
return Method_Compiled;
}
@ -1340,6 +1334,13 @@ ion::CanEnter(JSContext *cx, HandleScript script, StackFrame *fp, bool newType)
return status;
}
// This can GC, so afterward, script->ion is not guaranteed to be valid.
if (!cx->compartment->ionCompartment()->enterJIT(cx))
return Method_Error;
if (!script->ion)
return Method_Skipped;
return Method_Compiled;
}
@ -1357,7 +1358,7 @@ ion::CanEnterUsingFastInvoke(JSContext *cx, HandleScript script)
// This can GC, so afterward, script->ion is not guaranteed to be valid.
AssertCanGC();
if (!cx->compartment->ionCompartment()->enterJIT())
if (!cx->compartment->ionCompartment()->enterJIT(cx))
return Method_Error;
if (!script->ion)
@ -1375,7 +1376,7 @@ EnterIon(JSContext *cx, StackFrame *fp, void *jitcode)
JS_ASSERT(CheckFrame(fp));
JS_ASSERT(!fp->script()->ion->bailoutExpected());
EnterIonCode enter = cx->compartment->ionCompartment()->enterJIT();
EnterIonCode enter = cx->compartment->ionCompartment()->enterJITInfallible();
// maxArgc is the maximum of arguments between the number of actual
// arguments and the number of formal arguments. It accounts for |this|.
@ -1549,7 +1550,7 @@ ion::FastInvoke(JSContext *cx, HandleFunction fun, CallArgs &args)
activation.setPrevPc(cx->regs().pc);
EnterIonCode enter = cx->compartment->ionCompartment()->enterJIT();
EnterIonCode enter = cx->compartment->ionCompartment()->enterJITInfallible();
void *calleeToken = CalleeToToken(fun);
Value result = Int32Value(fun->nargs);

View File

@ -27,58 +27,37 @@ class IonBuilder;
typedef Vector<IonBuilder*, 0, SystemAllocPolicy> OffThreadCompilationVector;
class IonRuntime
class IonCompartment
{
friend class IonCompartment;
typedef WeakCache<const VMFunction *, ReadBarriered<IonCode> > VMWrapperMap;
// Executable allocator.
friend class IonActivation;
// Executable allocator (owned by the runtime).
JSC::ExecutableAllocator *execAlloc_;
// Trampoline for entering JIT code. Contains OSR prologue.
IonCode *enterJIT_;
ReadBarriered<IonCode> enterJIT_;
// Vector mapping frame class sizes to bailout tables.
Vector<IonCode*, 4, SystemAllocPolicy> bailoutTables_;
Vector<ReadBarriered<IonCode>, 4, SystemAllocPolicy> bailoutTables_;
// Generic bailout table; used if the bailout table overflows.
IonCode *bailoutHandler_;
ReadBarriered<IonCode> bailoutHandler_;
// Argument-rectifying thunk, in the case of insufficient arguments passed
// to a function call site. Pads with |undefined|.
IonCode *argumentsRectifier_;
ReadBarriered<IonCode> argumentsRectifier_;
// Thunk that invalides an (Ion compiled) caller on the Ion stack.
IonCode *invalidator_;
ReadBarriered<IonCode> invalidator_;
// Thunk that calls the GC pre barrier.
IonCode *preBarrier_;
ReadBarriered<IonCode> preBarrier_;
// Map VMFunction addresses to the IonCode of the wrapper.
typedef WeakCache<const VMFunction *, IonCode *> VMWrapperMap;
VMWrapperMap *functionWrappers_;
private:
IonCode *generateEnterJIT(JSContext *cx);
IonCode *generateArgumentsRectifier(JSContext *cx);
IonCode *generateBailoutTable(JSContext *cx, uint32 frameClass);
IonCode *generateBailoutHandler(JSContext *cx);
IonCode *generateInvalidator(JSContext *cx);
IonCode *generatePreBarrier(JSContext *cx);
IonCode *generateVMWrapper(JSContext *cx, const VMFunction &f);
public:
IonRuntime();
~IonRuntime();
bool initialize(JSContext *cx);
};
class IonCompartment
{
friend class IonActivation;
// Ion state for the compartment's runtime.
IonRuntime *rt;
// Any scripts for which off thread compilation has successfully finished,
// failed, or been cancelled. All off thread compilations which are started
// will eventually appear in this list asynchronously. Protected by the
@ -88,45 +67,94 @@ class IonCompartment
// Keep track of memoryregions that are going to be flushed.
AutoFlushCache *flusher_;
private:
IonCode *generateEnterJIT(JSContext *cx);
IonCode *generateReturnError(JSContext *cx);
IonCode *generateArgumentsRectifier(JSContext *cx);
IonCode *generateBailoutTable(JSContext *cx, uint32 frameClass);
IonCode *generateBailoutHandler(JSContext *cx);
IonCode *generateInvalidator(JSContext *cx);
IonCode *generatePreBarrier(JSContext *cx);
public:
IonCode *getVMWrapper(const VMFunction &f);
IonCode *generateVMWrapper(JSContext *cx, const VMFunction &f);
OffThreadCompilationVector &finishedOffThreadCompilations() {
return finishedOffThreadCompilations_;
}
public:
IonCompartment(IonRuntime *rt);
bool initialize(JSContext *cx);
IonCompartment();
~IonCompartment();
void mark(JSTracer *trc, JSCompartment *compartment);
void sweep(FreeOp *fop);
JSC::ExecutableAllocator *execAlloc() {
return rt->execAlloc_;
return execAlloc_;
}
IonCode *getGenericBailoutHandler() {
return rt->bailoutHandler_;
IonCode *getBailoutTable(JSContext *cx, const FrameSizeClass &frameClass);
IonCode *getGenericBailoutHandler(JSContext *cx) {
if (!bailoutHandler_) {
bailoutHandler_ = generateBailoutHandler(cx);
if (!bailoutHandler_)
return NULL;
}
return bailoutHandler_;
}
// Infallible; does not generate a table.
IonCode *getBailoutTable(const FrameSizeClass &frameClass);
IonCode *getArgumentsRectifier() {
return rt->argumentsRectifier_;
// Fallible; generates a thunk and returns the target.
IonCode *getArgumentsRectifier(JSContext *cx) {
if (!argumentsRectifier_) {
argumentsRectifier_ = generateArgumentsRectifier(cx);
if (!argumentsRectifier_)
return NULL;
}
return argumentsRectifier_;
}
IonCode **getArgumentsRectifierAddr() {
return argumentsRectifier_.unsafeGet();
}
IonCode *getInvalidationThunk() {
return rt->invalidator_;
IonCode *getOrCreateInvalidationThunk(JSContext *cx) {
if (!invalidator_) {
invalidator_ = generateInvalidator(cx);
if (!invalidator_)
return NULL;
}
return invalidator_;
}
IonCode **getInvalidationThunkAddr() {
return invalidator_.unsafeGet();
}
EnterIonCode enterJIT() {
return rt->enterJIT_->as<EnterIonCode>();
EnterIonCode enterJITInfallible() {
JS_ASSERT(enterJIT_);
return enterJIT_.get()->as<EnterIonCode>();
}
IonCode *preBarrier() {
return rt->preBarrier_;
EnterIonCode enterJIT(JSContext *cx) {
if (!enterJIT_) {
enterJIT_ = generateEnterJIT(cx);
if (!enterJIT_)
return NULL;
}
return enterJIT_.get()->as<EnterIonCode>();
}
IonCode *preBarrier(JSContext *cx) {
if (!preBarrier_) {
preBarrier_ = generatePreBarrier(cx);
if (!preBarrier_)
return NULL;
}
return preBarrier_;
}
AutoFlushCache *flusher() {
return flusher_;
}

View File

@ -652,8 +652,11 @@ MarkIonActivation(JSTracer *trc, const IonActivationIterator &activations)
JS_NOT_REACHED("invalid");
break;
case IonFrame_Rectifier:
case IonFrame_Bailed_Rectifier:
case IonFrame_Bailed_Rectifier: {
IonCompartment *ionCompartment = activations.activation()->compartment()->ionCompartment();
MarkIonCodeRoot(trc, ionCompartment->getArgumentsRectifierAddr(), "Arguments Rectifier");
break;
}
case IonFrame_Osr:
// The callee token will be marked by the callee JS frame;
// otherwise, it does not need to be marked, since the frame is

View File

@ -208,9 +208,8 @@ class FrameSizeClass
return FrameSizeClass(class_);
}
// These functions are implemented in specific CodeGenerator-* files.
// These two functions are implemented in specific CodeGenerator-* files.
static FrameSizeClass FromDepth(uint32 frameDepth);
static FrameSizeClass ClassLimit();
uint32 frameSize() const;
uint32 classId() const {

View File

@ -367,15 +367,18 @@ class MacroAssembler : public MacroAssemblerSpecific
JS_ASSERT(type == MIRType_Value || type == MIRType_String || type == MIRType_Object);
Label done;
JSContext *cx = GetIonContext()->cx;
IonCode *preBarrier = cx->compartment->ionCompartment()->preBarrier(cx);
if (!preBarrier) {
enoughMemory_ = false;
return;
}
if (type == MIRType_Value)
branchTestGCThing(Assembler::NotEqual, address, &done);
Push(PreBarrierReg);
computeEffectiveAddress(address, PreBarrierReg);
JSCompartment *compartment = GetIonContext()->compartment;
IonCode *preBarrier = compartment->ionCompartment()->preBarrier();
call(preBarrier);
Pop(PreBarrierReg);

View File

@ -21,22 +21,6 @@ using namespace js::ion;
namespace js {
namespace ion {
// Don't explicitly initialize, it's not guaranteed that this initializer will
// run before the constructors for static VMFunctions.
/* static */ VMFunction *VMFunction::functions;
void
VMFunction::addToFunctions()
{
static bool initialized = false;
if (!initialized) {
initialized = true;
functions = NULL;
}
this->next = functions;
functions = this;
}
static inline bool
ShouldMonitorReturnType(JSFunction *fun)
{

View File

@ -34,10 +34,6 @@ enum DataType {
// argument, and are treated as re-entrant into the VM and therefore fallible.
struct VMFunction
{
// Global linked list of all VMFunctions.
static VMFunction *functions;
VMFunction *next;
// Address of the C function.
void *wrapped;
@ -172,16 +168,6 @@ struct VMFunction
JS_ASSERT_IF(outParam != Type_Void, returnType == Type_Bool);
JS_ASSERT(returnType == Type_Bool || returnType == Type_Object);
}
VMFunction(const VMFunction &o)
{
*this = o;
addToFunctions();
}
private:
// Add this to the global list of VMFunctions.
void addToFunctions();
};
template <class> struct TypeToDataType { /* Unexpected return type for a VMFunction. */ };

View File

@ -176,9 +176,11 @@ CodeGeneratorARM::generateOutOfLineCode()
// Push the frame size, so the handler can recover the IonScript.
masm.ma_mov(Imm32(frameSize()), lr);
IonCompartment *ion = GetIonContext()->compartment->ionCompartment();
IonCode *handler = ion->getGenericBailoutHandler();
JSContext *cx = GetIonContext()->cx;
IonCompartment *ion = cx->compartment->ionCompartment();
IonCode *handler = ion->getGenericBailoutHandler(cx);
if (!handler)
return false;
masm.branch(handler);
}
@ -980,7 +982,11 @@ CodeGeneratorARM::visitTruncateDToInt32(LTruncateDToInt32 *ins)
return emitTruncateDouble(ToFloatRegister(ins->input()), ToRegister(ins->output()));
}
static const uint32 FrameSizes[] = { 128, 256, 512, 1024 };
// The first two size classes are 128 and 256 bytes respectively. After that we
// increment by 512.
static const uint32 LAST_FRAME_SIZE = 512;
static const uint32 LAST_FRAME_INCREMENT = 512;
static const uint32 FrameSizes[] = { 128, 256, LAST_FRAME_SIZE };
FrameSizeClass
FrameSizeClass::FromDepth(uint32 frameDepth)
@ -990,22 +996,21 @@ FrameSizeClass::FromDepth(uint32 frameDepth)
return FrameSizeClass(i);
}
return FrameSizeClass::None();
}
uint32 newFrameSize = frameDepth - LAST_FRAME_SIZE;
uint32 sizeClass = (newFrameSize / LAST_FRAME_INCREMENT) + 1;
FrameSizeClass
FrameSizeClass::ClassLimit()
{
return FrameSizeClass(JS_ARRAY_LENGTH(FrameSizes));
return FrameSizeClass(JS_ARRAY_LENGTH(FrameSizes) + sizeClass);
}
uint32
FrameSizeClass::frameSize() const
{
JS_ASSERT(class_ != NO_FRAME_SIZE_CLASS_ID);
JS_ASSERT(class_ < JS_ARRAY_LENGTH(FrameSizes));
return FrameSizes[class_];
if (class_ < JS_ARRAY_LENGTH(FrameSizes))
return FrameSizes[class_];
uint32 step = class_ - JS_ARRAY_LENGTH(FrameSizes);
return LAST_FRAME_SIZE + step * LAST_FRAME_INCREMENT;
}
ValueOperand
@ -1455,13 +1460,13 @@ CodeGeneratorARM::visitRecompileCheck(LRecompileCheck *lir)
return true;
}
typedef bool (*InterruptCheckFn)(JSContext *);
static const VMFunction InterruptCheckInfo = FunctionInfo<InterruptCheckFn>(InterruptCheck);
bool
CodeGeneratorARM::visitInterruptCheck(LInterruptCheck *lir)
{
OutOfLineCode *ool = oolCallVM(InterruptCheckInfo, lir, (ArgList()), StoreNothing());
typedef bool (*pf)(JSContext *);
static const VMFunction interruptCheckInfo = FunctionInfo<pf>(InterruptCheck);
OutOfLineCode *ool = oolCallVM(interruptCheckInfo, lir, (ArgList()), StoreNothing());
if (!ool)
return false;
@ -1487,9 +1492,13 @@ CodeGeneratorARM::generateInvalidateEpilogue()
// Push the return address of the point that we bailed out at onto the stack
masm.Push(lr);
JSContext *cx = GetIonContext()->cx;
// Push the Ion script onto the stack (when we determine what that pointer is).
invalidateEpilogueData_ = masm.pushWithPatch(ImmWord(uintptr_t(-1)));
IonCode *thunk = GetIonContext()->compartment->ionCompartment()->getInvalidationThunk();
IonCode *thunk = cx->compartment->ionCompartment()->getOrCreateInvalidationThunk(cx);
if (!thunk)
return false;
masm.branch(thunk);

View File

@ -70,7 +70,7 @@ struct EnterJITStack
* ...using standard EABI calling convention
*/
IonCode *
IonRuntime::generateEnterJIT(JSContext *cx)
IonCompartment::generateEnterJIT(JSContext *cx)
{
AutoFlushCache afc("GenerateEnterJIT", cx->compartment->ionCompartment());
@ -199,9 +199,22 @@ IonRuntime::generateEnterJIT(JSContext *cx)
}
IonCode *
IonRuntime::generateInvalidator(JSContext *cx)
IonCompartment::generateReturnError(JSContext *cx)
{
// See large comment in x86's IonRuntime::generateInvalidator.
MacroAssembler masm(cx);
// This is where the stack size is stored on x86. where is it stored here?
masm.ma_pop(r0);
masm.ma_add(r0, sp, sp);
GenerateReturn(masm, JS_FALSE);
Linker linker(masm);
return linker.newCode(cx);
}
IonCode *
IonCompartment::generateInvalidator(JSContext *cx)
{
// See large comment in x86's IonCompartment::generateInvalidator.
AutoIonContextAlloc aica(cx);
MacroAssembler masm(cx);
//masm.as_bkpt();
@ -248,7 +261,7 @@ IonRuntime::generateInvalidator(JSContext *cx)
}
IonCode *
IonRuntime::generateArgumentsRectifier(JSContext *cx)
IonCompartment::generateArgumentsRectifier(JSContext *cx)
{
MacroAssembler masm(cx);
// ArgumentsRectifierReg contains the |nargs| pushed onto the current frame.
@ -435,7 +448,7 @@ GenerateBailoutThunk(MacroAssembler &masm, uint32 frameClass)
}
IonCode *
IonRuntime::generateBailoutTable(JSContext *cx, uint32 frameClass)
IonCompartment::generateBailoutTable(JSContext *cx, uint32 frameClass)
{
MacroAssembler masm;
@ -451,7 +464,7 @@ IonRuntime::generateBailoutTable(JSContext *cx, uint32 frameClass)
}
IonCode *
IonRuntime::generateBailoutHandler(JSContext *cx)
IonCompartment::generateBailoutHandler(JSContext *cx)
{
MacroAssembler masm;
GenerateBailoutThunk(masm, NO_FRAME_SIZE_CLASS_ID);
@ -461,7 +474,7 @@ IonRuntime::generateBailoutHandler(JSContext *cx)
}
IonCode *
IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
IonCompartment::generateVMWrapper(JSContext *cx, const VMFunction &f)
{
typedef MoveResolver::MoveOperand MoveOperand;
@ -611,7 +624,7 @@ IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
}
IonCode *
IonRuntime::generatePreBarrier(JSContext *cx)
IonCompartment::generatePreBarrier(JSContext *cx)
{
MacroAssembler masm;

View File

@ -216,8 +216,7 @@ CodeGeneratorShared::encode(LSnapshot *snapshot)
DebugOnly<jsbytecode *> bailPC = pc;
if (mir->mode() == MResumePoint::ResumeAfter)
bailPC = GetNextPc(pc);
JS_ASSERT_IF(GetIonContext()->cx,
exprStack == js_ReconstructStackDepth(GetIonContext()->cx, script, bailPC));
JS_ASSERT(exprStack == js_ReconstructStackDepth(GetIonContext()->cx, script, bailPC));
#ifdef TRACK_SNAPSHOTS
LInstruction *ins = instruction();
@ -372,9 +371,10 @@ CodeGeneratorShared::callVM(const VMFunction &fun, LInstruction *ins, const Regi
pushedArgs_ = 0;
#endif
// Get the wrapper of the VM function.
IonCompartment *ion = GetIonContext()->compartment->ionCompartment();
IonCode *wrapper = ion->getVMWrapper(fun);
// Generate the wrapper of the VM function.
JSContext *cx = GetIonContext()->cx;
IonCompartment *ion = cx->compartment->ionCompartment();
IonCode *wrapper = ion->generateVMWrapper(cx, fun);
if (!wrapper)
return false;

View File

@ -293,8 +293,11 @@ CodeGeneratorX86Shared::generateOutOfLineCode()
// Push the frame size, so the handler can recover the IonScript.
masm.push(Imm32(frameSize()));
IonCompartment *ion = GetIonContext()->compartment->ionCompartment();
IonCode *handler = ion->getGenericBailoutHandler();
JSContext *cx = GetIonContext()->cx;
IonCompartment *ion = cx->compartment->ionCompartment();
IonCode *handler = ion->getGenericBailoutHandler(cx);
if (!handler)
return false;
masm.jmp(handler->raw(), Relocation::IONCODE);
}
@ -1311,9 +1314,13 @@ CodeGeneratorX86Shared::generateInvalidateEpilogue()
masm.bind(&invalidate_);
JSContext *cx = GetIonContext()->cx;
// Push the Ion script onto the stack (when we determine what that pointer is).
invalidateEpilogueData_ = masm.pushWithPatch(ImmWord(uintptr_t(-1)));
IonCode *thunk = GetIonContext()->compartment->ionCompartment()->getInvalidationThunk();
IonCode *thunk = cx->compartment->ionCompartment()->getOrCreateInvalidationThunk(cx);
if (!thunk)
return false;
masm.call(thunk);

View File

@ -47,12 +47,6 @@ FrameSizeClass::FromDepth(uint32 frameDepth)
return FrameSizeClass::None();
}
FrameSizeClass
FrameSizeClass::ClassLimit()
{
return FrameSizeClass(0);
}
uint32
FrameSizeClass::frameSize() const
{
@ -293,13 +287,13 @@ CodeGeneratorX64::visitRecompileCheck(LRecompileCheck *lir)
return true;
}
typedef bool (*InterruptCheckFn)(JSContext *);
static const VMFunction InterruptCheckInfo = FunctionInfo<InterruptCheckFn>(InterruptCheck);
bool
CodeGeneratorX64::visitInterruptCheck(LInterruptCheck *lir)
{
OutOfLineCode *ool = oolCallVM(InterruptCheckInfo, lir, (ArgList()), StoreNothing());
typedef bool (*pf)(JSContext *);
static const VMFunction interruptCheckInfo = FunctionInfo<pf>(InterruptCheck);
OutOfLineCode *ool = oolCallVM(interruptCheckInfo, lir, (ArgList()), StoreNothing());
if (!ool)
return false;

View File

@ -864,7 +864,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
// Save an exit frame (which must be aligned to the stack pointer) to
// ThreadData::ionTop.
void linkExitFrame() {
mov(ImmWord(GetIonContext()->compartment->rt), ScratchReg);
mov(ImmWord(GetIonContext()->cx->runtime), ScratchReg);
mov(StackPointer, Operand(ScratchReg, offsetof(JSRuntime, ionTop)));
}

View File

@ -25,7 +25,7 @@ using namespace js::ion;
* ...using standard x64 fastcall calling convention
*/
IonCode *
IonRuntime::generateEnterJIT(JSContext *cx)
IonCompartment::generateEnterJIT(JSContext *cx)
{
MacroAssembler masm(cx);
@ -180,12 +180,26 @@ IonRuntime::generateEnterJIT(JSContext *cx)
}
IonCode *
IonRuntime::generateInvalidator(JSContext *cx)
IonCompartment::generateReturnError(JSContext *cx)
{
MacroAssembler masm(cx);
masm.pop(r14); // sizeDescriptor.
masm.xorl(Imm32(0x1), r14); // Unmark EntryFrame.
masm.addq(r14, rsp); // Remove arguments.
masm.pop(r11); // Discard |vp|: returning from error.
Linker linker(masm);
return linker.newCode(cx);
}
IonCode *
IonCompartment::generateInvalidator(JSContext *cx)
{
AutoIonContextAlloc aica(cx);
MacroAssembler masm(cx);
// See explanatory comment in x86's IonRuntime::generateInvalidator.
// See explanatory comment in x86's IonCompartment::generateInvalidator.
masm.addq(Imm32(sizeof(uintptr_t)), rsp);
@ -222,7 +236,7 @@ IonRuntime::generateInvalidator(JSContext *cx)
}
IonCode *
IonRuntime::generateArgumentsRectifier(JSContext *cx)
IonCompartment::generateArgumentsRectifier(JSContext *cx)
{
// Do not erase the frame pointer in this function.
@ -345,14 +359,14 @@ GenerateBailoutThunk(JSContext *cx, MacroAssembler &masm, uint32 frameClass)
}
IonCode *
IonRuntime::generateBailoutTable(JSContext *cx, uint32 frameClass)
IonCompartment::generateBailoutTable(JSContext *cx, uint32 frameClass)
{
JS_NOT_REACHED("x64 does not use bailout tables");
return NULL;
}
IonCode *
IonRuntime::generateBailoutHandler(JSContext *cx)
IonCompartment::generateBailoutHandler(JSContext *cx)
{
MacroAssembler masm;
@ -363,7 +377,7 @@ IonRuntime::generateBailoutHandler(JSContext *cx)
}
IonCode *
IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
IonCompartment::generateVMWrapper(JSContext *cx, const VMFunction &f)
{
typedef MoveResolver::MoveOperand MoveOperand;
@ -517,7 +531,7 @@ IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
}
IonCode *
IonRuntime::generatePreBarrier(JSContext *cx)
IonCompartment::generatePreBarrier(JSContext *cx)
{
MacroAssembler masm;

View File

@ -21,7 +21,11 @@ CodeGeneratorX86::CodeGeneratorX86(MIRGenerator *gen, LIRGraph &graph)
{
}
static const uint32 FrameSizes[] = { 128, 256, 512, 1024 };
// The first two size classes are 128 and 256 bytes respectively. After that we
// increment by 512.
static const uint32 LAST_FRAME_SIZE = 512;
static const uint32 LAST_FRAME_INCREMENT = 512;
static const uint32 FrameSizes[] = { 128, 256, LAST_FRAME_SIZE };
FrameSizeClass
FrameSizeClass::FromDepth(uint32 frameDepth)
@ -31,22 +35,21 @@ FrameSizeClass::FromDepth(uint32 frameDepth)
return FrameSizeClass(i);
}
return FrameSizeClass::None();
}
uint32 newFrameSize = frameDepth - LAST_FRAME_SIZE;
uint32 sizeClass = (newFrameSize / LAST_FRAME_INCREMENT) + 1;
FrameSizeClass
FrameSizeClass::ClassLimit()
{
return FrameSizeClass(JS_ARRAY_LENGTH(FrameSizes));
return FrameSizeClass(JS_ARRAY_LENGTH(FrameSizes) + sizeClass);
}
uint32
FrameSizeClass::frameSize() const
{
JS_ASSERT(class_ != NO_FRAME_SIZE_CLASS_ID);
JS_ASSERT(class_ < JS_ARRAY_LENGTH(FrameSizes));
return FrameSizes[class_];
if (class_ < JS_ARRAY_LENGTH(FrameSizes))
return FrameSizes[class_];
uint32 step = class_ - JS_ARRAY_LENGTH(FrameSizes);
return LAST_FRAME_SIZE + step * LAST_FRAME_INCREMENT;
}
ValueOperand
@ -285,13 +288,13 @@ CodeGeneratorX86::visitRecompileCheck(LRecompileCheck *lir)
return true;
}
typedef bool (*InterruptCheckFn)(JSContext *);
static const VMFunction InterruptCheckInfo = FunctionInfo<InterruptCheckFn>(InterruptCheck);
bool
CodeGeneratorX86::visitInterruptCheck(LInterruptCheck *lir)
{
OutOfLineCode *ool = oolCallVM(InterruptCheckInfo, lir, (ArgList()), StoreNothing());
typedef bool (*pf)(JSContext *);
static const VMFunction interruptCheckInfo = FunctionInfo<pf>(InterruptCheck);
OutOfLineCode *ool = oolCallVM(interruptCheckInfo, lir, (ArgList()), StoreNothing());
if (!ool)
return false;

View File

@ -33,7 +33,7 @@ enum EnterJitEbpArgumentOffset {
* using the standard cdecl calling convention.
*/
IonCode *
IonRuntime::generateEnterJIT(JSContext *cx)
IonCompartment::generateEnterJIT(JSContext *cx)
{
MacroAssembler masm(cx);
@ -161,7 +161,7 @@ IonRuntime::generateEnterJIT(JSContext *cx)
}
IonCode *
IonRuntime::generateInvalidator(JSContext *cx)
IonCompartment::generateInvalidator(JSContext *cx)
{
AutoIonContextAlloc aica(cx);
MacroAssembler masm(cx);
@ -211,7 +211,7 @@ IonRuntime::generateInvalidator(JSContext *cx)
}
IonCode *
IonRuntime::generateArgumentsRectifier(JSContext *cx)
IonCompartment::generateArgumentsRectifier(JSContext *cx)
{
MacroAssembler masm(cx);
@ -357,7 +357,7 @@ GenerateBailoutThunk(JSContext *cx, MacroAssembler &masm, uint32 frameClass)
}
IonCode *
IonRuntime::generateBailoutTable(JSContext *cx, uint32 frameClass)
IonCompartment::generateBailoutTable(JSContext *cx, uint32 frameClass)
{
MacroAssembler masm;
@ -373,7 +373,7 @@ IonRuntime::generateBailoutTable(JSContext *cx, uint32 frameClass)
}
IonCode *
IonRuntime::generateBailoutHandler(JSContext *cx)
IonCompartment::generateBailoutHandler(JSContext *cx)
{
MacroAssembler masm;
@ -384,7 +384,7 @@ IonRuntime::generateBailoutHandler(JSContext *cx)
}
IonCode *
IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
IonCompartment::generateVMWrapper(JSContext *cx, const VMFunction &f)
{
AssertCanGC();
typedef MoveResolver::MoveOperand MoveOperand;
@ -544,7 +544,7 @@ IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
}
IonCode *
IonRuntime::generatePreBarrier(JSContext *cx)
IonCompartment::generatePreBarrier(JSContext *cx)
{
MacroAssembler masm;

View File

@ -684,26 +684,20 @@ mozilla::ThreadLocal<JSRuntime *> TlsRuntime;
JS_FRIEND_API(void)
EnterAssertNoGCScope()
{
JSRuntime *rt = TlsRuntime.get();
if (rt)
++rt->gcAssertNoGCDepth;
++TlsRuntime.get()->gcAssertNoGCDepth;
}
JS_FRIEND_API(void)
LeaveAssertNoGCScope()
{
JSRuntime *rt = TlsRuntime.get();
if (rt) {
--rt->gcAssertNoGCDepth;
JS_ASSERT(rt->gcAssertNoGCDepth >= 0);
}
--TlsRuntime.get()->gcAssertNoGCDepth;
JS_ASSERT(TlsRuntime.get()->gcAssertNoGCDepth >= 0);
}
JS_FRIEND_API(bool)
InNoGCScope()
{
JSRuntime *rt = TlsRuntime.get();
return !rt || rt->gcAssertNoGCDepth > 0;
return TlsRuntime.get()->gcAssertNoGCDepth > 0;
}
JS_FRIEND_API(bool)

View File

@ -92,7 +92,6 @@ class JaegerRuntime;
class MathCache;
namespace ion {
class IonRuntime;
class IonActivation;
}
@ -439,14 +438,12 @@ struct JSRuntime : js::RuntimeFriendFields
#ifdef JS_METHODJIT
js::mjit::JaegerRuntime *jaegerRuntime_;
#endif
js::ion::IonRuntime *ionRuntime_;
JSObject *selfHostedGlobal_;
JSC::ExecutableAllocator *createExecutableAllocator(JSContext *cx);
WTF::BumpPointerAllocator *createBumpPointerAllocator(JSContext *cx);
js::mjit::JaegerRuntime *createJaegerRuntime(JSContext *cx);
js::ion::IonRuntime *createIonRuntime(JSContext *cx);
public:
JSC::ExecutableAllocator *getExecAlloc(JSContext *cx) {
@ -471,9 +468,6 @@ struct JSRuntime : js::RuntimeFriendFields
return *jaegerRuntime_;
}
#endif
js::ion::IonRuntime *getIonRuntime(JSContext *cx) {
return ionRuntime_ ? ionRuntime_ : createIonRuntime(cx);
}
bool initSelfHosting(JSContext *cx);
void markSelfHostedGlobal(JSTracer *trc);

View File

@ -149,29 +149,6 @@ JSCompartment::setNeedsBarrier(bool needs)
}
#ifdef JS_ION
ion::IonRuntime *
JSRuntime::createIonRuntime(JSContext *cx)
{
ionRuntime_ = cx->new_<ion::IonRuntime>();
if (!ionRuntime_)
return NULL;
if (!ionRuntime_->initialize(cx)) {
js_delete(ionRuntime_);
ionRuntime_ = NULL;
if (cx->runtime->atomsCompartment->ionCompartment_) {
js_delete(cx->runtime->atomsCompartment->ionCompartment_);
cx->runtime->atomsCompartment->ionCompartment_ = NULL;
}
return NULL;
}
return ionRuntime_;
}
bool
JSCompartment::ensureIonCompartmentExists(JSContext *cx)
{
@ -179,15 +156,15 @@ JSCompartment::ensureIonCompartmentExists(JSContext *cx)
if (ionCompartment_)
return true;
IonRuntime *ionRuntime = cx->runtime->getIonRuntime(cx);
if (!ionRuntime)
return false;
/* Set the compartment early, so linking works. */
ionCompartment_ = cx->new_<IonCompartment>(ionRuntime);
ionCompartment_ = cx->new_<IonCompartment>();
if (!ionCompartment_)
if (!ionCompartment_ || !ionCompartment_->initialize(cx)) {
if (ionCompartment_)
delete ionCompartment_;
ionCompartment_ = NULL;
return false;
}
return true;
}

View File

@ -121,7 +121,6 @@ struct JSCompartment
JSPrincipals *principals;
private:
friend struct JSRuntime;
friend struct JSContext;
js::GlobalObject *global_;
public:

View File

@ -3895,14 +3895,6 @@ BeginSweepPhase(JSRuntime *rt)
}
#ifdef JS_ION
for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
/*
* Don't sweep IonCode objects from the atoms compartment. These are
* stubs and wrappers allocated when the IonRuntime is created and
* must persist until the runtime is destroyed.
*/
if (c == rt->atomsCompartment)
continue;
if (c->isGCSweeping()) {
gcstats::AutoSCC scc(rt->gcStats, partition.getSCC(c));
c->arenas.queueIonCodeForSweep(&fop);

View File

@ -437,9 +437,7 @@ NewGCThing(JSContext *cx, js::gc::AllocKind kind, size_t thingSize)
AssertCanGC();
JS_ASSERT(thingSize == js::gc::Arena::thingSize(kind));
JS_ASSERT_IF(cx->compartment == cx->runtime->atomsCompartment,
kind == FINALIZE_STRING ||
kind == FINALIZE_SHORT_STRING ||
kind == FINALIZE_IONCODE);
kind == js::gc::FINALIZE_STRING || kind == js::gc::FINALIZE_SHORT_STRING);
JS_ASSERT(!cx->runtime->isHeapBusy());
JS_ASSERT(!cx->runtime->noGCOrAllocationCheck);

View File

@ -17,7 +17,8 @@ using namespace js;
bool
js::OffThreadCompilationAvailable(JSContext *cx)
{
return cx->runtime->useHelperThreads();
WorkerThreadState &state = *cx->runtime->workerThreadState;
return state.numThreads > 0;
}
bool
@ -73,8 +74,6 @@ CompiledScriptMatches(JSCompartment *compartment, JSScript *script, JSScript *ta
void
js::CancelOffThreadIonCompile(JSCompartment *compartment, JSScript *script)
{
AutoAssertNoGC nogc;
if (!compartment->rt->workerThreadState)
return;