зеркало из https://github.com/mozilla/gecko-dev.git
Bug 785905 - Build Ion MIR graph off thread, r=jandem.
This commit is contained in:
Родитель
d3040f3cad
Коммит
03fbbbdef7
|
@ -2804,7 +2804,13 @@ frontend::EmitFunctionScript(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNo
|
|||
/* Initialize fun->script() so that the debugger has a valid fun->script(). */
|
||||
RootedFunction fun(cx, bce->script->function());
|
||||
JS_ASSERT(fun->isInterpreted());
|
||||
fun->setScript(bce->script);
|
||||
|
||||
if (fun->isInterpretedLazy()) {
|
||||
AutoLockForCompilation lock(cx);
|
||||
fun->setUnlazifiedScript(bce->script);
|
||||
} else {
|
||||
fun->setScript(bce->script);
|
||||
}
|
||||
|
||||
bce->tellDebuggerAboutCompiledScript(cx);
|
||||
|
||||
|
|
|
@ -1129,23 +1129,17 @@ ScanTypeObject(GCMarker *gcmarker, types::TypeObject *type)
|
|||
PushMarkStack(gcmarker, JSID_TO_STRING(prop->id));
|
||||
}
|
||||
|
||||
if (TaggedProto(type->proto).isObject())
|
||||
PushMarkStack(gcmarker, type->proto);
|
||||
if (type->proto().isObject())
|
||||
PushMarkStack(gcmarker, type->proto().toObject());
|
||||
|
||||
if (type->singleton && !type->lazy())
|
||||
PushMarkStack(gcmarker, type->singleton);
|
||||
|
||||
if (type->addendum) {
|
||||
switch (type->addendum->kind) {
|
||||
case types::TypeObjectAddendum::NewScript:
|
||||
PushMarkStack(gcmarker, type->newScript()->fun);
|
||||
PushMarkStack(gcmarker, type->newScript()->templateObject);
|
||||
break;
|
||||
|
||||
case types::TypeObjectAddendum::TypedObject:
|
||||
PushMarkStack(gcmarker, type->typedObject()->typeRepr->ownerObject());
|
||||
break;
|
||||
}
|
||||
if (type->hasNewScript()) {
|
||||
PushMarkStack(gcmarker, type->newScript()->fun);
|
||||
PushMarkStack(gcmarker, type->newScript()->templateObject);
|
||||
} else if (type->hasTypedObject()) {
|
||||
PushMarkStack(gcmarker, type->typedObject()->typeRepr->ownerObject());
|
||||
}
|
||||
|
||||
if (type->interpretedFunction)
|
||||
|
@ -1162,23 +1156,17 @@ gc::MarkChildren(JSTracer *trc, types::TypeObject *type)
|
|||
MarkId(trc, &prop->id, "type_prop");
|
||||
}
|
||||
|
||||
if (TaggedProto(type->proto).isObject())
|
||||
MarkObject(trc, &type->proto, "type_proto");
|
||||
if (type->proto().isObject())
|
||||
MarkObject(trc, &type->protoRaw(), "type_proto");
|
||||
|
||||
if (type->singleton && !type->lazy())
|
||||
MarkObject(trc, &type->singleton, "type_singleton");
|
||||
|
||||
if (type->addendum) {
|
||||
switch (type->addendum->kind) {
|
||||
case types::TypeObjectAddendum::NewScript:
|
||||
MarkObject(trc, &type->newScript()->fun, "type_new_function");
|
||||
MarkObject(trc, &type->newScript()->templateObject, "type_new_template");
|
||||
break;
|
||||
|
||||
case types::TypeObjectAddendum::TypedObject:
|
||||
type->typedObject()->typeRepr->mark(trc);
|
||||
break;
|
||||
}
|
||||
if (type->hasNewScript()) {
|
||||
MarkObject(trc, &type->newScript()->fun, "type_new_function");
|
||||
MarkObject(trc, &type->newScript()->templateObject, "type_new_template");
|
||||
} else if (type->hasTypedObject()) {
|
||||
type->typedObject()->typeRepr->mark(trc);
|
||||
}
|
||||
|
||||
if (type->interpretedFunction)
|
||||
|
@ -1441,7 +1429,7 @@ GCMarker::processMarkStackTop(SliceBudget &budget)
|
|||
PushMarkStack(this, shape);
|
||||
|
||||
/* Call the trace hook if necessary. */
|
||||
const Class *clasp = type->clasp;
|
||||
const Class *clasp = type->clasp();
|
||||
if (clasp->trace) {
|
||||
JS_ASSERT_IF(runtime->gcMode() == JSGC_MODE_INCREMENTAL &&
|
||||
runtime->gcIncrementalEnabled,
|
||||
|
|
|
@ -47,7 +47,7 @@ MarkExactStackRoot(JSTracer *trc, Rooted<void*> *rooter, ThingRootKind kind)
|
|||
if (IsNullTaggedPointer(*addr))
|
||||
return;
|
||||
|
||||
if (kind == THING_ROOT_OBJECT && *addr == Proxy::LazyProto)
|
||||
if (kind == THING_ROOT_OBJECT && *addr == TaggedProto::LazyProto)
|
||||
return;
|
||||
|
||||
switch (kind) {
|
||||
|
|
|
@ -186,10 +186,8 @@ BaselineCompiler::compile()
|
|||
baselineScript->setMethod(code);
|
||||
baselineScript->setTemplateScope(templateScope);
|
||||
|
||||
script->setBaselineScript(baselineScript);
|
||||
|
||||
IonSpew(IonSpew_BaselineScripts, "Created BaselineScript %p (raw %p) for %s:%d",
|
||||
(void *) script->baselineScript(), (void *) code->raw(),
|
||||
(void *) baselineScript, (void *) code->raw(),
|
||||
script->filename(), script->lineno());
|
||||
|
||||
#ifdef JS_ION_PERF
|
||||
|
@ -254,6 +252,8 @@ BaselineCompiler::compile()
|
|||
if (script->compartment()->debugMode())
|
||||
baselineScript->setDebugMode();
|
||||
|
||||
script->setBaselineScript(cx, baselineScript);
|
||||
|
||||
return Method_Compiled;
|
||||
}
|
||||
|
||||
|
|
|
@ -130,12 +130,16 @@ ICStubIterator::operator++()
|
|||
}
|
||||
|
||||
void
|
||||
ICStubIterator::unlink(Zone *zone)
|
||||
ICStubIterator::unlink(JSContext *cx)
|
||||
{
|
||||
JS_ASSERT(currentStub_->next() != nullptr);
|
||||
JS_ASSERT(currentStub_ != fallbackStub_);
|
||||
JS_ASSERT(!unlinked_);
|
||||
fallbackStub_->unlinkStub(zone, previousStub_, currentStub_);
|
||||
|
||||
{
|
||||
AutoLockForCompilation lock(cx);
|
||||
fallbackStub_->unlinkStub(cx->zone(), previousStub_, currentStub_);
|
||||
}
|
||||
|
||||
// Mark the current iterator position as unlinked, so operator++ works properly.
|
||||
unlinked_ = true;
|
||||
|
@ -485,7 +489,7 @@ ICFallbackStub::unlinkStubsWithKind(JSContext *cx, ICStub::Kind kind)
|
|||
{
|
||||
for (ICStubIterator iter = beginChain(); !iter.atEnd(); iter++) {
|
||||
if (iter->kind() == kind)
|
||||
iter.unlink(cx->zone());
|
||||
iter.unlink(cx);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1061,7 +1065,7 @@ DoProfilerFallback(JSContext *cx, BaselineFrame *frame, ICProfiler_Fallback *stu
|
|||
ICStub *optStub = compiler.getStub(compiler.getStubSpace(script));
|
||||
if (!optStub)
|
||||
return false;
|
||||
stub->addNewStub(optStub);
|
||||
stub->addNewStub(cx, optStub);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1146,8 +1150,10 @@ ICTypeMonitor_Fallback::addMonitorStubForValue(JSContext *cx, HandleScript scrip
|
|||
ICTypeMonitor_PrimitiveSet::Compiler compiler(cx, existingStub, type);
|
||||
ICStub *stub = existingStub ? compiler.updateStub()
|
||||
: compiler.getStub(compiler.getStubSpace(script));
|
||||
if (!stub)
|
||||
if (!stub) {
|
||||
js_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
IonSpew(IonSpew_BaselineIC, " %s TypeMonitor stub %p for primitive type %d",
|
||||
existingStub ? "Modified existing" : "Created new", stub, type);
|
||||
|
@ -1171,8 +1177,10 @@ ICTypeMonitor_Fallback::addMonitorStubForValue(JSContext *cx, HandleScript scrip
|
|||
|
||||
ICTypeMonitor_SingleObject::Compiler compiler(cx, obj);
|
||||
ICStub *stub = compiler.getStub(compiler.getStubSpace(script));
|
||||
if (!stub)
|
||||
if (!stub) {
|
||||
js_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
IonSpew(IonSpew_BaselineIC, " Added TypeMonitor stub %p for singleton %p",
|
||||
stub, obj.get());
|
||||
|
@ -1193,8 +1201,10 @@ ICTypeMonitor_Fallback::addMonitorStubForValue(JSContext *cx, HandleScript scrip
|
|||
|
||||
ICTypeMonitor_TypeObject::Compiler compiler(cx, type);
|
||||
ICStub *stub = compiler.getStub(compiler.getStubSpace(script));
|
||||
if (!stub)
|
||||
if (!stub) {
|
||||
js_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
IonSpew(IonSpew_BaselineIC, " Added TypeMonitor stub %p for TypeObject %p",
|
||||
stub, type.get());
|
||||
|
@ -1785,7 +1795,7 @@ DoCompareFallback(JSContext *cx, BaselineFrame *frame, ICCompare_Fallback *stub,
|
|||
if (!int32Stub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(int32Stub);
|
||||
stub->addNewStub(cx, int32Stub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1803,7 +1813,7 @@ DoCompareFallback(JSContext *cx, BaselineFrame *frame, ICCompare_Fallback *stub,
|
|||
if (!doubleStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(doubleStub);
|
||||
stub->addNewStub(cx, doubleStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1818,7 +1828,7 @@ DoCompareFallback(JSContext *cx, BaselineFrame *frame, ICCompare_Fallback *stub,
|
|||
if (!doubleStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(doubleStub);
|
||||
stub->addNewStub(cx, doubleStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1829,7 +1839,7 @@ DoCompareFallback(JSContext *cx, BaselineFrame *frame, ICCompare_Fallback *stub,
|
|||
if (!booleanStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(booleanStub);
|
||||
stub->addNewStub(cx, booleanStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1842,7 +1852,7 @@ DoCompareFallback(JSContext *cx, BaselineFrame *frame, ICCompare_Fallback *stub,
|
|||
if (!optStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(optStub);
|
||||
stub->addNewStub(cx, optStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1854,7 +1864,7 @@ DoCompareFallback(JSContext *cx, BaselineFrame *frame, ICCompare_Fallback *stub,
|
|||
if (!stringStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(stringStub);
|
||||
stub->addNewStub(cx, stringStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1866,7 +1876,7 @@ DoCompareFallback(JSContext *cx, BaselineFrame *frame, ICCompare_Fallback *stub,
|
|||
if (!objectStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(objectStub);
|
||||
stub->addNewStub(cx, objectStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1884,7 +1894,7 @@ DoCompareFallback(JSContext *cx, BaselineFrame *frame, ICCompare_Fallback *stub,
|
|||
if (!objectStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(objectStub);
|
||||
stub->addNewStub(cx, objectStub);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -2090,7 +2100,7 @@ ICCompare_ObjectWithUndefined::Compiler::generateStubCode(MacroAssembler &masm)
|
|||
Label emulatesUndefined;
|
||||
Register obj = masm.extractObject(objectOperand, ExtractTemp0);
|
||||
masm.loadPtr(Address(obj, JSObject::offsetOfType()), obj);
|
||||
masm.loadPtr(Address(obj, offsetof(types::TypeObject, clasp)), obj);
|
||||
masm.loadPtr(Address(obj, types::TypeObject::offsetOfClasp()), obj);
|
||||
masm.branchTest32(Assembler::NonZero,
|
||||
Address(obj, Class::offsetOfFlags()),
|
||||
Imm32(JSCLASS_EMULATES_UNDEFINED),
|
||||
|
@ -2196,7 +2206,7 @@ DoToBoolFallback(JSContext *cx, BaselineFrame *frame, ICToBool_Fallback *stub, H
|
|||
if (!int32Stub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(int32Stub);
|
||||
stub->addNewStub(cx, int32Stub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2207,7 +2217,7 @@ DoToBoolFallback(JSContext *cx, BaselineFrame *frame, ICToBool_Fallback *stub, H
|
|||
if (!doubleStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(doubleStub);
|
||||
stub->addNewStub(cx, doubleStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2218,7 +2228,7 @@ DoToBoolFallback(JSContext *cx, BaselineFrame *frame, ICToBool_Fallback *stub, H
|
|||
if (!stringStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(stringStub);
|
||||
stub->addNewStub(cx, stringStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2228,7 +2238,7 @@ DoToBoolFallback(JSContext *cx, BaselineFrame *frame, ICToBool_Fallback *stub, H
|
|||
if (!nilStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(nilStub);
|
||||
stub->addNewStub(cx, nilStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2239,7 +2249,7 @@ DoToBoolFallback(JSContext *cx, BaselineFrame *frame, ICToBool_Fallback *stub, H
|
|||
if (!objStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(objStub);
|
||||
stub->addNewStub(cx, objStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2531,11 +2541,11 @@ DoBinaryArithFallback(JSContext *cx, BaselineFrame *frame, ICBinaryArith_Fallbac
|
|||
}
|
||||
|
||||
if (ret.isDouble())
|
||||
stub->setSawDoubleResult();
|
||||
stub->setSawDoubleResult(cx);
|
||||
|
||||
// Check to see if a new stub should be generated.
|
||||
if (stub->numOptimizedStubs() >= ICBinaryArith_Fallback::MAX_OPTIMIZED_STUBS) {
|
||||
stub->noteUnoptimizableOperands();
|
||||
stub->noteUnoptimizableOperands(cx);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2548,7 +2558,7 @@ DoBinaryArithFallback(JSContext *cx, BaselineFrame *frame, ICBinaryArith_Fallbac
|
|||
ICStub *strcatStub = compiler.getStub(compiler.getStubSpace(script));
|
||||
if (!strcatStub)
|
||||
return false;
|
||||
stub->addNewStub(strcatStub);
|
||||
stub->addNewStub(cx, strcatStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2561,7 +2571,7 @@ DoBinaryArithFallback(JSContext *cx, BaselineFrame *frame, ICBinaryArith_Fallbac
|
|||
ICStub *strcatStub = compiler.getStub(compiler.getStubSpace(script));
|
||||
if (!strcatStub)
|
||||
return false;
|
||||
stub->addNewStub(strcatStub);
|
||||
stub->addNewStub(cx, strcatStub);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -2577,13 +2587,13 @@ DoBinaryArithFallback(JSContext *cx, BaselineFrame *frame, ICBinaryArith_Fallbac
|
|||
ICStub *arithStub = compiler.getStub(compiler.getStubSpace(script));
|
||||
if (!arithStub)
|
||||
return false;
|
||||
stub->addNewStub(arithStub);
|
||||
stub->addNewStub(cx, arithStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Handle only int32 or double.
|
||||
if (!lhs.isNumber() || !rhs.isNumber()) {
|
||||
stub->noteUnoptimizableOperands();
|
||||
stub->noteUnoptimizableOperands(cx);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2607,7 +2617,7 @@ DoBinaryArithFallback(JSContext *cx, BaselineFrame *frame, ICBinaryArith_Fallbac
|
|||
ICStub *doubleStub = compiler.getStub(compiler.getStubSpace(script));
|
||||
if (!doubleStub)
|
||||
return false;
|
||||
stub->addNewStub(doubleStub);
|
||||
stub->addNewStub(cx, doubleStub);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
|
@ -2625,7 +2635,7 @@ DoBinaryArithFallback(JSContext *cx, BaselineFrame *frame, ICBinaryArith_Fallbac
|
|||
ICStub *int32Stub = compilerInt32.getStub(compilerInt32.getStubSpace(script));
|
||||
if (!int32Stub)
|
||||
return false;
|
||||
stub->addNewStub(int32Stub);
|
||||
stub->addNewStub(cx, int32Stub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2644,7 +2654,7 @@ DoBinaryArithFallback(JSContext *cx, BaselineFrame *frame, ICBinaryArith_Fallbac
|
|||
ICStub *optStub = compiler.getStub(compiler.getStubSpace(script));
|
||||
if (!optStub)
|
||||
return false;
|
||||
stub->addNewStub(optStub);
|
||||
stub->addNewStub(cx, optStub);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
|
@ -2652,7 +2662,7 @@ DoBinaryArithFallback(JSContext *cx, BaselineFrame *frame, ICBinaryArith_Fallbac
|
|||
}
|
||||
}
|
||||
|
||||
stub->noteUnoptimizableOperands();
|
||||
stub->noteUnoptimizableOperands(cx);
|
||||
return true;
|
||||
}
|
||||
#if defined(_MSC_VER)
|
||||
|
@ -3047,7 +3057,7 @@ DoUnaryArithFallback(JSContext *cx, BaselineFrame *frame, ICUnaryArith_Fallback
|
|||
ICStub *int32Stub = compiler.getStub(compiler.getStubSpace(script));
|
||||
if (!int32Stub)
|
||||
return false;
|
||||
stub->addNewStub(int32Stub);
|
||||
stub->addNewStub(cx, int32Stub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3061,7 +3071,7 @@ DoUnaryArithFallback(JSContext *cx, BaselineFrame *frame, ICUnaryArith_Fallback
|
|||
ICStub *doubleStub = compiler.getStub(compiler.getStubSpace(script));
|
||||
if (!doubleStub)
|
||||
return false;
|
||||
stub->addNewStub(doubleStub);
|
||||
stub->addNewStub(cx, doubleStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3629,7 +3639,7 @@ RemoveExistingGetElemNativeStubs(JSContext *cx, ICGetElem_Fallback *stub, Handle
|
|||
// If the holder matches, but the holder's lastProperty doesn't match, then
|
||||
// this stub is invalid anyway. Unlink it.
|
||||
if (holder->lastProperty() != protoStub->holderShape()) {
|
||||
iter.unlink(cx->zone());
|
||||
iter.unlink(cx);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
|
@ -3645,7 +3655,7 @@ RemoveExistingGetElemNativeStubs(JSContext *cx, ICGetElem_Fallback *stub, Handle
|
|||
// If the holder matches, but the holder's lastProperty doesn't match, then
|
||||
// this stub is invalid anyway. Unlink it.
|
||||
if (holder->lastProperty() != protoStub->holderShape()) {
|
||||
iter.unlink(cx->zone());
|
||||
iter.unlink(cx);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -3654,7 +3664,7 @@ RemoveExistingGetElemNativeStubs(JSContext *cx, ICGetElem_Fallback *stub, Handle
|
|||
// If the new stub needs atomization, and the old stub doesn't atomize, then
|
||||
// remove the old stub.
|
||||
if (needsAtomize && !getElemNativeStub->needsAtomize()) {
|
||||
iter.unlink(cx->zone());
|
||||
iter.unlink(cx);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -3745,7 +3755,7 @@ static bool TryAttachNativeGetElemStub(JSContext *cx, HandleScript script, jsbyt
|
|||
if (!newStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(newStub);
|
||||
stub->addNewStub(cx, newStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3797,7 +3807,7 @@ static bool TryAttachNativeGetElemStub(JSContext *cx, HandleScript script, jsbyt
|
|||
if (!newStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(newStub);
|
||||
stub->addNewStub(cx, newStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3831,7 +3841,7 @@ TryAttachGetElemStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICGetEl
|
|||
if (!stringStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(stringStub);
|
||||
stub->addNewStub(cx, stringStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3849,7 +3859,7 @@ TryAttachGetElemStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICGetEl
|
|||
if (!argsStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(argsStub);
|
||||
stub->addNewStub(cx, argsStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3871,7 +3881,7 @@ TryAttachGetElemStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICGetEl
|
|||
if (!argsStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(argsStub);
|
||||
stub->addNewStub(cx, argsStub);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -3886,7 +3896,7 @@ TryAttachGetElemStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICGetEl
|
|||
if (!denseStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(denseStub);
|
||||
stub->addNewStub(cx, denseStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3920,7 +3930,7 @@ TryAttachGetElemStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICGetEl
|
|||
if (!typedArrayStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(typedArrayStub);
|
||||
stub->addNewStub(cx, typedArrayStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3928,13 +3938,13 @@ TryAttachGetElemStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICGetEl
|
|||
// be cached by either Baseline or Ion. Indicate this in the cache so that
|
||||
// Ion does not generate a cache for this op.
|
||||
if (!obj->isNative() && !obj->is<TypedArrayObject>())
|
||||
stub->noteNonNativeAccess();
|
||||
stub->noteNonNativeAccess(cx);
|
||||
|
||||
// GetElem operations which could access negative indexes generally can't
|
||||
// be optimized without the potential for bailouts, as we can't statically
|
||||
// determine that an object has no properties on such indexes.
|
||||
if (rhs.isNumber() && rhs.toNumber() < 0)
|
||||
stub->noteNegativeIndex();
|
||||
stub->noteNegativeIndex(cx);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -4844,7 +4854,7 @@ RemoveExistingTypedArraySetElemStub(JSContext *cx, ICSetElem_Fallback *stub, Han
|
|||
// TypedArraySetElem stubs are only removed using this procedure if
|
||||
// being replaced with one that expects out of bounds index.
|
||||
JS_ASSERT(!iter->toSetElem_TypedArray()->expectOutOfBounds());
|
||||
iter.unlink(cx->zone());
|
||||
iter.unlink(cx);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -5001,7 +5011,7 @@ DoSetElemFallback(JSContext *cx, BaselineFrame *frame, ICSetElem_Fallback *stub,
|
|||
if (!denseStub->addUpdateStubForValue(cx, script, obj, JSID_VOIDHANDLE, rhs))
|
||||
return false;
|
||||
|
||||
stub->addNewStub(denseStub);
|
||||
stub->addNewStub(cx, denseStub);
|
||||
} else if (!addingCase &&
|
||||
!DenseSetElemStubExists(cx, ICStub::SetElem_Dense, stub, obj))
|
||||
{
|
||||
|
@ -5015,7 +5025,7 @@ DoSetElemFallback(JSContext *cx, BaselineFrame *frame, ICSetElem_Fallback *stub,
|
|||
if (!denseStub->addUpdateStubForValue(cx, script, obj, JSID_VOIDHANDLE, rhs))
|
||||
return false;
|
||||
|
||||
stub->addNewStub(denseStub);
|
||||
stub->addNewStub(cx, denseStub);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5048,7 +5058,7 @@ DoSetElemFallback(JSContext *cx, BaselineFrame *frame, ICSetElem_Fallback *stub,
|
|||
if (!typedArrayStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(typedArrayStub);
|
||||
stub->addNewStub(cx, typedArrayStub);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -5098,13 +5108,13 @@ ICSetElem_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
|
|||
}
|
||||
|
||||
void
|
||||
BaselineScript::noteArrayWriteHole(uint32_t pcOffset)
|
||||
BaselineScript::noteArrayWriteHole(JSContext *cx, uint32_t pcOffset)
|
||||
{
|
||||
ICEntry &entry = icEntryFromPCOffset(pcOffset);
|
||||
ICFallbackStub *stub = entry.fallbackStub();
|
||||
|
||||
if (stub->isSetElem_Fallback())
|
||||
stub->toSetElem_Fallback()->noteArrayWriteHole();
|
||||
stub->toSetElem_Fallback()->noteArrayWriteHole(cx);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -5626,7 +5636,7 @@ TryAttachGlobalNameStub(JSContext *cx, HandleScript script, ICGetName_Fallback *
|
|||
if (!newStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(newStub);
|
||||
stub->addNewStub(cx, newStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -5716,7 +5726,7 @@ TryAttachScopeNameStub(JSContext *cx, HandleScript script, ICGetName_Fallback *s
|
|||
if (!newStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(newStub);
|
||||
stub->addNewStub(cx, newStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -5923,7 +5933,7 @@ DoGetIntrinsicFallback(JSContext *cx, BaselineFrame *frame, ICGetIntrinsic_Fallb
|
|||
if (!newStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(newStub);
|
||||
stub->addNewStub(cx, newStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -5971,7 +5981,7 @@ TryAttachLengthStub(JSContext *cx, HandleScript script, ICGetProp_Fallback *stub
|
|||
return false;
|
||||
|
||||
*attached = true;
|
||||
stub->addNewStub(newStub);
|
||||
stub->addNewStub(cx, newStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -5983,7 +5993,7 @@ TryAttachLengthStub(JSContext *cx, HandleScript script, ICGetProp_Fallback *stub
|
|||
return false;
|
||||
|
||||
*attached = true;
|
||||
stub->addNewStub(newStub);
|
||||
stub->addNewStub(cx, newStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -6000,7 +6010,7 @@ TryAttachLengthStub(JSContext *cx, HandleScript script, ICGetProp_Fallback *stub
|
|||
return false;
|
||||
|
||||
*attached = true;
|
||||
stub->addNewStub(newStub);
|
||||
stub->addNewStub(cx, newStub);
|
||||
return true;
|
||||
}
|
||||
if (obj->is<TypedArrayObject>()) {
|
||||
|
@ -6012,7 +6022,7 @@ TryAttachLengthStub(JSContext *cx, HandleScript script, ICGetProp_Fallback *stub
|
|||
return false;
|
||||
|
||||
*attached = true;
|
||||
stub->addNewStub(newStub);
|
||||
stub->addNewStub(cx, newStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -6028,7 +6038,7 @@ TryAttachLengthStub(JSContext *cx, HandleScript script, ICGetProp_Fallback *stub
|
|||
return false;
|
||||
|
||||
*attached = true;
|
||||
stub->addNewStub(newStub);
|
||||
stub->addNewStub(cx, newStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -6111,7 +6121,7 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
|
|||
if (!newStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(newStub);
|
||||
stub->addNewStub(cx, newStub);
|
||||
*attached = true;
|
||||
return true;
|
||||
}
|
||||
|
@ -6142,7 +6152,7 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
|
|||
if (!newStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(newStub);
|
||||
stub->addNewStub(cx, newStub);
|
||||
*attached = true;
|
||||
return true;
|
||||
}
|
||||
|
@ -6189,7 +6199,7 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
|
|||
}
|
||||
if (!newStub)
|
||||
return false;
|
||||
stub->addNewStub(newStub);
|
||||
stub->addNewStub(cx, newStub);
|
||||
*attached = true;
|
||||
return true;
|
||||
}
|
||||
|
@ -6209,7 +6219,7 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
|
|||
ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
|
||||
if (!newStub)
|
||||
return false;
|
||||
stub->addNewStub(newStub);
|
||||
stub->addNewStub(cx, newStub);
|
||||
*attached = true;
|
||||
return true;
|
||||
}
|
||||
|
@ -6263,7 +6273,7 @@ TryAttachPrimitiveGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc
|
|||
if (!newStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(newStub);
|
||||
stub->addNewStub(cx, newStub);
|
||||
*attached = true;
|
||||
return true;
|
||||
}
|
||||
|
@ -6349,7 +6359,7 @@ DoGetPropFallback(JSContext *cx, BaselineFrame *frame, ICGetProp_Fallback *stub,
|
|||
}
|
||||
|
||||
JS_ASSERT(!attached);
|
||||
stub->noteUnoptimizableAccess();
|
||||
stub->noteUnoptimizableAccess(cx);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -7094,13 +7104,13 @@ ICGetProp_ArgumentsLength::Compiler::generateStubCode(MacroAssembler &masm)
|
|||
}
|
||||
|
||||
void
|
||||
BaselineScript::noteAccessedGetter(uint32_t pcOffset)
|
||||
BaselineScript::noteAccessedGetter(JSContext *cx, uint32_t pcOffset)
|
||||
{
|
||||
ICEntry &entry = icEntryFromPCOffset(pcOffset);
|
||||
ICFallbackStub *stub = entry.fallbackStub();
|
||||
|
||||
if (stub->isGetProp_Fallback())
|
||||
stub->toGetProp_Fallback()->noteAccessedGetter();
|
||||
stub->toGetProp_Fallback()->noteAccessedGetter(cx);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -7141,7 +7151,7 @@ TryAttachSetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICSetPr
|
|||
if (!newStub->addUpdateStubForValue(cx, script, obj, id, rhs))
|
||||
return false;
|
||||
|
||||
stub->addNewStub(newStub);
|
||||
stub->addNewStub(cx, newStub);
|
||||
*attached = true;
|
||||
return true;
|
||||
}
|
||||
|
@ -7159,7 +7169,7 @@ TryAttachSetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICSetPr
|
|||
if (!newStub->addUpdateStubForValue(cx, script, obj, id, rhs))
|
||||
return false;
|
||||
|
||||
stub->addNewStub(newStub);
|
||||
stub->addNewStub(cx, newStub);
|
||||
*attached = true;
|
||||
return true;
|
||||
}
|
||||
|
@ -7181,7 +7191,7 @@ TryAttachSetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICSetPr
|
|||
if (!newStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(newStub);
|
||||
stub->addNewStub(cx, newStub);
|
||||
*attached = true;
|
||||
return true;
|
||||
}
|
||||
|
@ -7200,7 +7210,7 @@ TryAttachSetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICSetPr
|
|||
if (!newStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(newStub);
|
||||
stub->addNewStub(cx, newStub);
|
||||
*attached = true;
|
||||
return true;
|
||||
}
|
||||
|
@ -7271,7 +7281,7 @@ DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub,
|
|||
return true;
|
||||
|
||||
JS_ASSERT(!attached);
|
||||
stub->noteUnoptimizableAccess();
|
||||
stub->noteUnoptimizableAccess(cx);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -7775,7 +7785,7 @@ TryAttachFunApplyStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script,
|
|||
if (!newStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(newStub);
|
||||
stub->addNewStub(cx, newStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -7792,7 +7802,7 @@ TryAttachFunApplyStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script,
|
|||
if (!newStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(newStub);
|
||||
stub->addNewStub(cx, newStub);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -7933,7 +7943,7 @@ TryAttachCallStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script, jsb
|
|||
stub->unlinkStubsWithKind(cx, ICStub::Call_Scripted);
|
||||
|
||||
// Add new generalized stub.
|
||||
stub->addNewStub(newStub);
|
||||
stub->addNewStub(cx, newStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -7962,7 +7972,7 @@ TryAttachCallStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script, jsb
|
|||
if (!newStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(newStub);
|
||||
stub->addNewStub(cx, newStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -7999,7 +8009,7 @@ TryAttachCallStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script, jsb
|
|||
if (!newStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(newStub);
|
||||
stub->addNewStub(cx, newStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -9123,7 +9133,7 @@ DoIteratorMoreFallback(JSContext *cx, BaselineFrame *frame, ICIteratorMore_Fallb
|
|||
ICStub *newStub = compiler.getStub(compiler.getStubSpace(frame->script()));
|
||||
if (!newStub)
|
||||
return false;
|
||||
stub->addNewStub(newStub);
|
||||
stub->addNewStub(cx, newStub);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -9197,7 +9207,7 @@ DoIteratorNextFallback(JSContext *cx, BaselineFrame *frame, ICIteratorNext_Fallb
|
|||
return false;
|
||||
|
||||
if (!res.isString() && !stub->hasNonStringResult())
|
||||
stub->setHasNonStringResult();
|
||||
stub->setHasNonStringResult(cx);
|
||||
|
||||
if (iteratorObject->is<PropertyIteratorObject>() &&
|
||||
!stub->hasStub(ICStub::IteratorNext_Native))
|
||||
|
@ -9206,7 +9216,7 @@ DoIteratorNextFallback(JSContext *cx, BaselineFrame *frame, ICIteratorNext_Fallb
|
|||
ICStub *newStub = compiler.getStub(compiler.getStubSpace(frame->script()));
|
||||
if (!newStub)
|
||||
return false;
|
||||
stub->addNewStub(newStub);
|
||||
stub->addNewStub(cx, newStub);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -9370,7 +9380,7 @@ DoTypeOfFallback(JSContext *cx, BaselineFrame *frame, ICTypeOf_Fallback *stub, H
|
|||
ICStub *typeOfStub = compiler.getStub(compiler.getStubSpace(frame->script()));
|
||||
if (!typeOfStub)
|
||||
return false;
|
||||
stub->addNewStub(typeOfStub);
|
||||
stub->addNewStub(cx, typeOfStub);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -9457,7 +9467,7 @@ DoRetSubFallback(JSContext *cx, BaselineFrame *frame, ICRetSub_Fallback *stub,
|
|||
if (!optStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(optStub);
|
||||
stub->addNewStub(cx, optStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -516,7 +516,7 @@ class ICStubIterator
|
|||
return currentStub_ == (ICStub *) fallbackStub_;
|
||||
}
|
||||
|
||||
void unlink(Zone *zone);
|
||||
void unlink(JSContext *cx);
|
||||
};
|
||||
|
||||
//
|
||||
|
@ -687,6 +687,8 @@ class ICStub
|
|||
}
|
||||
|
||||
inline void setNext(ICStub *stub) {
|
||||
// Note: next_ only needs to be changed under the compilation lock for
|
||||
// non-type-monitor/update ICs.
|
||||
next_ = stub;
|
||||
}
|
||||
|
||||
|
@ -833,7 +835,8 @@ class ICFallbackStub : public ICStub
|
|||
}
|
||||
|
||||
// Add a new stub to the IC chain terminated by this fallback stub.
|
||||
void addNewStub(ICStub *stub) {
|
||||
void addNewStub(JSContext *cx, ICStub *stub) {
|
||||
AutoLockForCompilation lock(cx);
|
||||
JS_ASSERT(*lastStubPtrAddr_ == this);
|
||||
JS_ASSERT(stub->next() == nullptr);
|
||||
stub->setNext(this);
|
||||
|
@ -2439,13 +2442,15 @@ class ICBinaryArith_Fallback : public ICFallbackStub
|
|||
bool sawDoubleResult() const {
|
||||
return extra_ & SAW_DOUBLE_RESULT_BIT;
|
||||
}
|
||||
void setSawDoubleResult() {
|
||||
void setSawDoubleResult(JSContext *cx) {
|
||||
AutoLockForCompilation lock(cx);
|
||||
extra_ |= SAW_DOUBLE_RESULT_BIT;
|
||||
}
|
||||
bool hadUnoptimizableOperands() const {
|
||||
return extra_ & UNOPTIMIZABLE_OPERANDS_BIT;
|
||||
}
|
||||
void noteUnoptimizableOperands() {
|
||||
void noteUnoptimizableOperands(JSContext *cx) {
|
||||
AutoLockForCompilation lock(cx);
|
||||
extra_ |= UNOPTIMIZABLE_OPERANDS_BIT;
|
||||
}
|
||||
|
||||
|
@ -2846,14 +2851,16 @@ class ICGetElem_Fallback : public ICMonitoredFallbackStub
|
|||
return space->allocate<ICGetElem_Fallback>(code);
|
||||
}
|
||||
|
||||
void noteNonNativeAccess() {
|
||||
void noteNonNativeAccess(JSContext *cx) {
|
||||
AutoLockForCompilation lock(cx);
|
||||
extra_ |= EXTRA_NON_NATIVE;
|
||||
}
|
||||
bool hasNonNativeAccess() const {
|
||||
return extra_ & EXTRA_NON_NATIVE;
|
||||
}
|
||||
|
||||
void noteNegativeIndex() {
|
||||
void noteNegativeIndex(JSContext *cx) {
|
||||
AutoLockForCompilation lock(cx);
|
||||
extra_ |= EXTRA_NEGATIVE_INDEX;
|
||||
}
|
||||
bool hasNegativeIndex() const {
|
||||
|
@ -3441,7 +3448,8 @@ class ICSetElem_Fallback : public ICFallbackStub
|
|||
return space->allocate<ICSetElem_Fallback>(code);
|
||||
}
|
||||
|
||||
void noteArrayWriteHole() {
|
||||
void noteArrayWriteHole(JSContext *cx) {
|
||||
AutoLockForCompilation lock(cx);
|
||||
extra_ = 1;
|
||||
}
|
||||
bool hasArrayWriteHole() const {
|
||||
|
@ -4016,14 +4024,16 @@ class ICGetProp_Fallback : public ICMonitoredFallbackStub
|
|||
static const size_t UNOPTIMIZABLE_ACCESS_BIT = 0;
|
||||
static const size_t ACCESSED_GETTER_BIT = 1;
|
||||
|
||||
void noteUnoptimizableAccess() {
|
||||
void noteUnoptimizableAccess(JSContext *cx) {
|
||||
AutoLockForCompilation lock(cx);
|
||||
extra_ |= (1u << UNOPTIMIZABLE_ACCESS_BIT);
|
||||
}
|
||||
bool hadUnoptimizableAccess() const {
|
||||
return extra_ & (1u << UNOPTIMIZABLE_ACCESS_BIT);
|
||||
}
|
||||
|
||||
void noteAccessedGetter() {
|
||||
void noteAccessedGetter(JSContext *cx) {
|
||||
AutoLockForCompilation lock(cx);
|
||||
extra_ |= (1u << ACCESSED_GETTER_BIT);
|
||||
}
|
||||
bool hasAccessedGetter() const {
|
||||
|
@ -4830,7 +4840,8 @@ class ICSetProp_Fallback : public ICFallbackStub
|
|||
}
|
||||
|
||||
static const size_t UNOPTIMIZABLE_ACCESS_BIT = 0;
|
||||
void noteUnoptimizableAccess() {
|
||||
void noteUnoptimizableAccess(JSContext *cx) {
|
||||
AutoLockForCompilation lock(cx);
|
||||
extra_ |= (1u << UNOPTIMIZABLE_ACCESS_BIT);
|
||||
}
|
||||
bool hadUnoptimizableAccess() const {
|
||||
|
@ -5721,7 +5732,8 @@ class ICIteratorNext_Fallback : public ICFallbackStub
|
|||
return space->allocate<ICIteratorNext_Fallback>(code);
|
||||
}
|
||||
|
||||
void setHasNonStringResult() {
|
||||
void setHasNonStringResult(JSContext *cx) {
|
||||
AutoLockForCompilation lock(cx);
|
||||
JS_ASSERT(extra_ == 0);
|
||||
extra_ = 1;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@ using mozilla::DebugOnly;
|
|||
bool
|
||||
SetElemICInspector::sawOOBDenseWrite() const
|
||||
{
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
|
||||
if (!icEntry_)
|
||||
return false;
|
||||
|
||||
|
@ -38,6 +40,8 @@ SetElemICInspector::sawOOBDenseWrite() const
|
|||
bool
|
||||
SetElemICInspector::sawOOBTypedArrayWrite() const
|
||||
{
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
|
||||
if (!icEntry_)
|
||||
return false;
|
||||
|
||||
|
@ -54,6 +58,8 @@ SetElemICInspector::sawOOBTypedArrayWrite() const
|
|||
bool
|
||||
SetElemICInspector::sawDenseWrite() const
|
||||
{
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
|
||||
if (!icEntry_)
|
||||
return false;
|
||||
|
||||
|
@ -68,6 +74,8 @@ SetElemICInspector::sawDenseWrite() const
|
|||
bool
|
||||
SetElemICInspector::sawTypedArrayWrite() const
|
||||
{
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
|
||||
if (!icEntry_)
|
||||
return false;
|
||||
|
||||
|
@ -82,6 +90,8 @@ SetElemICInspector::sawTypedArrayWrite() const
|
|||
bool
|
||||
BaselineInspector::maybeShapesForPropertyOp(jsbytecode *pc, ShapeVector &shapes)
|
||||
{
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
|
||||
// Return a list of shapes seen by the baseline IC for the current op.
|
||||
// An empty list indicates no shapes are known, or there was an uncacheable
|
||||
// access.
|
||||
|
@ -139,6 +149,8 @@ BaselineInspector::maybeShapesForPropertyOp(jsbytecode *pc, ShapeVector &shapes)
|
|||
ICStub *
|
||||
BaselineInspector::monomorphicStub(jsbytecode *pc)
|
||||
{
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
|
||||
if (!hasBaselineScript())
|
||||
return nullptr;
|
||||
|
||||
|
@ -156,6 +168,8 @@ BaselineInspector::monomorphicStub(jsbytecode *pc)
|
|||
bool
|
||||
BaselineInspector::dimorphicStub(jsbytecode *pc, ICStub **pfirst, ICStub **psecond)
|
||||
{
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
|
||||
if (!hasBaselineScript())
|
||||
return false;
|
||||
|
||||
|
@ -176,6 +190,8 @@ BaselineInspector::dimorphicStub(jsbytecode *pc, ICStub **pfirst, ICStub **pseco
|
|||
MIRType
|
||||
BaselineInspector::expectedResultType(jsbytecode *pc)
|
||||
{
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
|
||||
// Look at the IC entries for this op to guess what type it will produce,
|
||||
// returning MIRType_None otherwise.
|
||||
|
||||
|
@ -222,6 +238,8 @@ CanUseInt32Compare(ICStub::Kind kind)
|
|||
MCompare::CompareType
|
||||
BaselineInspector::expectedCompareType(jsbytecode *pc)
|
||||
{
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
|
||||
ICStub *first = monomorphicStub(pc), *second = nullptr;
|
||||
if (!first && !dimorphicStub(pc, &first, &second))
|
||||
return MCompare::Compare_Unknown;
|
||||
|
@ -304,6 +322,8 @@ TryToSpecializeBinaryArithOp(ICStub **stubs,
|
|||
MIRType
|
||||
BaselineInspector::expectedBinaryArithSpecialization(jsbytecode *pc)
|
||||
{
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
|
||||
MIRType result;
|
||||
ICStub *stubs[2];
|
||||
|
||||
|
@ -332,6 +352,8 @@ BaselineInspector::expectedBinaryArithSpecialization(jsbytecode *pc)
|
|||
bool
|
||||
BaselineInspector::hasSeenNonNativeGetElement(jsbytecode *pc)
|
||||
{
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
|
||||
if (!hasBaselineScript())
|
||||
return false;
|
||||
|
||||
|
@ -346,6 +368,8 @@ BaselineInspector::hasSeenNonNativeGetElement(jsbytecode *pc)
|
|||
bool
|
||||
BaselineInspector::hasSeenNegativeIndexGetElement(jsbytecode *pc)
|
||||
{
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
|
||||
if (!hasBaselineScript())
|
||||
return false;
|
||||
|
||||
|
@ -360,6 +384,8 @@ BaselineInspector::hasSeenNegativeIndexGetElement(jsbytecode *pc)
|
|||
bool
|
||||
BaselineInspector::hasSeenAccessedGetter(jsbytecode *pc)
|
||||
{
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
|
||||
if (!hasBaselineScript())
|
||||
return false;
|
||||
|
||||
|
@ -374,6 +400,8 @@ BaselineInspector::hasSeenAccessedGetter(jsbytecode *pc)
|
|||
bool
|
||||
BaselineInspector::hasSeenNonStringIterNext(jsbytecode *pc)
|
||||
{
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
|
||||
JS_ASSERT(JSOp(*pc) == JSOP_ITERNEXT);
|
||||
|
||||
if (!hasBaselineScript())
|
||||
|
@ -388,6 +416,8 @@ BaselineInspector::hasSeenNonStringIterNext(jsbytecode *pc)
|
|||
bool
|
||||
BaselineInspector::hasSeenDoubleResult(jsbytecode *pc)
|
||||
{
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
|
||||
if (!hasBaselineScript())
|
||||
return false;
|
||||
|
||||
|
@ -407,6 +437,8 @@ BaselineInspector::hasSeenDoubleResult(jsbytecode *pc)
|
|||
JSObject *
|
||||
BaselineInspector::getTemplateObject(jsbytecode *pc)
|
||||
{
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
|
||||
if (!hasBaselineScript())
|
||||
return nullptr;
|
||||
|
||||
|
@ -434,6 +466,8 @@ BaselineInspector::getTemplateObject(jsbytecode *pc)
|
|||
JSObject *
|
||||
BaselineInspector::getTemplateObjectForNative(jsbytecode *pc, Native native)
|
||||
{
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
|
||||
if (!hasBaselineScript())
|
||||
return nullptr;
|
||||
|
||||
|
@ -467,6 +501,8 @@ BaselineInspector::templateCallObject()
|
|||
JSObject *
|
||||
BaselineInspector::commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonGetter)
|
||||
{
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
|
||||
const ICEntry &entry = icEntryFromPC(pc);
|
||||
for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) {
|
||||
if (stub->isGetProp_CallScripted() || stub->isGetProp_CallNative()) {
|
||||
|
@ -482,6 +518,8 @@ BaselineInspector::commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, J
|
|||
JSObject *
|
||||
BaselineInspector::commonSetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonSetter)
|
||||
{
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
|
||||
const ICEntry &entry = icEntryFromPC(pc);
|
||||
for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) {
|
||||
if (stub->isSetProp_CallScripted() || stub->isSetProp_CallNative()) {
|
||||
|
|
|
@ -237,7 +237,7 @@ jit::BaselineCompile(JSContext *cx, HandleScript script)
|
|||
JS_ASSERT_IF(status != Method_Compiled, !script->hasBaselineScript());
|
||||
|
||||
if (status == Method_CantCompile)
|
||||
script->setBaselineScript(BASELINE_DISABLED_SCRIPT);
|
||||
script->setBaselineScript(cx, BASELINE_DISABLED_SCRIPT);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
@ -650,7 +650,7 @@ BaselineScript::copyPCMappingIndexEntries(const PCMappingIndexEntry *entries)
|
|||
uint8_t *
|
||||
BaselineScript::nativeCodeForPC(JSScript *script, jsbytecode *pc, PCMappingSlotInfo *slotInfo)
|
||||
{
|
||||
JS_ASSERT(script->baselineScript() == this);
|
||||
JS_ASSERT_IF(script->hasBaselineScript(), script->baselineScript() == this);
|
||||
|
||||
uint32_t pcOffset = script->pcToOffset(pc);
|
||||
|
||||
|
@ -892,7 +892,7 @@ jit::FinishDiscardBaselineScript(FreeOp *fop, JSScript *script)
|
|||
}
|
||||
|
||||
BaselineScript *baseline = script->baselineScript();
|
||||
script->setBaselineScript(nullptr);
|
||||
script->setBaselineScript(nullptr, nullptr);
|
||||
BaselineScript::Destroy(fop, baseline);
|
||||
}
|
||||
|
||||
|
|
|
@ -289,8 +289,8 @@ struct BaselineScript
|
|||
|
||||
void toggleSPS(bool enable);
|
||||
|
||||
void noteAccessedGetter(uint32_t pcOffset);
|
||||
void noteArrayWriteHole(uint32_t pcOffset);
|
||||
void noteAccessedGetter(JSContext *cx, uint32_t pcOffset);
|
||||
void noteArrayWriteHole(JSContext *cx, uint32_t pcOffset);
|
||||
|
||||
static size_t offsetOfFlags() {
|
||||
return offsetof(BaselineScript, flags_);
|
||||
|
|
|
@ -3389,14 +3389,14 @@ CodeGenerator::visitNewCallObject(LNewCallObject *lir)
|
|||
ool = oolCallVM(NewCallObjectInfo, lir,
|
||||
(ArgList(), ImmGCPtr(lir->mir()->block()->info().script()),
|
||||
ImmGCPtr(templateObj->lastProperty()),
|
||||
ImmGCPtr(templateObj->hasLazyType() ? nullptr : templateObj->type()),
|
||||
ImmGCPtr(templateObj->hasSingletonType() ? nullptr : templateObj->type()),
|
||||
ToRegister(lir->slots())),
|
||||
StoreRegisterTo(obj));
|
||||
} else {
|
||||
ool = oolCallVM(NewCallObjectInfo, lir,
|
||||
(ArgList(), ImmGCPtr(lir->mir()->block()->info().script()),
|
||||
ImmGCPtr(templateObj->lastProperty()),
|
||||
ImmGCPtr(templateObj->hasLazyType() ? nullptr : templateObj->type()),
|
||||
ImmGCPtr(templateObj->hasSingletonType() ? nullptr : templateObj->type()),
|
||||
ImmPtr(nullptr)),
|
||||
StoreRegisterTo(obj));
|
||||
}
|
||||
|
@ -7409,8 +7409,7 @@ CodeGenerator::emitInstanceOf(LInstruction *ins, JSObject *prototypeObject)
|
|||
// out of the loop on Proxy::LazyProto.
|
||||
|
||||
// Load the lhs's prototype.
|
||||
masm.loadPtr(Address(objReg, JSObject::offsetOfType()), output);
|
||||
masm.loadPtr(Address(output, offsetof(types::TypeObject, proto)), output);
|
||||
masm.loadObjProto(objReg, output);
|
||||
|
||||
Label testLazy;
|
||||
{
|
||||
|
@ -7424,14 +7423,13 @@ CodeGenerator::emitInstanceOf(LInstruction *ins, JSObject *prototypeObject)
|
|||
masm.jump(&done);
|
||||
masm.bind(¬PrototypeObject);
|
||||
|
||||
JS_ASSERT(uintptr_t(Proxy::LazyProto) == 1);
|
||||
JS_ASSERT(uintptr_t(TaggedProto::LazyProto) == 1);
|
||||
|
||||
// Test for nullptr or Proxy::LazyProto
|
||||
masm.branchPtr(Assembler::BelowOrEqual, output, ImmWord(1), &testLazy);
|
||||
|
||||
// Load the current object's prototype.
|
||||
masm.loadPtr(Address(output, JSObject::offsetOfType()), output);
|
||||
masm.loadPtr(Address(output, offsetof(types::TypeObject, proto)), output);
|
||||
masm.loadObjProto(output, output);
|
||||
|
||||
masm.jump(&loopPrototypeChain);
|
||||
}
|
||||
|
|
|
@ -45,9 +45,9 @@ class CompileInfo
|
|||
{
|
||||
public:
|
||||
CompileInfo(JSScript *script, JSFunction *fun, jsbytecode *osrPc, bool constructing,
|
||||
ExecutionMode executionMode)
|
||||
ExecutionMode executionMode, bool scriptNeedsArgsObj)
|
||||
: script_(script), fun_(fun), osrPc_(osrPc), constructing_(constructing),
|
||||
executionMode_(executionMode)
|
||||
executionMode_(executionMode), scriptNeedsArgsObj_(scriptNeedsArgsObj)
|
||||
{
|
||||
JS_ASSERT_IF(osrPc, JSOp(*osrPc) == JSOP_LOOPENTRY);
|
||||
|
||||
|
@ -68,7 +68,7 @@ class CompileInfo
|
|||
|
||||
CompileInfo(unsigned nlocals, ExecutionMode executionMode)
|
||||
: script_(nullptr), fun_(nullptr), osrPc_(nullptr), constructing_(false),
|
||||
executionMode_(executionMode)
|
||||
executionMode_(executionMode), scriptNeedsArgsObj_(false)
|
||||
{
|
||||
nimplicit_ = 0;
|
||||
nargs_ = 0;
|
||||
|
@ -250,10 +250,10 @@ class CompileInfo
|
|||
return script()->argumentsAliasesFormals();
|
||||
}
|
||||
bool needsArgsObj() const {
|
||||
return script()->needsArgsObj();
|
||||
return scriptNeedsArgsObj_;
|
||||
}
|
||||
bool argsObjAliasesFormals() const {
|
||||
return script()->argsObjAliasesFormals();
|
||||
return scriptNeedsArgsObj_ && !script()->strict();
|
||||
}
|
||||
|
||||
ExecutionMode executionMode() const {
|
||||
|
@ -275,6 +275,11 @@ class CompileInfo
|
|||
jsbytecode *osrPc_;
|
||||
bool constructing_;
|
||||
ExecutionMode executionMode_;
|
||||
|
||||
// Whether a script needs an arguments object is unstable over compilation
|
||||
// since the arguments optimization could be marked as failed on the main
|
||||
// thread, so cache a value here and use it throughout for consistency.
|
||||
bool scriptNeedsArgsObj_;
|
||||
};
|
||||
|
||||
} // namespace jit
|
||||
|
|
|
@ -125,11 +125,13 @@ CompileRuntime::positiveInfinityValue()
|
|||
return runtime()->positiveInfinityValue;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool
|
||||
CompileRuntime::isInsideNursery(gc::Cell *cell)
|
||||
{
|
||||
return UninlinedIsInsideNursery(runtime(), cell);
|
||||
}
|
||||
#endif
|
||||
|
||||
const DOMCallbacks *
|
||||
CompileRuntime::DOMcallbacks()
|
||||
|
@ -228,3 +230,10 @@ CompileCompartment::hasObjectMetadataCallback()
|
|||
{
|
||||
return compartment()->hasObjectMetadataCallback();
|
||||
}
|
||||
|
||||
AutoLockForCompilation::AutoLockForCompilation(CompileCompartment *compartment
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
init(compartment->compartment()->runtimeFromAnyThread());
|
||||
}
|
||||
|
|
|
@ -66,7 +66,9 @@ class CompileRuntime
|
|||
const Value &NaNValue();
|
||||
const Value &positiveInfinityValue();
|
||||
|
||||
#ifdef DEBUG
|
||||
bool isInsideNursery(gc::Cell *cell);
|
||||
#endif
|
||||
|
||||
// DOM callbacks must be threadsafe (and will hopefully be removed soon).
|
||||
const DOMCallbacks *DOMcallbacks();
|
||||
|
@ -96,6 +98,8 @@ class CompileCompartment
|
|||
{
|
||||
JSCompartment *compartment();
|
||||
|
||||
friend class js::AutoLockForCompilation;
|
||||
|
||||
public:
|
||||
static CompileCompartment *get(JSCompartment *comp);
|
||||
|
||||
|
|
|
@ -49,6 +49,8 @@
|
|||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
||||
using mozilla::Maybe;
|
||||
|
||||
// Global variables.
|
||||
IonOptions jit::js_IonOptions;
|
||||
|
||||
|
@ -516,6 +518,8 @@ JitCompartment::ensureIonStubsExist(JSContext *cx)
|
|||
void
|
||||
jit::FinishOffThreadBuilder(IonBuilder *builder)
|
||||
{
|
||||
builder->script()->runtimeFromMainThread()->removeCompilationThread();
|
||||
|
||||
ExecutionMode executionMode = builder->info().executionMode();
|
||||
|
||||
// Clear the recompiling flag if it would have failed.
|
||||
|
@ -1563,6 +1567,9 @@ AttachFinishedCompilations(JSContext *cx)
|
|||
// operation callback and can't propagate failures.
|
||||
cx->clearPendingException();
|
||||
}
|
||||
} else {
|
||||
if (builder->abortReason() == AbortReason_Disable)
|
||||
SetIonScript(builder->script(), builder->info().executionMode(), ION_DISABLED_SCRIPT);
|
||||
}
|
||||
|
||||
FinishOffThreadBuilder(builder);
|
||||
|
@ -1663,11 +1670,13 @@ IonCompile(JSContext *cx, JSScript *script,
|
|||
return AbortReason_Alloc;
|
||||
|
||||
CompileInfo *info = alloc->new_<CompileInfo>(script, script->function(), osrPc, constructing,
|
||||
executionMode);
|
||||
executionMode, script->needsArgsObj());
|
||||
if (!info)
|
||||
return AbortReason_Alloc;
|
||||
|
||||
BaselineInspector inspector(script);
|
||||
BaselineInspector *inspector = alloc->new_<BaselineInspector>(script);
|
||||
if (!inspector)
|
||||
return AbortReason_Alloc;
|
||||
|
||||
BaselineFrameInspector *baselineFrameInspector = nullptr;
|
||||
if (baselineFrame) {
|
||||
|
@ -1686,7 +1695,7 @@ IonCompile(JSContext *cx, JSScript *script,
|
|||
IonBuilder *builder = alloc->new_<IonBuilder>((JSContext *) nullptr,
|
||||
CompileCompartment::get(cx->compartment()),
|
||||
temp, graph, constraints,
|
||||
&inspector, info, baselineFrameInspector);
|
||||
inspector, info, baselineFrameInspector);
|
||||
if (!builder)
|
||||
return AbortReason_Alloc;
|
||||
|
||||
|
@ -1696,28 +1705,6 @@ IonCompile(JSContext *cx, JSScript *script,
|
|||
RootedScript builderScript(cx, builder->script());
|
||||
IonSpewNewFunction(graph, builderScript);
|
||||
|
||||
mozilla::Maybe<AutoProtectHeapForCompilation> protect;
|
||||
if (js_IonOptions.checkThreadSafety &&
|
||||
cx->runtime()->gcIncrementalState == gc::NO_INCREMENTAL &&
|
||||
!cx->runtime()->profilingScripts &&
|
||||
!cx->runtime()->spsProfiler.enabled())
|
||||
{
|
||||
protect.construct(cx->runtime());
|
||||
}
|
||||
|
||||
bool succeeded = builder->build();
|
||||
builder->clearForBackEnd();
|
||||
|
||||
if (!succeeded) {
|
||||
if (cx->isExceptionPending()) {
|
||||
IonSpew(IonSpew_Abort, "Builder raised exception.");
|
||||
return AbortReason_Error;
|
||||
}
|
||||
|
||||
IonSpew(IonSpew_Abort, "Builder failed to build.");
|
||||
return builder->abortReason();
|
||||
}
|
||||
|
||||
// If possible, compile the script off thread.
|
||||
if (OffThreadCompilationAvailable(cx)) {
|
||||
if (recompile) {
|
||||
|
@ -1739,6 +1726,24 @@ IonCompile(JSContext *cx, JSScript *script,
|
|||
return AbortReason_NoAbort;
|
||||
}
|
||||
|
||||
Maybe<AutoEnterIonCompilation> ionCompiling;
|
||||
ionCompiling.construct();
|
||||
|
||||
Maybe<AutoProtectHeapForIonCompilation> protect;
|
||||
if (js_IonOptions.checkThreadSafety &&
|
||||
cx->runtime()->gcIncrementalState == gc::NO_INCREMENTAL &&
|
||||
!cx->runtime()->profilingScripts &&
|
||||
!cx->runtime()->spsProfiler.enabled())
|
||||
{
|
||||
protect.construct(cx->runtime());
|
||||
}
|
||||
|
||||
bool succeeded = builder->build();
|
||||
builder->clearForBackEnd();
|
||||
|
||||
if (!succeeded)
|
||||
return builder->abortReason();
|
||||
|
||||
ScopedJSDeletePtr<CodeGenerator> codegen(CompileBackEnd(builder));
|
||||
if (!codegen) {
|
||||
IonSpew(IonSpew_Abort, "Failed during back-end compilation.");
|
||||
|
@ -1747,6 +1752,7 @@ IonCompile(JSContext *cx, JSScript *script,
|
|||
|
||||
if (!protect.empty())
|
||||
protect.destroy();
|
||||
ionCompiling.destroy();
|
||||
|
||||
bool success = codegen->link(cx, builder->constraints());
|
||||
|
||||
|
|
|
@ -222,11 +222,10 @@ IsPhiObservable(MPhi *phi, Observability observe)
|
|||
if (fun && slot == info.thisSlot())
|
||||
return true;
|
||||
|
||||
// If the function is heavyweight, and the Phi is of the |scopeChain|
|
||||
// value, and the function may need an arguments object, then make sure
|
||||
// to preserve the scope chain, because it may be needed to construct the
|
||||
// arguments object during bailout.
|
||||
if (fun && fun->isHeavyweight() && info.hasArguments() && slot == info.scopeChainSlot())
|
||||
// If the function may need an arguments object, then make sure to preserve
|
||||
// the scope chain, because it may be needed to construct the arguments
|
||||
// object during bailout.
|
||||
if (fun && info.hasArguments() && slot == info.scopeChainSlot())
|
||||
return true;
|
||||
|
||||
// If the Phi is one of the formal argument, and we are using an argument
|
||||
|
@ -2177,7 +2176,8 @@ jit::AnalyzeNewScriptProperties(JSContext *cx, JSFunction *fun,
|
|||
MIRGraph graph(&temp);
|
||||
CompileInfo info(script, fun,
|
||||
/* osrPc = */ nullptr, /* constructing = */ false,
|
||||
DefinitePropertiesAnalysis);
|
||||
DefinitePropertiesAnalysis,
|
||||
script->needsArgsObj());
|
||||
|
||||
AutoTempAllocatorRooter root(cx, &temp);
|
||||
|
||||
|
|
|
@ -135,16 +135,24 @@ IonBuilder::IonBuilder(JSContext *analysisContext, CompileCompartment *comp, Tem
|
|||
lazyArguments_(nullptr),
|
||||
inlineCallInfo_(nullptr)
|
||||
{
|
||||
script_.init(info->script());
|
||||
script_ = info->script();
|
||||
pc = info->startPC();
|
||||
|
||||
#ifdef DEBUG
|
||||
lock();
|
||||
JS_ASSERT(script()->hasBaselineScript());
|
||||
unlock();
|
||||
#endif
|
||||
JS_ASSERT(!!analysisContext == (info->executionMode() == DefinitePropertiesAnalysis));
|
||||
}
|
||||
|
||||
void
|
||||
IonBuilder::clearForBackEnd()
|
||||
{
|
||||
// This case should only be hit if there was a failure while building.
|
||||
if (!lock_.empty())
|
||||
lock_.destroy();
|
||||
|
||||
JS_ASSERT(!analysisContext);
|
||||
baselineFrame_ = nullptr;
|
||||
|
||||
|
@ -581,12 +589,16 @@ IonBuilder::pushLoop(CFGState::State initial, jsbytecode *stopAt, MBasicBlock *e
|
|||
bool
|
||||
IonBuilder::init()
|
||||
{
|
||||
lock();
|
||||
|
||||
if (!types::TypeScript::FreezeTypeSets(constraints(), script(),
|
||||
&thisTypes, &argTypes, &typeArray))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
unlock();
|
||||
|
||||
if (!analysis().init(alloc(), gsn))
|
||||
return false;
|
||||
|
||||
|
@ -694,6 +706,8 @@ IonBuilder::build()
|
|||
if (!traverseBytecode())
|
||||
return false;
|
||||
|
||||
unlock();
|
||||
|
||||
if (!maybeAddOsrTypeBarriers())
|
||||
return false;
|
||||
|
||||
|
@ -851,6 +865,7 @@ IonBuilder::buildInline(IonBuilder *callerBuilder, MResumePoint *callerResumePoi
|
|||
if (!traverseBytecode())
|
||||
return false;
|
||||
|
||||
unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -905,6 +920,9 @@ IonBuilder::initParameters()
|
|||
// interpreter and didn't accumulate type information, try to use that OSR
|
||||
// frame to determine possible initial types for 'this' and parameters.
|
||||
|
||||
// For unknownProperties() tests under addType.
|
||||
lock();
|
||||
|
||||
if (thisTypes->empty() && baselineFrame_) {
|
||||
if (!thisTypes->addType(baselineFrame_->thisType, alloc_->lifoAlloc()))
|
||||
return false;
|
||||
|
@ -928,6 +946,8 @@ IonBuilder::initParameters()
|
|||
current->initSlot(info().argSlotUnchecked(i), param);
|
||||
}
|
||||
|
||||
unlock();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -950,6 +970,8 @@ IonBuilder::initScopeChain(MDefinition *callee)
|
|||
if (!script()->compileAndGo())
|
||||
return abort("non-CNG global scripts are not supported");
|
||||
|
||||
lock();
|
||||
|
||||
if (JSFunction *fun = info().fun()) {
|
||||
if (!callee) {
|
||||
MCallee *calleeIns = MCallee::New(alloc());
|
||||
|
@ -975,6 +997,8 @@ IonBuilder::initScopeChain(MDefinition *callee)
|
|||
scope = constant(ObjectValue(script()->global()));
|
||||
}
|
||||
|
||||
unlock();
|
||||
|
||||
current->setScopeChain(scope);
|
||||
return true;
|
||||
}
|
||||
|
@ -1168,6 +1192,14 @@ IonBuilder::maybeAddOsrTypeBarriers()
|
|||
bool
|
||||
IonBuilder::traverseBytecode()
|
||||
{
|
||||
// Always hold the compilation lock when traversing bytecode, though release
|
||||
// it before reacquiring it every few opcodes so that the main thread does not
|
||||
// block for long when updating compilation data.
|
||||
lock();
|
||||
|
||||
size_t lockOpcodeCount = 0;
|
||||
static const size_t LOCK_OPCODE_GRANULARITY = 5;
|
||||
|
||||
for (;;) {
|
||||
JS_ASSERT(pc < info().limitPC());
|
||||
|
||||
|
@ -1242,6 +1274,12 @@ IonBuilder::traverseBytecode()
|
|||
if (!inspectOpcode(op))
|
||||
return false;
|
||||
|
||||
if (++lockOpcodeCount == LOCK_OPCODE_GRANULARITY) {
|
||||
unlock();
|
||||
lock();
|
||||
lockOpcodeCount = 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
for (size_t i = 0; i < popped.length(); i++) {
|
||||
// Call instructions can discard PassArg instructions. Ignore them.
|
||||
|
@ -3845,13 +3883,16 @@ IonBuilder::inlineScriptedCall(CallInfo &callInfo, JSFunction *target)
|
|||
LifoAlloc *lifoAlloc = alloc_->lifoAlloc();
|
||||
CompileInfo *info = lifoAlloc->new_<CompileInfo>(calleeScript, target,
|
||||
(jsbytecode *)nullptr, callInfo.constructing(),
|
||||
this->info().executionMode());
|
||||
this->info().executionMode(),
|
||||
/* needsArgsObj = */ false);
|
||||
if (!info)
|
||||
return false;
|
||||
|
||||
MIRGraphReturns returns(alloc());
|
||||
AutoAccumulateReturns aar(graph(), returns);
|
||||
|
||||
unlock();
|
||||
|
||||
// Build the graph.
|
||||
IonBuilder inlineBuilder(analysisContext, compartment,
|
||||
&alloc(), &graph(), constraints(), &inspector, info, nullptr,
|
||||
|
@ -3875,6 +3916,8 @@ IonBuilder::inlineScriptedCall(CallInfo &callInfo, JSFunction *target)
|
|||
return false;
|
||||
}
|
||||
|
||||
lock();
|
||||
|
||||
// Create return block.
|
||||
jsbytecode *postCall = GetNextPc(pc);
|
||||
MBasicBlock *returnBlock = newBlock(nullptr, postCall);
|
||||
|
@ -4698,7 +4741,7 @@ IonBuilder::createThisScriptedSingleton(JSFunction *target, MDefinition *callee)
|
|||
JSObject *templateObject = inspector->getTemplateObject(pc);
|
||||
if (!templateObject || !templateObject->is<JSObject>())
|
||||
return nullptr;
|
||||
if (templateObject->getProto() != proto)
|
||||
if (!templateObject->hasTenuredProto() || templateObject->getProto() != proto)
|
||||
return nullptr;
|
||||
|
||||
if (!target->nonLazyScript()->types)
|
||||
|
@ -5096,6 +5139,8 @@ IonBuilder::testShouldDOMCall(types::TypeSet *inTypes,
|
|||
if (!curType)
|
||||
continue;
|
||||
|
||||
if (!curType->hasTenuredProto())
|
||||
return false;
|
||||
JSObject *proto = curType->proto().toObjectOrNull();
|
||||
if (!instanceChecker(proto, jinfo->protoID, jinfo->depth))
|
||||
return false;
|
||||
|
@ -6031,6 +6076,8 @@ IonBuilder::testSingletonProperty(JSObject *obj, PropertyName *name)
|
|||
if (ClassHasResolveHook(compartment, obj->getClass(), name))
|
||||
return nullptr;
|
||||
|
||||
if (!obj->hasTenuredProto())
|
||||
return nullptr;
|
||||
obj = obj->getProto();
|
||||
}
|
||||
|
||||
|
@ -6104,6 +6151,8 @@ IonBuilder::testSingletonPropertyTypes(MDefinition *obj, JSObject *singleton, Pr
|
|||
if (property.isOwnProperty(constraints()))
|
||||
return false;
|
||||
|
||||
if (!object->hasTenuredProto())
|
||||
return false;
|
||||
if (JSObject *proto = object->proto().toObjectOrNull()) {
|
||||
// Test this type.
|
||||
if (testSingletonProperty(proto, name) != singleton)
|
||||
|
@ -7897,6 +7946,8 @@ IonBuilder::objectsHaveCommonPrototype(types::TemporaryTypeSet *types, PropertyN
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!type->hasTenuredProto())
|
||||
return false;
|
||||
JSObject *proto = type->proto().toObjectOrNull();
|
||||
if (proto == foundProto)
|
||||
break;
|
||||
|
@ -7996,7 +8047,7 @@ IonBuilder::annotateGetPropertyCache(MDefinition *obj, MGetPropertyCache *getPro
|
|||
if (!baseTypeObj)
|
||||
continue;
|
||||
types::TypeObjectKey *typeObj = types::TypeObjectKey::get(baseTypeObj);
|
||||
if (typeObj->unknownProperties() || !typeObj->proto().isObject())
|
||||
if (typeObj->unknownProperties() || !typeObj->hasTenuredProto() || !typeObj->proto().isObject())
|
||||
continue;
|
||||
|
||||
const Class *clasp = typeObj->clasp();
|
||||
|
|
|
@ -724,7 +724,7 @@ class IonBuilder : public MIRGenerator
|
|||
}
|
||||
|
||||
// A builder is inextricably tied to a particular script.
|
||||
HeapPtrScript script_;
|
||||
JSScript *script_;
|
||||
|
||||
// If off thread compilation is successful, the final code generator is
|
||||
// attached here. Code has been generated, but not linked (there is not yet
|
||||
|
@ -735,7 +735,7 @@ class IonBuilder : public MIRGenerator
|
|||
public:
|
||||
void clearForBackEnd();
|
||||
|
||||
JSScript *script() const { return script_.get(); }
|
||||
JSScript *script() const { return script_; }
|
||||
|
||||
CodeGenerator *backgroundCodegen() const { return backgroundCodegen_; }
|
||||
void setBackgroundCodegen(CodeGenerator *codegen) { backgroundCodegen_ = codegen; }
|
||||
|
@ -765,6 +765,17 @@ class IonBuilder : public MIRGenerator
|
|||
// Constraints for recording dependencies on type information.
|
||||
types::CompilerConstraintList *constraints_;
|
||||
|
||||
mozilla::Maybe<AutoLockForCompilation> lock_;
|
||||
|
||||
void lock() {
|
||||
if (!analysisContext)
|
||||
lock_.construct(compartment);
|
||||
}
|
||||
void unlock() {
|
||||
if (!analysisContext)
|
||||
lock_.destroy();
|
||||
}
|
||||
|
||||
// Basic analysis information about the script.
|
||||
BytecodeAnalysis analysis_;
|
||||
BytecodeAnalysis &analysis() {
|
||||
|
|
|
@ -468,7 +468,7 @@ GeneratePrototypeGuards(JSContext *cx, IonScript *ion, MacroAssembler &masm, JSO
|
|||
// Note: objectReg and scratchReg may be the same register, so we cannot
|
||||
// use objectReg in the rest of this function.
|
||||
masm.loadPtr(Address(objectReg, JSObject::offsetOfType()), scratchReg);
|
||||
Address proto(scratchReg, offsetof(types::TypeObject, proto));
|
||||
Address proto(scratchReg, types::TypeObject::offsetOfProto());
|
||||
masm.branchNurseryPtr(Assembler::NotEqual, proto,
|
||||
ImmMaybeNurseryPtr(obj->getProto()), failures);
|
||||
}
|
||||
|
@ -796,11 +796,7 @@ GenerateReadSlot(JSContext *cx, IonScript *ion, MacroAssembler &masm,
|
|||
Register lastReg = object;
|
||||
JS_ASSERT(scratchReg != object);
|
||||
while (proto) {
|
||||
Address addrType(lastReg, JSObject::offsetOfType());
|
||||
masm.loadPtr(addrType, scratchReg);
|
||||
Address addrProto(scratchReg, offsetof(types::TypeObject, proto));
|
||||
masm.loadPtr(addrProto, scratchReg);
|
||||
Address addrShape(scratchReg, JSObject::offsetOfShape());
|
||||
masm.loadObjProto(lastReg, scratchReg);
|
||||
|
||||
// Guard the shape of the current prototype.
|
||||
masm.branchPtr(Assembler::NotEqual,
|
||||
|
@ -2584,8 +2580,7 @@ GenerateAddSlot(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &att
|
|||
Shape *protoShape = proto->lastProperty();
|
||||
|
||||
// load next prototype
|
||||
masm.loadPtr(Address(protoReg, JSObject::offsetOfType()), protoReg);
|
||||
masm.loadPtr(Address(protoReg, offsetof(types::TypeObject, proto)), protoReg);
|
||||
masm.loadObjProto(protoReg, protoReg);
|
||||
|
||||
// Ensure that its shape matches.
|
||||
masm.branchTestObjShape(Assembler::NotEqual, protoReg, protoShape, &failuresPopObject);
|
||||
|
|
|
@ -292,12 +292,12 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
}
|
||||
void loadObjClass(Register objReg, Register dest) {
|
||||
loadPtr(Address(objReg, JSObject::offsetOfType()), dest);
|
||||
loadPtr(Address(dest, offsetof(types::TypeObject, clasp)), dest);
|
||||
loadPtr(Address(dest, types::TypeObject::offsetOfClasp()), dest);
|
||||
}
|
||||
void branchTestObjClass(Condition cond, Register obj, Register scratch, const js::Class *clasp,
|
||||
Label *label) {
|
||||
loadPtr(Address(obj, JSObject::offsetOfType()), scratch);
|
||||
branchPtr(cond, Address(scratch, offsetof(types::TypeObject, clasp)), ImmPtr(clasp), label);
|
||||
branchPtr(cond, Address(scratch, types::TypeObject::offsetOfClasp()), ImmPtr(clasp), label);
|
||||
}
|
||||
void branchTestObjShape(Condition cond, Register obj, const Shape *shape, Label *label) {
|
||||
branchPtr(cond, Address(obj, JSObject::offsetOfShape()), ImmGCPtr(shape), label);
|
||||
|
@ -353,7 +353,7 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
|
||||
void loadObjProto(Register obj, Register dest) {
|
||||
loadPtr(Address(obj, JSObject::offsetOfType()), dest);
|
||||
loadPtr(Address(dest, offsetof(types::TypeObject, proto)), dest);
|
||||
loadPtr(Address(dest, types::TypeObject::offsetOfProto()), dest);
|
||||
}
|
||||
|
||||
void loadStringLength(Register str, Register dest) {
|
||||
|
|
|
@ -2929,7 +2929,13 @@ jit::PropertyReadNeedsTypeBarrier(JSContext *propertycx,
|
|||
// If this access has never executed, try to add types to the observed set
|
||||
// according to any property which exists on the object or its prototype.
|
||||
if (updateObserved && observed->empty() && name) {
|
||||
JSObject *obj = object->singleton() ? object->singleton() : object->proto().toObjectOrNull();
|
||||
JSObject *obj;
|
||||
if (object->singleton())
|
||||
obj = object->singleton();
|
||||
else if (object->hasTenuredProto())
|
||||
obj = object->proto().toObjectOrNull();
|
||||
else
|
||||
obj = nullptr;
|
||||
|
||||
while (obj) {
|
||||
if (!obj->getClass()->isNative())
|
||||
|
@ -2953,6 +2959,8 @@ jit::PropertyReadNeedsTypeBarrier(JSContext *propertycx,
|
|||
}
|
||||
}
|
||||
|
||||
if (!obj->hasTenuredProto())
|
||||
break;
|
||||
obj = obj->getProto();
|
||||
}
|
||||
}
|
||||
|
@ -3004,7 +3012,11 @@ jit::PropertyReadOnPrototypeNeedsTypeBarrier(types::CompilerConstraintList *cons
|
|||
types::TypeObjectKey *object = types->getObject(i);
|
||||
if (!object)
|
||||
continue;
|
||||
while (object->proto().isObject()) {
|
||||
while (true) {
|
||||
if (!object->hasTenuredProto())
|
||||
return true;
|
||||
if (!object->proto().isObject())
|
||||
break;
|
||||
object = types::TypeObjectKey::get(object->proto().toObject());
|
||||
if (PropertyReadNeedsTypeBarrier(constraints, object, name, observed))
|
||||
return true;
|
||||
|
|
|
@ -946,7 +946,7 @@ AssertValidObjectPtr(JSContext *cx, JSObject *obj)
|
|||
JS_ASSERT(obj->runtimeFromMainThread() == cx->runtime());
|
||||
|
||||
JS_ASSERT_IF(!obj->hasLazyType(),
|
||||
obj->type()->clasp == obj->lastProperty()->getObjectClass());
|
||||
obj->type()->clasp() == obj->lastProperty()->getObjectClass());
|
||||
|
||||
if (obj->isTenured()) {
|
||||
JS_ASSERT(obj->isAligned());
|
||||
|
|
|
@ -1725,7 +1725,7 @@ CodeGeneratorX86Shared::visitGuardClass(LGuardClass *guard)
|
|||
Register tmp = ToRegister(guard->tempInt());
|
||||
|
||||
masm.loadPtr(Address(obj, JSObject::offsetOfType()), tmp);
|
||||
masm.cmpPtr(Operand(tmp, offsetof(types::TypeObject, clasp)), ImmPtr(guard->mir()->getClass()));
|
||||
masm.cmpPtr(Operand(tmp, types::TypeObject::offsetOfClasp()), ImmPtr(guard->mir()->getClass()));
|
||||
if (!bailoutIf(Assembler::NotEqual, guard->snapshot()))
|
||||
return false;
|
||||
return true;
|
||||
|
|
|
@ -116,6 +116,7 @@ js::ExistingCloneFunctionAtCallsite(const CallsiteCloneTable &table, JSFunction
|
|||
JS_ASSERT(fun->nonLazyScript()->shouldCloneAtCallsite());
|
||||
JS_ASSERT(!fun->nonLazyScript()->enclosingStaticScope());
|
||||
JS_ASSERT(types::UseNewTypeForClone(fun));
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
|
||||
/*
|
||||
* If we start allocating function objects in the nursery, then the callsite
|
||||
|
@ -126,7 +127,7 @@ js::ExistingCloneFunctionAtCallsite(const CallsiteCloneTable &table, JSFunction
|
|||
if (!table.initialized())
|
||||
return nullptr;
|
||||
|
||||
CallsiteCloneTable::Ptr p = table.lookup(CallsiteCloneKey(fun, script, script->pcToOffset(pc)));
|
||||
CallsiteCloneTable::Ptr p = table.readonlyThreadsafeLookup(CallsiteCloneKey(fun, script, script->pcToOffset(pc)));
|
||||
if (p)
|
||||
return p->value();
|
||||
|
||||
|
@ -153,6 +154,8 @@ js::CloneFunctionAtCallsite(JSContext *cx, HandleFunction fun, HandleScript scri
|
|||
typedef CallsiteCloneKey Key;
|
||||
typedef CallsiteCloneTable Table;
|
||||
|
||||
AutoLockForCompilation lock(cx);
|
||||
|
||||
Table &table = cx->compartment()->callsiteClones;
|
||||
if (!table.initialized() && !table.init())
|
||||
return nullptr;
|
||||
|
|
|
@ -32,7 +32,10 @@ js_ReportOverRecursed(js::ThreadSafeContext *cx);
|
|||
|
||||
namespace js {
|
||||
|
||||
namespace jit { class IonContext; }
|
||||
namespace jit {
|
||||
class IonContext;
|
||||
class CompileCompartment;
|
||||
}
|
||||
|
||||
struct CallsiteCloneKey {
|
||||
/* The original function that we are cloning. */
|
||||
|
@ -1038,7 +1041,9 @@ class AutoLockForExclusiveAccess
|
|||
if (runtime->numExclusiveThreads) {
|
||||
runtime->assertCanLock(JSRuntime::ExclusiveAccessLock);
|
||||
PR_Lock(runtime->exclusiveAccessLock);
|
||||
#ifdef DEBUG
|
||||
runtime->exclusiveAccessOwner = PR_GetCurrentThread();
|
||||
#endif
|
||||
} else {
|
||||
JS_ASSERT(!runtime->mainThreadHasExclusiveAccess);
|
||||
runtime->mainThreadHasExclusiveAccess = true;
|
||||
|
@ -1057,9 +1062,7 @@ class AutoLockForExclusiveAccess
|
|||
~AutoLockForExclusiveAccess() {
|
||||
if (runtime->numExclusiveThreads) {
|
||||
JS_ASSERT(runtime->exclusiveAccessOwner == PR_GetCurrentThread());
|
||||
#ifdef DEBUG
|
||||
runtime->exclusiveAccessOwner = nullptr;
|
||||
#endif
|
||||
PR_Unlock(runtime->exclusiveAccessLock);
|
||||
} else {
|
||||
JS_ASSERT(runtime->mainThreadHasExclusiveAccess);
|
||||
|
@ -1083,6 +1086,69 @@ class AutoLockForExclusiveAccess
|
|||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
class AutoLockForCompilation
|
||||
{
|
||||
#ifdef JS_WORKER_THREADS
|
||||
JSRuntime *runtime;
|
||||
|
||||
void init(JSRuntime *rt) {
|
||||
runtime = rt;
|
||||
if (runtime->numCompilationThreads) {
|
||||
runtime->assertCanLock(JSRuntime::CompilationLock);
|
||||
PR_Lock(runtime->compilationLock);
|
||||
#ifdef DEBUG
|
||||
runtime->compilationLockOwner = PR_GetCurrentThread();
|
||||
#endif
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
JS_ASSERT(!runtime->mainThreadHasCompilationLock);
|
||||
runtime->mainThreadHasCompilationLock = true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
AutoLockForCompilation(ExclusiveContext *cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
if (cx->isJSContext())
|
||||
init(cx->asJSContext()->runtime());
|
||||
else
|
||||
runtime = nullptr;
|
||||
}
|
||||
AutoLockForCompilation(jit::CompileCompartment *compartment MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
|
||||
~AutoLockForCompilation() {
|
||||
if (runtime) {
|
||||
if (runtime->numCompilationThreads) {
|
||||
JS_ASSERT(runtime->compilationLockOwner == PR_GetCurrentThread());
|
||||
#ifdef DEBUG
|
||||
runtime->compilationLockOwner = nullptr;
|
||||
#endif
|
||||
PR_Unlock(runtime->compilationLock);
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
JS_ASSERT(runtime->mainThreadHasCompilationLock);
|
||||
runtime->mainThreadHasCompilationLock = false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#else // JS_WORKER_THREADS
|
||||
public:
|
||||
AutoLockForCompilation(ExclusiveContext *cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
AutoLockForCompilation(jit::CompileCompartment *compartment MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
~AutoLockForCompilation() {
|
||||
// An empty destructor is needed to avoid warnings from clang about
|
||||
// unused local variables of this type.
|
||||
}
|
||||
#endif // JS_WORKER_THREADS
|
||||
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
|
|
@ -338,7 +338,7 @@ JSCompartment::wrap(JSContext *cx, MutableHandleObject obj, HandleObject existin
|
|||
return true;
|
||||
}
|
||||
|
||||
RootedObject proto(cx, Proxy::LazyProto);
|
||||
RootedObject proto(cx, TaggedProto::LazyProto);
|
||||
RootedObject existing(cx, existingArg);
|
||||
if (existing) {
|
||||
/* Is it possible to reuse |existing|? */
|
||||
|
|
|
@ -1124,25 +1124,21 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti
|
|||
// THING_ROOT_LAZY_SCRIPT).
|
||||
AutoSuppressGC suppressGC(cx);
|
||||
|
||||
fun->flags_ &= ~INTERPRETED_LAZY;
|
||||
fun->flags_ |= INTERPRETED;
|
||||
|
||||
RootedScript script(cx, lazy->maybeScript());
|
||||
|
||||
if (script) {
|
||||
fun->initScript(script);
|
||||
AutoLockForCompilation lock(cx);
|
||||
fun->setUnlazifiedScript(script);
|
||||
return true;
|
||||
}
|
||||
|
||||
fun->initScript(nullptr);
|
||||
|
||||
if (fun != lazy->function()) {
|
||||
script = lazy->function()->getOrCreateScript(cx);
|
||||
if (!script) {
|
||||
fun->initLazyScript(lazy);
|
||||
if (!script)
|
||||
return false;
|
||||
}
|
||||
fun->initScript(script);
|
||||
|
||||
AutoLockForCompilation lock(cx);
|
||||
fun->setUnlazifiedScript(script);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1162,17 +1158,19 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti
|
|||
if (script) {
|
||||
RootedObject enclosingScope(cx, lazy->enclosingScope());
|
||||
RootedScript clonedScript(cx, CloneScript(cx, enclosingScope, fun, script));
|
||||
if (!clonedScript) {
|
||||
fun->initLazyScript(lazy);
|
||||
if (!clonedScript)
|
||||
return false;
|
||||
}
|
||||
|
||||
clonedScript->setSourceObject(lazy->sourceObject());
|
||||
|
||||
fun->initAtom(script->function()->displayAtom());
|
||||
fun->initScript(clonedScript);
|
||||
clonedScript->setFunction(fun);
|
||||
|
||||
{
|
||||
AutoLockForCompilation lock(cx);
|
||||
fun->setUnlazifiedScript(clonedScript);
|
||||
}
|
||||
|
||||
CallNewScriptHook(cx, clonedScript, fun);
|
||||
|
||||
lazy->initScript(clonedScript);
|
||||
|
@ -1184,18 +1182,14 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti
|
|||
// Parse and compile the script from source.
|
||||
SourceDataCache::AutoSuppressPurge asp(cx);
|
||||
const jschar *chars = lazy->source()->chars(cx, asp);
|
||||
if (!chars) {
|
||||
fun->initLazyScript(lazy);
|
||||
if (!chars)
|
||||
return false;
|
||||
}
|
||||
|
||||
const jschar *lazyStart = chars + lazy->begin();
|
||||
size_t lazyLength = lazy->end() - lazy->begin();
|
||||
|
||||
if (!frontend::CompileLazyFunction(cx, lazy, lazyStart, lazyLength)) {
|
||||
fun->initLazyScript(lazy);
|
||||
if (!frontend::CompileLazyFunction(cx, lazy, lazyStart, lazyLength))
|
||||
return false;
|
||||
}
|
||||
|
||||
script = fun->nonLazyScript();
|
||||
|
||||
|
|
|
@ -123,8 +123,6 @@ class JSFunction : public JSObject
|
|||
|
||||
/* Possible attributes of an interpreted function: */
|
||||
bool isFunctionPrototype() const { return flags() & IS_FUN_PROTO; }
|
||||
bool isInterpretedLazy() const { return flags() & INTERPRETED_LAZY; }
|
||||
bool hasScript() const { return flags() & INTERPRETED; }
|
||||
bool isExprClosure() const { return flags() & EXPR_CLOSURE; }
|
||||
bool hasGuessedAtom() const { return flags() & HAS_GUESSED_ATOM; }
|
||||
bool isLambda() const { return flags() & LAMBDA; }
|
||||
|
@ -136,6 +134,17 @@ class JSFunction : public JSObject
|
|||
return flags() & SH_WRAPPABLE;
|
||||
}
|
||||
|
||||
// Functions can change between being lazily interpreted and having scripts
|
||||
// when under the compilation lock.
|
||||
bool isInterpretedLazy() const {
|
||||
JS_ASSERT(js::CurrentThreadCanReadCompilationData());
|
||||
return flags() & INTERPRETED_LAZY;
|
||||
}
|
||||
bool hasScript() const {
|
||||
JS_ASSERT(js::CurrentThreadCanReadCompilationData());
|
||||
return flags() & INTERPRETED;
|
||||
}
|
||||
|
||||
bool hasJITCode() const {
|
||||
if (!hasScript())
|
||||
return false;
|
||||
|
@ -321,6 +330,7 @@ class JSFunction : public JSObject
|
|||
|
||||
JSScript *nonLazyScript() const {
|
||||
JS_ASSERT(hasScript());
|
||||
JS_ASSERT(js::CurrentThreadCanReadCompilationData());
|
||||
return u.i.s.script_;
|
||||
}
|
||||
|
||||
|
@ -331,11 +341,13 @@ class JSFunction : public JSObject
|
|||
|
||||
js::LazyScript *lazyScript() const {
|
||||
JS_ASSERT(isInterpretedLazy() && u.i.s.lazy_);
|
||||
JS_ASSERT(js::CurrentThreadCanReadCompilationData());
|
||||
return u.i.s.lazy_;
|
||||
}
|
||||
|
||||
js::LazyScript *lazyScriptOrNull() const {
|
||||
JS_ASSERT(isInterpretedLazy());
|
||||
JS_ASSERT(js::CurrentThreadCanReadCompilationData());
|
||||
return u.i.s.lazy_;
|
||||
}
|
||||
|
||||
|
@ -357,15 +369,25 @@ class JSFunction : public JSObject
|
|||
bool isStarGenerator() const { return generatorKind() == js::StarGenerator; }
|
||||
|
||||
void setScript(JSScript *script_) {
|
||||
JS_ASSERT(isInterpreted());
|
||||
JS_ASSERT(hasScript());
|
||||
mutableScript() = script_;
|
||||
}
|
||||
|
||||
void initScript(JSScript *script_) {
|
||||
JS_ASSERT(isInterpreted());
|
||||
JS_ASSERT(hasScript());
|
||||
mutableScript().init(script_);
|
||||
}
|
||||
|
||||
void setUnlazifiedScript(JSScript *script) {
|
||||
// Note: createScriptForLazilyInterpretedFunction triggers a barrier on
|
||||
// lazy script before it is overwritten here.
|
||||
JS_ASSERT(js::CurrentThreadCanWriteCompilationData());
|
||||
JS_ASSERT(isInterpretedLazy());
|
||||
flags_ &= ~INTERPRETED_LAZY;
|
||||
flags_ |= INTERPRETED;
|
||||
initScript(script);
|
||||
}
|
||||
|
||||
void initLazyScript(js::LazyScript *lazy) {
|
||||
JS_ASSERT(isInterpreted());
|
||||
flags_ &= ~INTERPRETED;
|
||||
|
|
|
@ -685,6 +685,8 @@ TypeScript::FreezeTypeSets(CompilerConstraintList *constraints, JSScript *script
|
|||
TemporaryTypeSet **pArgTypes,
|
||||
TemporaryTypeSet **pBytecodeTypes)
|
||||
{
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
|
||||
LifoAlloc *alloc = constraints->alloc();
|
||||
StackTypeSet *existing = script->types->typeArray();
|
||||
|
||||
|
@ -791,13 +793,26 @@ CompilerConstraintInstance<T>::generateTypeConstraint(JSContext *cx, RecompileIn
|
|||
const Class *
|
||||
TypeObjectKey::clasp()
|
||||
{
|
||||
return isTypeObject() ? asTypeObject()->clasp : asSingleObject()->getClass();
|
||||
return isTypeObject() ? asTypeObject()->clasp() : asSingleObject()->getClass();
|
||||
}
|
||||
|
||||
TaggedProto
|
||||
TypeObjectKey::proto()
|
||||
{
|
||||
return isTypeObject() ? TaggedProto(asTypeObject()->proto) : asSingleObject()->getTaggedProto();
|
||||
JS_ASSERT(hasTenuredProto());
|
||||
return isTypeObject() ? asTypeObject()->proto() : asSingleObject()->getTaggedProto();
|
||||
}
|
||||
|
||||
bool
|
||||
ObjectImpl::hasTenuredProto() const
|
||||
{
|
||||
return type_->hasTenuredProto();
|
||||
}
|
||||
|
||||
bool
|
||||
TypeObjectKey::hasTenuredProto()
|
||||
{
|
||||
return isTypeObject() ? asTypeObject()->hasTenuredProto() : asSingleObject()->hasTenuredProto();
|
||||
}
|
||||
|
||||
JSObject *
|
||||
|
@ -836,6 +851,7 @@ HeapTypeSetKey
|
|||
TypeObjectKey::property(jsid id)
|
||||
{
|
||||
JS_ASSERT(!unknownProperties());
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
|
||||
HeapTypeSetKey property;
|
||||
property.object_ = this;
|
||||
|
@ -1429,8 +1445,10 @@ ObjectStateChange(ExclusiveContext *cxArg, TypeObject *object, bool markingUnkno
|
|||
HeapTypeSet *types = object->maybeGetProperty(JSID_EMPTY);
|
||||
|
||||
/* Mark as unknown after getting the types, to avoid assertion. */
|
||||
if (markingUnknown)
|
||||
object->flags |= OBJECT_FLAG_DYNAMIC_MASK | OBJECT_FLAG_UNKNOWN_PROPERTIES;
|
||||
if (markingUnknown) {
|
||||
AutoLockForCompilation lock(cxArg);
|
||||
object->addFlags(OBJECT_FLAG_DYNAMIC_MASK | OBJECT_FLAG_UNKNOWN_PROPERTIES);
|
||||
}
|
||||
|
||||
if (types) {
|
||||
if (JSContext *cx = cxArg->maybeJSContext()) {
|
||||
|
@ -1678,6 +1696,9 @@ TemporaryTypeSet::getCommonPrototype()
|
|||
if (!object)
|
||||
continue;
|
||||
|
||||
if (!object->hasTenuredProto())
|
||||
return nullptr;
|
||||
|
||||
TaggedProto nproto = object->proto();
|
||||
if (proto) {
|
||||
if (nproto != proto)
|
||||
|
@ -1737,18 +1758,24 @@ TypeZone::init(JSContext *cx)
|
|||
}
|
||||
|
||||
TypeObject *
|
||||
TypeCompartment::newTypeObject(ExclusiveContext *cx, const Class *clasp, Handle<TaggedProto> proto, bool unknown)
|
||||
TypeCompartment::newTypeObject(ExclusiveContext *cx, const Class *clasp, Handle<TaggedProto> proto,
|
||||
TypeObjectFlags initialFlags)
|
||||
{
|
||||
JS_ASSERT_IF(proto.isObject(), cx->isInsideCurrentCompartment(proto.toObject()));
|
||||
|
||||
if (!cx->typeInferenceEnabled())
|
||||
initialFlags |= OBJECT_FLAG_UNKNOWN_MASK;
|
||||
|
||||
if (cx->isJSContext()) {
|
||||
if (proto.isObject() && IsInsideNursery(cx->asJSContext()->runtime(), proto.toObject()))
|
||||
initialFlags |= OBJECT_FLAG_NURSERY_PROTO;
|
||||
}
|
||||
|
||||
TypeObject *object = gc::NewGCThing<TypeObject, CanGC>(cx, gc::FINALIZE_TYPE_OBJECT,
|
||||
sizeof(TypeObject), gc::TenuredHeap);
|
||||
if (!object)
|
||||
return nullptr;
|
||||
new(object) TypeObject(clasp, proto, unknown);
|
||||
|
||||
if (!cx->typeInferenceEnabled())
|
||||
object->flags |= OBJECT_FLAG_UNKNOWN_MASK;
|
||||
new(object) TypeObject(clasp, proto, initialFlags);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
@ -1871,12 +1898,11 @@ TypeCompartment::addAllocationSiteTypeObject(JSContext *cx, AllocationSiteKey ke
|
|||
return nullptr;
|
||||
|
||||
Rooted<TaggedProto> tagged(cx, TaggedProto(proto));
|
||||
res = newTypeObject(cx, GetClassForProtoKey(key.kind), tagged);
|
||||
res = newTypeObject(cx, GetClassForProtoKey(key.kind), tagged, OBJECT_FLAG_FROM_ALLOCATION_SITE);
|
||||
if (!res) {
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
return nullptr;
|
||||
}
|
||||
res->flags |= OBJECT_FLAG_FROM_ALLOCATION_SITE;
|
||||
key.script = keyScript;
|
||||
}
|
||||
|
||||
|
@ -2010,6 +2036,8 @@ PrototypeHasIndexedProperty(CompilerConstraintList *constraints, JSObject *obj)
|
|||
HeapTypeSetKey index = type->property(JSID_VOID);
|
||||
if (index.configured(constraints) || index.isOwnProperty(constraints))
|
||||
return true;
|
||||
if (!obj->hasTenuredProto())
|
||||
return true;
|
||||
obj = obj->getProto();
|
||||
} while (obj);
|
||||
|
||||
|
@ -2175,10 +2203,9 @@ void
|
|||
TypeCompartment::markSetsUnknown(JSContext *cx, TypeObject *target)
|
||||
{
|
||||
JS_ASSERT(this == &cx->compartment()->types);
|
||||
JS_ASSERT(!(target->flags & OBJECT_FLAG_SETS_MARKED_UNKNOWN));
|
||||
JS_ASSERT(!(target->flags() & OBJECT_FLAG_SETS_MARKED_UNKNOWN));
|
||||
JS_ASSERT(!target->singleton);
|
||||
JS_ASSERT(target->unknownProperties());
|
||||
target->flags |= OBJECT_FLAG_SETS_MARKED_UNKNOWN;
|
||||
|
||||
AutoEnterAnalysis enter(cx);
|
||||
|
||||
|
@ -2219,6 +2246,9 @@ TypeCompartment::markSetsUnknown(JSContext *cx, TypeObject *target)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
AutoLockForCompilation lock(cx);
|
||||
target->addFlags(OBJECT_FLAG_SETS_MARKED_UNKNOWN);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2511,7 +2541,7 @@ TypeCompartment::fixObjectType(ExclusiveContext *cx, JSObject *obj)
|
|||
ObjectTypeTable::AddPtr p = objectTypeTable->lookupForAdd(lookup);
|
||||
|
||||
if (p) {
|
||||
JS_ASSERT(obj->getProto() == p->value().object->proto);
|
||||
JS_ASSERT(obj->getProto() == p->value().object->proto().toObject());
|
||||
JS_ASSERT(obj->lastProperty() == p->value().shape);
|
||||
|
||||
UpdateObjectTableEntryTypes(cx, p->value(), properties.begin(), properties.length());
|
||||
|
@ -2614,7 +2644,7 @@ TypeCompartment::newTypedObject(JSContext *cx, IdValuePair *properties, size_t n
|
|||
cx->clearPendingException();
|
||||
return nullptr;
|
||||
}
|
||||
JS_ASSERT(obj->getProto() == p->value().object->proto);
|
||||
JS_ASSERT(obj->getProto() == p->value().object->proto().toObject());
|
||||
|
||||
RootedShape shape(cx, p->value().shape);
|
||||
if (!JSObject::setLastProperty(cx, obj, shape)) {
|
||||
|
@ -2635,6 +2665,36 @@ TypeCompartment::newTypedObject(JSContext *cx, IdValuePair *properties, size_t n
|
|||
// TypeObject
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
TypeObject::assertCanAccessProto()
|
||||
{
|
||||
// The proto pointer for type objects representing singletons may move.
|
||||
JS_ASSERT_IF(singleton, CurrentThreadCanReadCompilationData());
|
||||
|
||||
// Any proto pointer which is in the nursery may be moved, and may not be
|
||||
// accessed during off thread compilation.
|
||||
#if defined(JSGC_GENERATIONAL) && defined(JS_WORKER_THREADS)
|
||||
PerThreadData *pt = TlsPerThreadData.get();
|
||||
TaggedProto proto(proto_);
|
||||
JS_ASSERT_IF(proto.isObject() && !proto.toObject()->isTenured(),
|
||||
!pt || !pt->ionCompiling);
|
||||
#endif
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
void
|
||||
TypeObject::setProto(JSContext *cx, TaggedProto proto)
|
||||
{
|
||||
JS_ASSERT(CurrentThreadCanWriteCompilationData());
|
||||
JS_ASSERT(singleton);
|
||||
|
||||
if (proto.isObject() && IsInsideNursery(cx->runtime(), proto.toObject()))
|
||||
addFlags(OBJECT_FLAG_NURSERY_PROTO);
|
||||
|
||||
setProtoUnchecked(proto);
|
||||
}
|
||||
|
||||
static inline void
|
||||
UpdatePropertyType(ExclusiveContext *cx, HeapTypeSet *types, JSObject *obj, Shape *shape,
|
||||
bool indexed)
|
||||
|
@ -2644,7 +2704,8 @@ UpdatePropertyType(ExclusiveContext *cx, HeapTypeSet *types, JSObject *obj, Shap
|
|||
|
||||
if (shape->hasGetterValue() || shape->hasSetterValue()) {
|
||||
types->setConfiguredProperty(cx);
|
||||
types->addType(cx, Type::UnknownType());
|
||||
if (!types->TypeSet::addType(Type::UnknownType(), &cx->typeLifoAlloc()))
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
} else if (shape->hasDefaultGetter() && shape->hasSlot()) {
|
||||
if (!indexed && types->canSetDefinite(shape->slot()))
|
||||
types->setDefinite(shape->slot());
|
||||
|
@ -2658,7 +2719,8 @@ UpdatePropertyType(ExclusiveContext *cx, HeapTypeSet *types, JSObject *obj, Shap
|
|||
*/
|
||||
if (indexed || !value.isUndefined() || !CanHaveEmptyPropertyTypesForOwnProperty(obj)) {
|
||||
Type type = GetValueType(value);
|
||||
types->addType(cx, type);
|
||||
if (!types->TypeSet::addType(type, &cx->typeLifoAlloc()))
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2696,7 +2758,8 @@ TypeObject::addProperty(ExclusiveContext *cx, jsid id, Property **pprop)
|
|||
const Value &value = singleton->getDenseElement(i);
|
||||
if (!value.isMagic(JS_ELEMENTS_HOLE)) {
|
||||
Type type = GetValueType(value);
|
||||
base->types.addType(cx, type);
|
||||
if (!base->types.TypeSet::addType(type, &cx->typeLifoAlloc()))
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
}
|
||||
}
|
||||
} else if (!JSID_IS_EMPTY(id)) {
|
||||
|
@ -2871,7 +2934,7 @@ TypeObject::markStateChange(ExclusiveContext *cxArg)
|
|||
void
|
||||
TypeObject::setFlags(ExclusiveContext *cx, TypeObjectFlags flags)
|
||||
{
|
||||
if ((this->flags & flags) == flags)
|
||||
if (hasAllFlags(flags))
|
||||
return;
|
||||
|
||||
AutoEnterAnalysis enter(cx);
|
||||
|
@ -2882,7 +2945,10 @@ TypeObject::setFlags(ExclusiveContext *cx, TypeObjectFlags flags)
|
|||
singleton->lastProperty()->hasObjectFlag(BaseShape::ITERATED_SINGLETON));
|
||||
}
|
||||
|
||||
this->flags |= flags;
|
||||
{
|
||||
AutoLockForCompilation lock(cx);
|
||||
addFlags(flags);
|
||||
}
|
||||
|
||||
InferSpew(ISpewOps, "%s: setFlags 0x%x", TypeObjectString(this), flags);
|
||||
|
||||
|
@ -2897,7 +2963,7 @@ TypeObject::markUnknown(ExclusiveContext *cx)
|
|||
JS_ASSERT(cx->compartment()->activeAnalysis);
|
||||
JS_ASSERT(!unknownProperties());
|
||||
|
||||
if (!(flags & OBJECT_FLAG_ADDENDUM_CLEARED))
|
||||
if (!(flags() & OBJECT_FLAG_ADDENDUM_CLEARED))
|
||||
clearAddendum(cx);
|
||||
|
||||
InferSpew(ISpewOps, "UnknownProperties: %s", TypeObjectString(this));
|
||||
|
@ -2926,8 +2992,11 @@ TypeObject::markUnknown(ExclusiveContext *cx)
|
|||
void
|
||||
TypeObject::clearAddendum(ExclusiveContext *cx)
|
||||
{
|
||||
JS_ASSERT(!(flags & OBJECT_FLAG_ADDENDUM_CLEARED));
|
||||
flags |= OBJECT_FLAG_ADDENDUM_CLEARED;
|
||||
JS_ASSERT(!(flags() & OBJECT_FLAG_ADDENDUM_CLEARED));
|
||||
{
|
||||
AutoLockForCompilation lock(cx);
|
||||
addFlags(OBJECT_FLAG_ADDENDUM_CLEARED);
|
||||
}
|
||||
|
||||
/*
|
||||
* It is possible for the object to not have a new script or other
|
||||
|
@ -3072,11 +3141,11 @@ TypeObject::clearTypedObjectAddendum(ExclusiveContext *cx)
|
|||
void
|
||||
TypeObject::print()
|
||||
{
|
||||
TaggedProto tagged(proto);
|
||||
TaggedProto tagged(proto());
|
||||
fprintf(stderr, "%s : %s",
|
||||
TypeObjectString(this),
|
||||
tagged.isObject() ? TypeString(Type::ObjectType(proto))
|
||||
: (tagged.isLazy() ? "(lazy)" : "(null)"));
|
||||
TypeObjectString(this),
|
||||
tagged.isObject() ? TypeString(Type::ObjectType(tagged.toObject()))
|
||||
: (tagged.isLazy() ? "(lazy)" : "(null)"));
|
||||
|
||||
if (unknownProperties()) {
|
||||
fprintf(stderr, " unknown");
|
||||
|
@ -3142,7 +3211,7 @@ class TypeConstraintClearDefiniteGetterSetter : public TypeConstraint
|
|||
* non-writable, both of which are indicated by the source type set
|
||||
* being marked as configured.
|
||||
*/
|
||||
if (!(object->flags & OBJECT_FLAG_ADDENDUM_CLEARED) && source->configuredProperty())
|
||||
if (!(object->flags() & OBJECT_FLAG_ADDENDUM_CLEARED) && source->configuredProperty())
|
||||
object->clearAddendum(cx);
|
||||
}
|
||||
|
||||
|
@ -3166,7 +3235,7 @@ types::AddClearDefiniteGetterSetterForPrototypeChain(JSContext *cx, TypeObject *
|
|||
* a permanent property in any transitive prototype, the definite
|
||||
* properties get cleared from the type.
|
||||
*/
|
||||
RootedObject parent(cx, type->proto);
|
||||
RootedObject parent(cx, type->proto().toObjectOrNull());
|
||||
while (parent) {
|
||||
TypeObject *parentObject = parent->getType(cx);
|
||||
if (!parentObject || parentObject->unknownProperties())
|
||||
|
@ -3196,7 +3265,7 @@ class TypeConstraintClearDefiniteSingle : public TypeConstraint
|
|||
const char *kind() { return "clearDefiniteSingle"; }
|
||||
|
||||
void newType(JSContext *cx, TypeSet *source, Type type) {
|
||||
if (object->flags & OBJECT_FLAG_ADDENDUM_CLEARED)
|
||||
if (object->flags() & OBJECT_FLAG_ADDENDUM_CLEARED)
|
||||
return;
|
||||
|
||||
if (source->baseFlags() || source->getObjectCount() > 1)
|
||||
|
@ -3279,9 +3348,9 @@ CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun)
|
|||
}
|
||||
|
||||
if (baseobj->slotSpan() == 0 ||
|
||||
!!(type->flags & OBJECT_FLAG_ADDENDUM_CLEARED))
|
||||
!!(type->flags() & OBJECT_FLAG_ADDENDUM_CLEARED))
|
||||
{
|
||||
if (type->addendum)
|
||||
if (type->hasNewScript())
|
||||
type->clearAddendum(cx);
|
||||
return;
|
||||
}
|
||||
|
@ -3296,8 +3365,8 @@ CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun)
|
|||
type->clearAddendum(cx);
|
||||
return;
|
||||
}
|
||||
JS_ASSERT(!type->addendum);
|
||||
JS_ASSERT(!(type->flags & OBJECT_FLAG_ADDENDUM_CLEARED));
|
||||
JS_ASSERT(!type->hasNewScript());
|
||||
JS_ASSERT(!(type->flags() & OBJECT_FLAG_ADDENDUM_CLEARED));
|
||||
|
||||
gc::AllocKind kind = gc::GetGCObjectKind(baseobj->slotSpan());
|
||||
|
||||
|
@ -3336,7 +3405,11 @@ CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun)
|
|||
newScript = (TypeNewScript *) cx->calloc_(numBytes);
|
||||
#endif
|
||||
new (newScript) TypeNewScript();
|
||||
type->addendum = newScript;
|
||||
|
||||
{
|
||||
AutoLockForCompilation lock(cx);
|
||||
type->setAddendum(newScript);
|
||||
}
|
||||
|
||||
if (!newScript) {
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
|
@ -3633,8 +3706,11 @@ JSObject::splicePrototype(JSContext *cx, const Class *clasp, Handle<TaggedProto>
|
|||
return true;
|
||||
}
|
||||
|
||||
type->clasp = clasp;
|
||||
type->proto = proto.raw();
|
||||
{
|
||||
AutoLockForCompilation lock(cx);
|
||||
type->setClasp(clasp);
|
||||
type->setProto(cx, proto);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -3651,8 +3727,22 @@ JSObject::makeLazyType(JSContext *cx, HandleObject obj)
|
|||
if (!fun->getOrCreateScript(cx))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Find flags which need to be specified immediately on the object.
|
||||
// Don't track whether singletons are packed.
|
||||
TypeObjectFlags initialFlags = OBJECT_FLAG_NON_PACKED;
|
||||
|
||||
if (obj->lastProperty()->hasObjectFlag(BaseShape::ITERATED_SINGLETON))
|
||||
initialFlags |= OBJECT_FLAG_ITERATED;
|
||||
|
||||
if (obj->isIndexed())
|
||||
initialFlags |= OBJECT_FLAG_SPARSE_INDEXES;
|
||||
|
||||
if (obj->is<ArrayObject>() && obj->as<ArrayObject>().length() > INT32_MAX)
|
||||
initialFlags |= OBJECT_FLAG_LENGTH_OVERFLOW;
|
||||
|
||||
Rooted<TaggedProto> proto(cx, obj->getTaggedProto());
|
||||
TypeObject *type = cx->compartment()->types.newTypeObject(cx, obj->getClass(), proto);
|
||||
TypeObject *type = cx->compartment()->types.newTypeObject(cx, obj->getClass(), proto, initialFlags);
|
||||
if (!type) {
|
||||
if (cx->typeInferenceEnabled())
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
|
@ -3674,24 +3764,10 @@ JSObject::makeLazyType(JSContext *cx, HandleObject obj)
|
|||
if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpreted())
|
||||
type->interpretedFunction = &obj->as<JSFunction>();
|
||||
|
||||
if (obj->lastProperty()->hasObjectFlag(BaseShape::ITERATED_SINGLETON))
|
||||
type->flags |= OBJECT_FLAG_ITERATED;
|
||||
|
||||
/*
|
||||
* Adjust flags for objects which will have the wrong flags set by just
|
||||
* looking at the class prototype key.
|
||||
*/
|
||||
|
||||
/* Don't track whether singletons are packed. */
|
||||
type->flags |= OBJECT_FLAG_NON_PACKED;
|
||||
|
||||
if (obj->isIndexed())
|
||||
type->flags |= OBJECT_FLAG_SPARSE_INDEXES;
|
||||
|
||||
if (obj->is<ArrayObject>() && obj->as<ArrayObject>().length() > INT32_MAX)
|
||||
type->flags |= OBJECT_FLAG_LENGTH_OVERFLOW;
|
||||
|
||||
obj->type_ = type;
|
||||
{
|
||||
AutoLockForCompilation lock(cx);
|
||||
obj->type_ = type;
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
@ -3707,8 +3783,8 @@ TypeObjectWithNewScriptEntry::hash(const Lookup &lookup)
|
|||
/* static */ inline bool
|
||||
TypeObjectWithNewScriptEntry::match(const TypeObjectWithNewScriptEntry &key, const Lookup &lookup)
|
||||
{
|
||||
return key.object->proto == lookup.matchProto.raw() &&
|
||||
key.object->clasp == lookup.clasp &&
|
||||
return key.object->proto() == lookup.matchProto &&
|
||||
key.object->clasp() == lookup.clasp &&
|
||||
key.newFunction == lookup.newFunction;
|
||||
}
|
||||
|
||||
|
@ -3805,8 +3881,8 @@ ExclusiveContext::getNewType(const Class *clasp, TaggedProto proto, JSFunction *
|
|||
newTypeObjects.lookupForAdd(TypeObjectWithNewScriptSet::Lookup(clasp, proto, fun));
|
||||
if (p) {
|
||||
TypeObject *type = p->object;
|
||||
JS_ASSERT(type->clasp == clasp);
|
||||
JS_ASSERT(type->proto.get() == proto.raw());
|
||||
JS_ASSERT(type->clasp() == clasp);
|
||||
JS_ASSERT(type->proto() == proto);
|
||||
JS_ASSERT_IF(type->hasNewScript(), type->newScript()->fun == fun);
|
||||
return type;
|
||||
}
|
||||
|
@ -3816,13 +3892,19 @@ ExclusiveContext::getNewType(const Class *clasp, TaggedProto proto, JSFunction *
|
|||
if (proto.isObject() && !proto.toObject()->setDelegate(this))
|
||||
return nullptr;
|
||||
|
||||
bool markUnknown =
|
||||
proto.isObject()
|
||||
? proto.toObject()->lastProperty()->hasObjectFlag(BaseShape::NEW_TYPE_UNKNOWN)
|
||||
: true;
|
||||
TypeObjectFlags initialFlags = 0;
|
||||
if (!proto.isObject() || proto.toObject()->lastProperty()->hasObjectFlag(BaseShape::NEW_TYPE_UNKNOWN)) {
|
||||
// The new type is not present in any type sets, so mark the object as
|
||||
// unknown in all type sets it appears in. This allows the prototype of
|
||||
// such objects to mutate freely without triggering an expensive walk of
|
||||
// the compartment's type sets. (While scripts normally don't mutate
|
||||
// __proto__, the browser will for proxies and such, and we need to
|
||||
// accommodate this behavior).
|
||||
initialFlags = OBJECT_FLAG_UNKNOWN_MASK | OBJECT_FLAG_SETS_MARKED_UNKNOWN;
|
||||
}
|
||||
|
||||
Rooted<TaggedProto> protoRoot(this, proto);
|
||||
TypeObject *type = compartment()->types.newTypeObject(this, clasp, protoRoot, markUnknown);
|
||||
TypeObject *type = compartment()->types.newTypeObject(this, clasp, protoRoot, initialFlags);
|
||||
if (!type)
|
||||
return nullptr;
|
||||
|
||||
|
@ -3872,17 +3954,6 @@ ExclusiveContext::getNewType(const Class *clasp, TaggedProto proto, JSFunction *
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The new type is not present in any type sets, so mark the object as
|
||||
* unknown in all type sets it appears in. This allows the prototype of
|
||||
* such objects to mutate freely without triggering an expensive walk of
|
||||
* the compartment's type sets. (While scripts normally don't mutate
|
||||
* __proto__, the browser will for proxies and such, and we need to
|
||||
* accommodate this behavior).
|
||||
*/
|
||||
if (type->unknownProperties())
|
||||
type->flags |= OBJECT_FLAG_SETS_MARKED_UNKNOWN;
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
|
@ -3907,7 +3978,7 @@ ExclusiveContext::getLazyType(const Class *clasp, TaggedProto proto)
|
|||
}
|
||||
|
||||
Rooted<TaggedProto> protoRoot(this, proto);
|
||||
TypeObject *type = compartment()->types.newTypeObject(this, clasp, protoRoot, false);
|
||||
TypeObject *type = compartment()->types.newTypeObject(this, clasp, protoRoot);
|
||||
if (!type)
|
||||
return nullptr;
|
||||
|
||||
|
@ -4159,8 +4230,8 @@ JSCompartment::sweepNewTypeObjectTable(TypeObjectWithNewScriptSet &table)
|
|||
} else if (entry.newFunction && IsObjectAboutToBeFinalized(&entry.newFunction)) {
|
||||
e.removeFront();
|
||||
} else if (entry.object != e.front().object) {
|
||||
TypeObjectWithNewScriptSet::Lookup lookup(entry.object->clasp,
|
||||
entry.object->proto.get(),
|
||||
TypeObjectWithNewScriptSet::Lookup lookup(entry.object->clasp(),
|
||||
entry.object->proto(),
|
||||
entry.newFunction);
|
||||
e.rekeyFront(lookup, entry);
|
||||
}
|
||||
|
@ -4428,7 +4499,7 @@ TypeObject::addTypedObjectAddendum(JSContext *cx,
|
|||
|
||||
JS_ASSERT(repr);
|
||||
|
||||
if (flags & OBJECT_FLAG_ADDENDUM_CLEARED)
|
||||
if (flags() & OBJECT_FLAG_ADDENDUM_CLEARED)
|
||||
return true;
|
||||
|
||||
JS_ASSERT(!unknownProperties());
|
||||
|
|
141
js/src/jsinfer.h
141
js/src/jsinfer.h
|
@ -25,20 +25,38 @@
|
|||
|
||||
namespace js {
|
||||
|
||||
#ifdef DEBUG
|
||||
bool CurrentThreadCanWriteCompilationData();
|
||||
bool CurrentThreadCanReadCompilationData();
|
||||
#endif
|
||||
|
||||
class TypeRepresentation;
|
||||
|
||||
class TaggedProto
|
||||
{
|
||||
public:
|
||||
static JSObject * const LazyProto;
|
||||
|
||||
TaggedProto() : proto(nullptr) {}
|
||||
TaggedProto(JSObject *proto) : proto(proto) {}
|
||||
|
||||
uintptr_t toWord() const { return uintptr_t(proto); }
|
||||
|
||||
inline bool isLazy() const;
|
||||
inline bool isObject() const;
|
||||
inline JSObject *toObject() const;
|
||||
inline JSObject *toObjectOrNull() const;
|
||||
bool isLazy() const {
|
||||
return proto == LazyProto;
|
||||
}
|
||||
bool isObject() const {
|
||||
/* Skip nullptr and LazyProto. */
|
||||
return uintptr_t(proto) > uintptr_t(TaggedProto::LazyProto);
|
||||
}
|
||||
JSObject *toObject() const {
|
||||
JS_ASSERT(isObject());
|
||||
return proto;
|
||||
}
|
||||
JSObject *toObjectOrNull() const {
|
||||
JS_ASSERT(!proto || isObject());
|
||||
return proto;
|
||||
}
|
||||
JSObject *raw() const { return proto; }
|
||||
|
||||
bool operator ==(const TaggedProto &other) { return proto == other.proto; }
|
||||
|
@ -77,10 +95,10 @@ class TaggedProtoOperations
|
|||
|
||||
public:
|
||||
uintptr_t toWord() const { return value()->toWord(); }
|
||||
inline bool isLazy() const;
|
||||
inline bool isObject() const;
|
||||
inline JSObject *toObject() const;
|
||||
inline JSObject *toObjectOrNull() const;
|
||||
inline bool isLazy() const { return value()->isLazy(); }
|
||||
inline bool isObject() const { return value()->isObject(); }
|
||||
inline JSObject *toObject() const { return value()->toObject(); }
|
||||
inline JSObject *toObjectOrNull() const { return value()->toObjectOrNull(); }
|
||||
JSObject *raw() const { return value()->raw(); }
|
||||
};
|
||||
|
||||
|
@ -383,6 +401,12 @@ enum MOZ_ENUM_TYPE(uint32_t) {
|
|||
/* If set, addendum information should not be installed on this object. */
|
||||
OBJECT_FLAG_ADDENDUM_CLEARED = 0x2,
|
||||
|
||||
/*
|
||||
* If set, the object's prototype might be in the nursery and can't be
|
||||
* used during Ion compilation (which may be occurring off thread).
|
||||
*/
|
||||
OBJECT_FLAG_NURSERY_PROTO = 0x4,
|
||||
|
||||
/*
|
||||
* Whether we have ensured all type sets in the compartment contain
|
||||
* ANYOBJECT instead of this object.
|
||||
|
@ -503,7 +527,7 @@ class TypeSet
|
|||
static TemporaryTypeSet *unionSets(TypeSet *a, TypeSet *b, LifoAlloc *alloc);
|
||||
|
||||
/* Add a type to this set using the specified allocator. */
|
||||
inline bool addType(Type type, LifoAlloc *alloc, bool *padded = nullptr);
|
||||
inline bool addType(Type type, LifoAlloc *alloc);
|
||||
|
||||
/* Get a list of all types in this set. */
|
||||
typedef Vector<Type, 1, SystemAllocPolicy> TypeList;
|
||||
|
@ -857,11 +881,45 @@ struct TypeTypedObject : public TypeObjectAddendum
|
|||
/* Type information about an object accessed by a script. */
|
||||
struct TypeObject : gc::BarrieredCell<TypeObject>
|
||||
{
|
||||
/* Class shared by objects using this type. */
|
||||
const Class *clasp;
|
||||
private:
|
||||
/* Class shared by object using this type. */
|
||||
const Class *clasp_;
|
||||
|
||||
/* Prototype shared by objects using this type. */
|
||||
HeapPtrObject proto;
|
||||
HeapPtrObject proto_;
|
||||
|
||||
#ifdef DEBUG
|
||||
void assertCanAccessProto();
|
||||
#else
|
||||
void assertCanAccessProto() {}
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
const Class *clasp() {
|
||||
return clasp_;
|
||||
}
|
||||
|
||||
void setClasp(const Class *clasp) {
|
||||
JS_ASSERT(CurrentThreadCanWriteCompilationData());
|
||||
JS_ASSERT(singleton);
|
||||
clasp_ = clasp;
|
||||
}
|
||||
|
||||
TaggedProto proto() {
|
||||
assertCanAccessProto();
|
||||
return TaggedProto(proto_);
|
||||
}
|
||||
|
||||
HeapPtrObject &protoRaw() {
|
||||
// For use during marking, don't call otherwise.
|
||||
return proto_;
|
||||
}
|
||||
|
||||
void setProto(JSContext *cx, TaggedProto proto);
|
||||
void setProtoUnchecked(TaggedProto proto) {
|
||||
proto_ = proto.raw();
|
||||
}
|
||||
|
||||
/*
|
||||
* Whether there is a singleton JS object with this type. That JS object
|
||||
|
@ -877,8 +935,9 @@ struct TypeObject : gc::BarrieredCell<TypeObject>
|
|||
static const size_t LAZY_SINGLETON = 1;
|
||||
bool lazy() const { return singleton == (JSObject *) LAZY_SINGLETON; }
|
||||
|
||||
private:
|
||||
/* Flags for this object. */
|
||||
TypeObjectFlags flags;
|
||||
TypeObjectFlags flags_;
|
||||
|
||||
/*
|
||||
* This field allows various special classes of objects to attach
|
||||
|
@ -891,23 +950,48 @@ struct TypeObject : gc::BarrieredCell<TypeObject>
|
|||
* before the object escapes.
|
||||
*/
|
||||
HeapPtr<TypeObjectAddendum> addendum;
|
||||
public:
|
||||
|
||||
TypeObjectFlags flags() const {
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
return flags_;
|
||||
}
|
||||
|
||||
void addFlags(TypeObjectFlags flags) {
|
||||
JS_ASSERT(CurrentThreadCanWriteCompilationData());
|
||||
flags_ |= flags;
|
||||
}
|
||||
|
||||
void clearFlags(TypeObjectFlags flags) {
|
||||
JS_ASSERT(CurrentThreadCanWriteCompilationData());
|
||||
flags_ &= ~flags;
|
||||
}
|
||||
|
||||
bool hasNewScript() const {
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
return addendum && addendum->isNewScript();
|
||||
}
|
||||
|
||||
TypeNewScript *newScript() {
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
return addendum->asNewScript();
|
||||
}
|
||||
|
||||
bool hasTypedObject() {
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
return addendum && addendum->isTypedObject();
|
||||
}
|
||||
|
||||
TypeTypedObject *typedObject() {
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
return addendum->asTypedObject();
|
||||
}
|
||||
|
||||
void setAddendum(TypeObjectAddendum *addendum) {
|
||||
JS_ASSERT(CurrentThreadCanWriteCompilationData());
|
||||
this->addendum = addendum;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tag the type object for a binary data type descriptor, instance,
|
||||
* or handle with the type representation of the data it points at.
|
||||
|
@ -919,6 +1003,7 @@ struct TypeObject : gc::BarrieredCell<TypeObject>
|
|||
TypeTypedObject::Kind kind ,
|
||||
TypeRepresentation *repr);
|
||||
|
||||
private:
|
||||
/*
|
||||
* Properties of this object. This may contain JSID_VOID, representing the
|
||||
* types of all integer indexes of the object, and/or JSID_EMPTY, holding
|
||||
|
@ -953,6 +1038,7 @@ struct TypeObject : gc::BarrieredCell<TypeObject>
|
|||
* might update the property with a new type.
|
||||
*/
|
||||
Property **propertySet;
|
||||
public:
|
||||
|
||||
/* If this is an interpreted function, the function object. */
|
||||
HeapPtrFunction interpretedFunction;
|
||||
|
@ -961,27 +1047,31 @@ struct TypeObject : gc::BarrieredCell<TypeObject>
|
|||
uint32_t padding;
|
||||
#endif
|
||||
|
||||
inline TypeObject(const Class *clasp, TaggedProto proto, bool unknown);
|
||||
inline TypeObject(const Class *clasp, TaggedProto proto, TypeObjectFlags initialFlags);
|
||||
|
||||
bool hasAnyFlags(TypeObjectFlags flags) {
|
||||
JS_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags);
|
||||
return !!(this->flags & flags);
|
||||
return !!(this->flags() & flags);
|
||||
}
|
||||
bool hasAllFlags(TypeObjectFlags flags) {
|
||||
JS_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags);
|
||||
return (this->flags & flags) == flags;
|
||||
return (this->flags() & flags) == flags;
|
||||
}
|
||||
|
||||
bool unknownProperties() {
|
||||
JS_ASSERT_IF(flags & OBJECT_FLAG_UNKNOWN_PROPERTIES,
|
||||
JS_ASSERT_IF(flags() & OBJECT_FLAG_UNKNOWN_PROPERTIES,
|
||||
hasAllFlags(OBJECT_FLAG_DYNAMIC_MASK));
|
||||
return !!(flags & OBJECT_FLAG_UNKNOWN_PROPERTIES);
|
||||
return !!(flags() & OBJECT_FLAG_UNKNOWN_PROPERTIES);
|
||||
}
|
||||
|
||||
bool shouldPreTenure() {
|
||||
return hasAnyFlags(OBJECT_FLAG_PRE_TENURE) && !unknownProperties();
|
||||
}
|
||||
|
||||
bool hasTenuredProto() const {
|
||||
return !(flags() & OBJECT_FLAG_NURSERY_PROTO);
|
||||
}
|
||||
|
||||
gc::InitialHeap initialHeap(CompilerConstraintList *constraints);
|
||||
|
||||
bool canPreTenure() {
|
||||
|
@ -991,7 +1081,7 @@ struct TypeObject : gc::BarrieredCell<TypeObject>
|
|||
// this bit reliably.
|
||||
if (unknownProperties())
|
||||
return false;
|
||||
return (flags & OBJECT_FLAG_FROM_ALLOCATION_SITE) || hasNewScript();
|
||||
return (flags() & OBJECT_FLAG_FROM_ALLOCATION_SITE) || hasNewScript();
|
||||
}
|
||||
|
||||
void setShouldPreTenure(ExclusiveContext *cx) {
|
||||
|
@ -1046,12 +1136,20 @@ struct TypeObject : gc::BarrieredCell<TypeObject>
|
|||
|
||||
static inline ThingRootKind rootKind() { return THING_ROOT_TYPE_OBJECT; }
|
||||
|
||||
static inline uint32_t offsetOfClasp() {
|
||||
return offsetof(TypeObject, clasp_);
|
||||
}
|
||||
|
||||
static inline uint32_t offsetOfProto() {
|
||||
return offsetof(TypeObject, proto_);
|
||||
}
|
||||
|
||||
private:
|
||||
inline uint32_t basePropertyCount() const;
|
||||
inline void setBasePropertyCount(uint32_t count);
|
||||
|
||||
static void staticAsserts() {
|
||||
JS_STATIC_ASSERT(offsetof(TypeObject, proto) == offsetof(js::shadow::TypeObject, proto));
|
||||
JS_STATIC_ASSERT(offsetof(TypeObject, proto_) == offsetof(js::shadow::TypeObject, proto));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1247,6 +1345,7 @@ struct TypeObjectKey
|
|||
|
||||
const Class *clasp();
|
||||
TaggedProto proto();
|
||||
bool hasTenuredProto();
|
||||
JSObject *singleton();
|
||||
TypeNewScript *newScript();
|
||||
|
||||
|
@ -1416,7 +1515,7 @@ struct TypeCompartment
|
|||
* js_ObjectClass).
|
||||
*/
|
||||
TypeObject *newTypeObject(ExclusiveContext *cx, const Class *clasp, Handle<TaggedProto> proto,
|
||||
bool unknown = false);
|
||||
TypeObjectFlags initialFlags = 0);
|
||||
|
||||
/* Get or make an object for an allocation site, and add to the allocation site table. */
|
||||
TypeObject *addAllocationSiteTypeObject(JSContext *cx, AllocationSiteKey key);
|
||||
|
|
|
@ -25,61 +25,6 @@
|
|||
#include "jsanalyzeinlines.h"
|
||||
#include "jscntxtinlines.h"
|
||||
|
||||
inline bool
|
||||
js::TaggedProto::isObject() const
|
||||
{
|
||||
/* Skip nullptr and Proxy::LazyProto. */
|
||||
return uintptr_t(proto) > uintptr_t(Proxy::LazyProto);
|
||||
}
|
||||
|
||||
inline bool
|
||||
js::TaggedProto::isLazy() const
|
||||
{
|
||||
return proto == Proxy::LazyProto;
|
||||
}
|
||||
|
||||
inline JSObject *
|
||||
js::TaggedProto::toObject() const
|
||||
{
|
||||
JS_ASSERT(isObject());
|
||||
return proto;
|
||||
}
|
||||
|
||||
inline JSObject *
|
||||
js::TaggedProto::toObjectOrNull() const
|
||||
{
|
||||
JS_ASSERT(!proto || isObject());
|
||||
return proto;
|
||||
}
|
||||
|
||||
template<class Outer>
|
||||
inline bool
|
||||
js::TaggedProtoOperations<Outer>::isLazy() const
|
||||
{
|
||||
return value()->isLazy();
|
||||
}
|
||||
|
||||
template<class Outer>
|
||||
inline bool
|
||||
js::TaggedProtoOperations<Outer>::isObject() const
|
||||
{
|
||||
return value()->isObject();
|
||||
}
|
||||
|
||||
template<class Outer>
|
||||
inline JSObject *
|
||||
js::TaggedProtoOperations<Outer>::toObject() const
|
||||
{
|
||||
return value()->toObject();
|
||||
}
|
||||
|
||||
template<class Outer>
|
||||
inline JSObject *
|
||||
js::TaggedProtoOperations<Outer>::toObjectOrNull() const
|
||||
{
|
||||
return value()->toObjectOrNull();
|
||||
}
|
||||
|
||||
namespace js {
|
||||
namespace types {
|
||||
|
||||
|
@ -534,7 +479,7 @@ MarkTypeObjectUnknownProperties(JSContext *cx, TypeObject *obj,
|
|||
if (cx->typeInferenceEnabled()) {
|
||||
if (!obj->unknownProperties())
|
||||
obj->markUnknown(cx);
|
||||
if (markSetsUnknown && !(obj->flags & OBJECT_FLAG_SETS_MARKED_UNKNOWN))
|
||||
if (markSetsUnknown && !(obj->flags() & OBJECT_FLAG_SETS_MARKED_UNKNOWN))
|
||||
cx->compartment()->types.markSetsUnknown(cx, obj);
|
||||
}
|
||||
}
|
||||
|
@ -605,7 +550,8 @@ TypeScript::NumTypeSets(JSScript *script)
|
|||
/* static */ inline StackTypeSet *
|
||||
TypeScript::ThisTypes(JSScript *script)
|
||||
{
|
||||
return script->types->typeArray() + script->nTypeSets() + js::analyze::ThisSlot();
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
return script->types->typeArray() + script->nTypeSets() + analyze::ThisSlot();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -618,7 +564,8 @@ TypeScript::ThisTypes(JSScript *script)
|
|||
TypeScript::ArgTypes(JSScript *script, unsigned i)
|
||||
{
|
||||
JS_ASSERT(i < script->function()->nargs());
|
||||
return script->types->typeArray() + script->nTypeSets() + js::analyze::ArgSlot(i);
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
return script->types->typeArray() + script->nTypeSets() + analyze::ArgSlot(i);
|
||||
}
|
||||
|
||||
template <typename TYPESET>
|
||||
|
@ -1089,10 +1036,8 @@ TypeSet::clearObjects()
|
|||
}
|
||||
|
||||
bool
|
||||
TypeSet::addType(Type type, LifoAlloc *alloc, bool *padded)
|
||||
TypeSet::addType(Type type, LifoAlloc *alloc)
|
||||
{
|
||||
JS_ASSERT_IF(padded, !*padded);
|
||||
|
||||
if (unknown())
|
||||
return true;
|
||||
|
||||
|
@ -1100,8 +1045,6 @@ TypeSet::addType(Type type, LifoAlloc *alloc, bool *padded)
|
|||
flags |= TYPE_FLAG_BASE_MASK;
|
||||
clearObjects();
|
||||
JS_ASSERT(unknown());
|
||||
if (padded)
|
||||
*padded = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1115,8 +1058,6 @@ TypeSet::addType(Type type, LifoAlloc *alloc, bool *padded)
|
|||
flag |= TYPE_FLAG_INT32;
|
||||
|
||||
flags |= flag;
|
||||
if (padded)
|
||||
*padded = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1156,8 +1097,6 @@ TypeSet::addType(Type type, LifoAlloc *alloc, bool *padded)
|
|||
clearObjects();
|
||||
}
|
||||
|
||||
if (padded)
|
||||
*padded = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1166,13 +1105,16 @@ ConstraintTypeSet::addType(ExclusiveContext *cxArg, Type type)
|
|||
{
|
||||
JS_ASSERT(cxArg->compartment()->activeAnalysis);
|
||||
|
||||
bool added = false;
|
||||
if (!TypeSet::addType(type, &cxArg->typeLifoAlloc(), &added)) {
|
||||
cxArg->compartment()->types.setPendingNukeTypes(cxArg);
|
||||
if (hasType(type))
|
||||
return;
|
||||
|
||||
{
|
||||
AutoLockForCompilation lock(cxArg);
|
||||
if (!TypeSet::addType(type, &cxArg->typeLifoAlloc())) {
|
||||
cxArg->compartment()->types.setPendingNukeTypes(cxArg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!added)
|
||||
return;
|
||||
|
||||
InferSpew(ISpewOps, "addType: %sT%p%s %s",
|
||||
InferSpewColor(this), this, InferSpewColorReset(),
|
||||
|
@ -1275,7 +1217,7 @@ TypeSet::getObjectClass(unsigned i) const
|
|||
if (JSObject *object = getSingleObject(i))
|
||||
return object->getClass();
|
||||
if (TypeObject *object = getTypeObject(i))
|
||||
return object->clasp;
|
||||
return object->clasp();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -1283,18 +1225,16 @@ TypeSet::getObjectClass(unsigned i) const
|
|||
// TypeObject
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline TypeObject::TypeObject(const Class *clasp, TaggedProto proto, bool unknown)
|
||||
inline TypeObject::TypeObject(const Class *clasp, TaggedProto proto, TypeObjectFlags initialFlags)
|
||||
{
|
||||
mozilla::PodZero(this);
|
||||
|
||||
/* Inner objects may not appear on prototype chains. */
|
||||
JS_ASSERT_IF(proto.isObject(), !proto.toObject()->getClass()->ext.outerObject);
|
||||
|
||||
this->clasp = clasp;
|
||||
this->proto = proto.raw();
|
||||
|
||||
if (unknown)
|
||||
flags |= OBJECT_FLAG_UNKNOWN_MASK;
|
||||
this->clasp_ = clasp;
|
||||
this->proto_ = proto.raw();
|
||||
this->flags_ = initialFlags;
|
||||
|
||||
InferSpew(ISpewOps, "newObject: %s", TypeObjectString(this));
|
||||
}
|
||||
|
@ -1302,15 +1242,17 @@ inline TypeObject::TypeObject(const Class *clasp, TaggedProto proto, bool unknow
|
|||
inline uint32_t
|
||||
TypeObject::basePropertyCount() const
|
||||
{
|
||||
return (flags & OBJECT_FLAG_PROPERTY_COUNT_MASK) >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT;
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
return (flags() & OBJECT_FLAG_PROPERTY_COUNT_MASK) >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT;
|
||||
}
|
||||
|
||||
inline void
|
||||
TypeObject::setBasePropertyCount(uint32_t count)
|
||||
{
|
||||
// Note: Callers must ensure they are performing threadsafe operations.
|
||||
JS_ASSERT(count <= OBJECT_FLAG_PROPERTY_COUNT_LIMIT);
|
||||
flags = (flags & ~OBJECT_FLAG_PROPERTY_COUNT_MASK)
|
||||
| (count << OBJECT_FLAG_PROPERTY_COUNT_SHIFT);
|
||||
flags_ = (flags() & ~OBJECT_FLAG_PROPERTY_COUNT_MASK)
|
||||
| (count << OBJECT_FLAG_PROPERTY_COUNT_SHIFT);
|
||||
}
|
||||
|
||||
inline HeapTypeSet *
|
||||
|
@ -1322,36 +1264,46 @@ TypeObject::getProperty(ExclusiveContext *cx, jsid id)
|
|||
JS_ASSERT_IF(!JSID_IS_EMPTY(id), id == IdToTypeId(id));
|
||||
JS_ASSERT(!unknownProperties());
|
||||
|
||||
uint32_t propertyCount = basePropertyCount();
|
||||
Property **pprop = HashSetInsert<jsid,Property,Property>
|
||||
(cx->typeLifoAlloc(), propertySet, propertyCount, id);
|
||||
if (!pprop) {
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
return nullptr;
|
||||
}
|
||||
if (HeapTypeSet *types = maybeGetProperty(id))
|
||||
return types;
|
||||
|
||||
uint32_t propertyCount;
|
||||
Property **pprop;
|
||||
{
|
||||
AutoLockForCompilation lock(cx);
|
||||
|
||||
propertyCount = basePropertyCount();
|
||||
pprop = HashSetInsert<jsid,Property,Property>
|
||||
(cx->typeLifoAlloc(), propertySet, propertyCount, id);
|
||||
if (!pprop) {
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JS_ASSERT(!*pprop);
|
||||
|
||||
if (!*pprop) {
|
||||
setBasePropertyCount(propertyCount);
|
||||
if (!addProperty(cx, id, pprop)) {
|
||||
setBasePropertyCount(0);
|
||||
propertySet = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
if (propertyCount == OBJECT_FLAG_PROPERTY_COUNT_LIMIT) {
|
||||
markUnknown(cx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return an arbitrary property in the object, as all have unknown
|
||||
* type and are treated as configured.
|
||||
*/
|
||||
unsigned count = getPropertyCount();
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
if (Property *prop = getProperty(i))
|
||||
return &prop->types;
|
||||
}
|
||||
if (propertyCount == OBJECT_FLAG_PROPERTY_COUNT_LIMIT) {
|
||||
markUnknown(cx);
|
||||
|
||||
MOZ_ASSUME_UNREACHABLE("Missing property");
|
||||
/*
|
||||
* Return an arbitrary property in the object, as all have unknown
|
||||
* type and are treated as configured.
|
||||
*/
|
||||
unsigned count = getPropertyCount();
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
if (Property *prop = getProperty(i))
|
||||
return &prop->types;
|
||||
}
|
||||
|
||||
MOZ_ASSUME_UNREACHABLE("Missing property");
|
||||
}
|
||||
|
||||
return &(*pprop)->types;
|
||||
|
@ -1363,6 +1315,7 @@ TypeObject::maybeGetProperty(jsid id)
|
|||
JS_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id));
|
||||
JS_ASSERT_IF(!JSID_IS_EMPTY(id), id == IdToTypeId(id));
|
||||
JS_ASSERT(!unknownProperties());
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
|
||||
Property *prop = HashSetLookup<jsid,Property,Property>
|
||||
(propertySet, basePropertyCount(), id);
|
||||
|
|
|
@ -1937,6 +1937,7 @@ GlobalObject::initIteratorClasses(JSContext *cx, Handle<GlobalObject *> global)
|
|||
if (!LinkConstructorAndPrototype(cx, genFunction, genFunctionProto))
|
||||
return false;
|
||||
|
||||
AutoLockForCompilation lock(cx);
|
||||
global->setSlot(STAR_GENERATOR_OBJECT_PROTO, ObjectValue(*genObjectProto));
|
||||
global->setConstructor(JSProto_GeneratorFunction, ObjectValue(*genFunction));
|
||||
global->setPrototype(JSProto_GeneratorFunction, ObjectValue(*genFunctionProto));
|
||||
|
|
|
@ -1273,7 +1273,7 @@ NewObject(ExclusiveContext *cx, const Class *clasp, types::TypeObject *type_, JS
|
|||
if (!NewObjectMetadata(cx, &metadata))
|
||||
return nullptr;
|
||||
|
||||
RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, TaggedProto(type->proto),
|
||||
RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, type->proto(),
|
||||
parent, metadata, kind));
|
||||
if (!shape)
|
||||
return nullptr;
|
||||
|
@ -1457,7 +1457,7 @@ js::NewObjectWithType(JSContext *cx, HandleTypeObject type, JSObject *parent, gc
|
|||
NewObjectCache &cache = cx->runtime()->newObjectCache;
|
||||
|
||||
NewObjectCache::EntryIndex entry = -1;
|
||||
if (parent == type->proto->getParent() &&
|
||||
if (parent == type->proto().toObject()->getParent() &&
|
||||
newKind == GenericObject &&
|
||||
!cx->compartment()->hasObjectMetadataCallback())
|
||||
{
|
||||
|
@ -1985,9 +1985,12 @@ JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved &
|
|||
* Swap the object's types, to restore their initial type information.
|
||||
* The prototypes and classes of the objects were swapped in ReserveForTradeGuts.
|
||||
*/
|
||||
TypeObject *tmp = a->type_;
|
||||
a->type_ = b->type_;
|
||||
b->type_ = tmp;
|
||||
{
|
||||
AutoLockForCompilation lock(cx);
|
||||
TypeObject *tmp = a->type_;
|
||||
a->type_ = b->type_;
|
||||
b->type_ = tmp;
|
||||
}
|
||||
|
||||
/* Don't try to swap a JSFunction for a plain function JSObject. */
|
||||
JS_ASSERT_IF(a->is<JSFunction>(), a->tenuredSizeOfThis() == b->tenuredSizeOfThis());
|
||||
|
@ -2019,9 +2022,12 @@ JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved &
|
|||
char tmp[mozilla::tl::Max<sizeof(JSFunction), sizeof(JSObject_Slots16)>::value];
|
||||
JS_ASSERT(size <= sizeof(tmp));
|
||||
|
||||
js_memcpy(tmp, a, size);
|
||||
js_memcpy(a, b, size);
|
||||
js_memcpy(b, tmp, size);
|
||||
{
|
||||
AutoLockForCompilation lock(cx);
|
||||
js_memcpy(tmp, a, size);
|
||||
js_memcpy(a, b, size);
|
||||
js_memcpy(b, tmp, size);
|
||||
}
|
||||
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
/*
|
||||
|
@ -2059,9 +2065,12 @@ JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved &
|
|||
void *bpriv = b->hasPrivate() ? b->getPrivate() : nullptr;
|
||||
|
||||
char tmp[sizeof(JSObject)];
|
||||
js_memcpy(&tmp, a, sizeof tmp);
|
||||
js_memcpy(a, b, sizeof tmp);
|
||||
js_memcpy(b, &tmp, sizeof tmp);
|
||||
{
|
||||
AutoLockForCompilation lock(cx);
|
||||
js_memcpy(&tmp, a, sizeof tmp);
|
||||
js_memcpy(a, b, sizeof tmp);
|
||||
js_memcpy(b, &tmp, sizeof tmp);
|
||||
}
|
||||
|
||||
if (a->isNative())
|
||||
a->shape_->setNumFixedSlots(reserved.newafixed);
|
||||
|
@ -2967,7 +2976,11 @@ js::SetClassAndProto(JSContext *cx, HandleObject obj,
|
|||
MarkTypeObjectUnknownProperties(cx, obj->type(), true);
|
||||
MarkTypeObjectUnknownProperties(cx, type, true);
|
||||
|
||||
obj->setType(type);
|
||||
{
|
||||
AutoLockForCompilation lock(cx);
|
||||
obj->setType(type);
|
||||
}
|
||||
|
||||
*succeeded = true;
|
||||
return true;
|
||||
}
|
||||
|
@ -4030,7 +4043,7 @@ NativeGetInline(JSContext *cx,
|
|||
case JSOP_GETPROP:
|
||||
case JSOP_CALLPROP:
|
||||
case JSOP_LENGTH:
|
||||
script->baselineScript()->noteAccessedGetter(script->pcToOffset(pc));
|
||||
script->baselineScript()->noteAccessedGetter(cx, script->pcToOffset(pc));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -474,7 +474,7 @@ class JSObject : public js::ObjectImpl
|
|||
bool uninlinedIsProxy() const;
|
||||
JSObject *getProto() const {
|
||||
JS_ASSERT(!uninlinedIsProxy());
|
||||
return js::ObjectImpl::getProto();
|
||||
return getTaggedProto().toObjectOrNull();
|
||||
}
|
||||
static inline bool getProto(JSContext *cx, js::HandleObject obj,
|
||||
js::MutableHandleObject protop);
|
||||
|
|
|
@ -393,6 +393,9 @@ JSObject::clearType(JSContext *cx, js::HandleObject obj)
|
|||
inline void
|
||||
JSObject::setType(js::types::TypeObject *newType)
|
||||
{
|
||||
// Note: This is usually called for newly created objects that haven't
|
||||
// escaped to script yet, so don't require that the compilation lock be
|
||||
// held here.
|
||||
JS_ASSERT(newType);
|
||||
JS_ASSERT(!hasSingletonType());
|
||||
type_ = newType;
|
||||
|
@ -405,7 +408,7 @@ JSObject::getProto(JSContext *cx, js::HandleObject obj, js::MutableHandleObject
|
|||
JS_ASSERT(obj->is<js::ProxyObject>());
|
||||
return js::Proxy::getPrototypeOf(cx, obj, protop);
|
||||
} else {
|
||||
protop.set(obj->js::ObjectImpl::getProto());
|
||||
protop.set(obj->getTaggedProto().toObjectOrNull());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -461,11 +464,11 @@ JSObject::create(js::ExclusiveContext *cx, js::gc::AllocKind kind, js::gc::Initi
|
|||
* make sure their presence is consistent with the shape.
|
||||
*/
|
||||
JS_ASSERT(shape && type);
|
||||
JS_ASSERT(type->clasp == shape->getObjectClass());
|
||||
JS_ASSERT(type->clasp != &js::ArrayObject::class_);
|
||||
JS_ASSERT(js::gc::GetGCKindSlots(kind, type->clasp) == shape->numFixedSlots());
|
||||
JS_ASSERT_IF(type->clasp->flags & JSCLASS_BACKGROUND_FINALIZE, IsBackgroundFinalized(kind));
|
||||
JS_ASSERT_IF(type->clasp->finalize, heap == js::gc::TenuredHeap);
|
||||
JS_ASSERT(type->clasp() == shape->getObjectClass());
|
||||
JS_ASSERT(type->clasp() != &js::ArrayObject::class_);
|
||||
JS_ASSERT(js::gc::GetGCKindSlots(kind, type->clasp()) == shape->numFixedSlots());
|
||||
JS_ASSERT_IF(type->clasp()->flags & JSCLASS_BACKGROUND_FINALIZE, IsBackgroundFinalized(kind));
|
||||
JS_ASSERT_IF(type->clasp()->finalize, heap == js::gc::TenuredHeap);
|
||||
JS_ASSERT_IF(extantSlots, dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan()));
|
||||
|
||||
js::HeapSlot *slots = extantSlots;
|
||||
|
@ -495,7 +498,7 @@ JSObject::create(js::ExclusiveContext *cx, js::gc::AllocKind kind, js::gc::Initi
|
|||
obj->slots = slots;
|
||||
obj->elements = js::emptyObjectElements;
|
||||
|
||||
const js::Class *clasp = type->clasp;
|
||||
const js::Class *clasp = type->clasp();
|
||||
if (clasp->hasPrivate())
|
||||
obj->privateRef(shape->numFixedSlots()) = nullptr;
|
||||
|
||||
|
@ -512,9 +515,9 @@ JSObject::createArray(js::ExclusiveContext *cx, js::gc::AllocKind kind, js::gc::
|
|||
uint32_t length)
|
||||
{
|
||||
JS_ASSERT(shape && type);
|
||||
JS_ASSERT(type->clasp == shape->getObjectClass());
|
||||
JS_ASSERT(type->clasp == &js::ArrayObject::class_);
|
||||
JS_ASSERT_IF(type->clasp->finalize, heap == js::gc::TenuredHeap);
|
||||
JS_ASSERT(type->clasp() == shape->getObjectClass());
|
||||
JS_ASSERT(type->clasp() == &js::ArrayObject::class_);
|
||||
JS_ASSERT_IF(type->clasp()->finalize, heap == js::gc::TenuredHeap);
|
||||
|
||||
/*
|
||||
* Arrays use their fixed slots to store elements, and must have enough
|
||||
|
@ -979,8 +982,11 @@ DefineConstructorAndPrototype(JSContext *cx, Handle<GlobalObject*> global,
|
|||
JS_ASSERT(!global->nativeLookup(cx, id));
|
||||
|
||||
/* Set these first in case AddTypePropertyId looks for this class. */
|
||||
global->setConstructor(key, ObjectValue(*ctor));
|
||||
global->setPrototype(key, ObjectValue(*proto));
|
||||
{
|
||||
AutoLockForCompilation lock(cx);
|
||||
global->setConstructor(key, ObjectValue(*ctor));
|
||||
global->setPrototype(key, ObjectValue(*proto));
|
||||
}
|
||||
global->setConstructorPropertySlot(key, ObjectValue(*ctor));
|
||||
|
||||
if (!global->addDataProperty(cx, id, GlobalObject::constructorPropertySlot(key), 0)) {
|
||||
|
|
|
@ -2748,7 +2748,7 @@ Proxy::defaultValue(JSContext *cx, HandleObject proxy, JSType hint, MutableHandl
|
|||
return proxy->as<ProxyObject>().handler()->defaultValue(cx, proxy, hint, vp);
|
||||
}
|
||||
|
||||
JSObject * const Proxy::LazyProto = reinterpret_cast<JSObject *>(0x1);
|
||||
JSObject * const TaggedProto::LazyProto = reinterpret_cast<JSObject *>(0x1);
|
||||
|
||||
bool
|
||||
Proxy::getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject proto)
|
||||
|
|
|
@ -324,8 +324,6 @@ class Proxy
|
|||
/* IC entry path for handling __noSuchMethod__ on access. */
|
||||
static bool callProp(JSContext *cx, HandleObject proxy, HandleObject reveiver, HandleId id,
|
||||
MutableHandleValue vp);
|
||||
|
||||
static JSObject * const LazyProto;
|
||||
};
|
||||
|
||||
// Use these in places where you don't want to #include vm/ProxyObject.h.
|
||||
|
|
|
@ -3015,7 +3015,10 @@ JSScript::argumentsOptimizationFailed(JSContext *cx, HandleScript script)
|
|||
|
||||
JS_ASSERT(!script->isGenerator());
|
||||
|
||||
script->needsArgsObj_ = true;
|
||||
{
|
||||
AutoLockForCompilation lock(cx);
|
||||
script->needsArgsObj_ = true;
|
||||
}
|
||||
|
||||
#ifdef JS_ION
|
||||
/*
|
||||
|
|
|
@ -977,7 +977,11 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
|
|||
* that needsArgsObj is only called after the script has been analyzed.
|
||||
*/
|
||||
bool analyzedArgsUsage() const { return !needsArgsAnalysis_; }
|
||||
bool needsArgsObj() const { JS_ASSERT(analyzedArgsUsage()); return needsArgsObj_; }
|
||||
bool needsArgsObj() const {
|
||||
JS_ASSERT(analyzedArgsUsage());
|
||||
JS_ASSERT(js::CurrentThreadCanReadCompilationData());
|
||||
return needsArgsObj_;
|
||||
}
|
||||
void setNeedsArgsObj(bool needsArgsObj);
|
||||
static bool argumentsOptimizationFailed(JSContext *cx, js::HandleScript script);
|
||||
|
||||
|
@ -1027,6 +1031,7 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
|
|||
}
|
||||
|
||||
bool hasBaselineScript() const {
|
||||
JS_ASSERT(js::CurrentThreadCanReadCompilationData());
|
||||
return baseline && baseline != BASELINE_DISABLED_SCRIPT;
|
||||
}
|
||||
bool canBaselineCompile() const {
|
||||
|
@ -1036,7 +1041,7 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
|
|||
JS_ASSERT(hasBaselineScript());
|
||||
return baseline;
|
||||
}
|
||||
inline void setBaselineScript(js::jit::BaselineScript *baselineScript);
|
||||
inline void setBaselineScript(JSContext *maybecx, js::jit::BaselineScript *baselineScript);
|
||||
|
||||
void updateBaselineOrIonRaw();
|
||||
|
||||
|
|
|
@ -125,11 +125,14 @@ JSScript::setIsCallsiteClone(JSObject *fun) {
|
|||
}
|
||||
|
||||
inline void
|
||||
JSScript::setBaselineScript(js::jit::BaselineScript *baselineScript) {
|
||||
JSScript::setBaselineScript(JSContext *maybecx, js::jit::BaselineScript *baselineScript) {
|
||||
#ifdef JS_ION
|
||||
if (hasBaselineScript())
|
||||
js::jit::BaselineScript::writeBarrierPre(tenuredZone(), baseline);
|
||||
#endif
|
||||
mozilla::Maybe<js::AutoLockForCompilation> lock;
|
||||
if (maybecx)
|
||||
lock.construct(maybecx);
|
||||
baseline = baselineScript;
|
||||
updateBaselineOrIonRaw();
|
||||
}
|
||||
|
|
|
@ -91,6 +91,8 @@ js::StartOffThreadIonCompile(JSContext *cx, jit::IonBuilder *builder)
|
|||
if (!state.ionWorklist.append(builder))
|
||||
return false;
|
||||
|
||||
cx->runtime()->addCompilationThread();
|
||||
|
||||
state.notifyAll(WorkerThreadState::PRODUCER);
|
||||
return true;
|
||||
}
|
||||
|
@ -615,7 +617,7 @@ WorkerThreadState::finishParseTask(JSContext *maybecx, JSRuntime *rt, void *toke
|
|||
iter.next())
|
||||
{
|
||||
types::TypeObject *object = iter.get<types::TypeObject>();
|
||||
TaggedProto proto(object->proto);
|
||||
TaggedProto proto(object->proto());
|
||||
if (!proto.isObject())
|
||||
continue;
|
||||
|
||||
|
@ -626,7 +628,9 @@ WorkerThreadState::finishParseTask(JSContext *maybecx, JSRuntime *rt, void *toke
|
|||
JSObject *newProto = GetClassPrototypePure(&parseTask->scopeChain->global(), key);
|
||||
JS_ASSERT(newProto);
|
||||
|
||||
object->proto = newProto;
|
||||
// Note: this is safe to do without requiring the compilation lock, as
|
||||
// the new type is not yet available to compilation threads.
|
||||
object->setProtoUnchecked(newProto);
|
||||
}
|
||||
|
||||
// Move the parsed script and all its contents into the desired compartment.
|
||||
|
@ -760,7 +764,11 @@ WorkerThread::handleIonWorkload(WorkerThreadState &state)
|
|||
jit::IonContext ictx(jit::CompileRuntime::get(runtime),
|
||||
jit::CompileCompartment::get(ionBuilder->script()->compartment()),
|
||||
&ionBuilder->alloc());
|
||||
ionBuilder->setBackgroundCodegen(jit::CompileBackEnd(ionBuilder));
|
||||
AutoEnterIonCompilation ionCompiling;
|
||||
bool succeeded = ionBuilder->build();
|
||||
ionBuilder->clearForBackEnd();
|
||||
if (succeeded)
|
||||
ionBuilder->setBackgroundCodegen(jit::CompileBackEnd(ionBuilder));
|
||||
}
|
||||
state.lock();
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ Wrapper::New(JSContext *cx, JSObject *obj, JSObject *parent, Wrapper *handler)
|
|||
RootedValue priv(cx, ObjectValue(*obj));
|
||||
ProxyOptions options;
|
||||
options.setCallable(obj->isCallable());
|
||||
return NewProxyObject(cx, handler, priv, Proxy::LazyProto, parent, options);
|
||||
return NewProxyObject(cx, handler, priv, TaggedProto::LazyProto, parent, options);
|
||||
}
|
||||
|
||||
JSObject *
|
||||
|
@ -141,7 +141,7 @@ js::TransparentObjectWrapper(JSContext *cx, HandleObject existing, HandleObject
|
|||
{
|
||||
// Allow wrapping outer window proxies.
|
||||
JS_ASSERT(!obj->is<WrapperObject>() || obj->getClass()->ext.innerObject);
|
||||
JS_ASSERT(wrappedProto == Proxy::LazyProto);
|
||||
JS_ASSERT(wrappedProto == TaggedProto::LazyProto);
|
||||
return Wrapper::New(cx, obj, parent, &CrossCompartmentWrapper::singleton);
|
||||
}
|
||||
|
||||
|
|
|
@ -669,7 +669,7 @@ GlobalObject::getSelfHostedFunction(JSContext *cx, HandleAtom selfHostedName, Ha
|
|||
RootedId shId(cx, AtomToId(selfHostedName));
|
||||
RootedObject holder(cx, cx->global()->intrinsicsHolder());
|
||||
|
||||
if (HasDataProperty(cx, holder, shId, funVal.address()))
|
||||
if (cx->global()->maybeGetIntrinsicValue(shId, funVal.address()))
|
||||
return true;
|
||||
|
||||
if (!cx->runtime()->maybeWrappedSelfHostedFunction(cx, shId, funVal))
|
||||
|
@ -685,5 +685,31 @@ GlobalObject::getSelfHostedFunction(JSContext *cx, HandleAtom selfHostedName, Ha
|
|||
fun->setExtendedSlot(0, StringValue(selfHostedName));
|
||||
funVal.setObject(*fun);
|
||||
|
||||
return JSObject::defineGeneric(cx, holder, shId, funVal, nullptr, nullptr, 0);
|
||||
return cx->global()->addIntrinsicValue(cx, shId, funVal);
|
||||
}
|
||||
|
||||
bool
|
||||
GlobalObject::addIntrinsicValue(JSContext *cx, HandleId id, HandleValue value)
|
||||
{
|
||||
RootedObject holder(cx, intrinsicsHolder());
|
||||
|
||||
// Work directly with the shape machinery underlying the object, so that we
|
||||
// don't take the compilation lock until we are ready to update the object
|
||||
// without triggering a GC.
|
||||
|
||||
uint32_t slot = holder->slotSpan();
|
||||
RootedShape last(cx, holder->lastProperty());
|
||||
Rooted<UnownedBaseShape*> base(cx, last->base()->unowned());
|
||||
|
||||
StackShape child(base, id, slot, holder->numFixedSlots(), 0, 0, 0);
|
||||
RootedShape shape(cx, cx->compartment()->propertyTree.getChild(cx, last, holder->numFixedSlots(), child));
|
||||
if (!shape)
|
||||
return false;
|
||||
|
||||
AutoLockForCompilation lock(cx);
|
||||
if (!JSObject::setLastProperty(cx, holder, shape))
|
||||
return false;
|
||||
|
||||
holder->setSlot(shape->slot(), value);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -513,26 +513,30 @@ class GlobalObject : public JSObject
|
|||
return &getSlotRefForCompilation(INTRINSICS).toObject();
|
||||
}
|
||||
|
||||
bool maybeGetIntrinsicValue(PropertyName *name, Value *vp) {
|
||||
bool maybeGetIntrinsicValue(jsid id, Value *vp) {
|
||||
JS_ASSERT(CurrentThreadCanReadCompilationData());
|
||||
JSObject *holder = intrinsicsHolder();
|
||||
if (Shape *shape = holder->nativeLookupPure(name)) {
|
||||
if (Shape *shape = holder->nativeLookupPure(id)) {
|
||||
*vp = holder->getSlot(shape->slot());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool maybeGetIntrinsicValue(PropertyName *name, Value *vp) {
|
||||
return maybeGetIntrinsicValue(NameToId(name), vp);
|
||||
}
|
||||
|
||||
bool getIntrinsicValue(JSContext *cx, HandlePropertyName name, MutableHandleValue value) {
|
||||
if (maybeGetIntrinsicValue(name, value.address()))
|
||||
return true;
|
||||
Rooted<GlobalObject*> self(cx, this);
|
||||
if (!cx->runtime()->cloneSelfHostedValue(cx, name, value))
|
||||
return false;
|
||||
RootedObject holder(cx, self->intrinsicsHolder());
|
||||
RootedId id(cx, NameToId(name));
|
||||
return JS_DefinePropertyById(cx, holder, id, value, nullptr, nullptr, 0);
|
||||
return addIntrinsicValue(cx, id, value);
|
||||
}
|
||||
|
||||
bool addIntrinsicValue(JSContext *cx, HandleId id, HandleValue value);
|
||||
|
||||
bool setIntrinsicValue(JSContext *cx, PropertyName *name, HandleValue value) {
|
||||
#ifdef DEBUG
|
||||
RootedObject self(cx, this);
|
||||
|
|
|
@ -1294,7 +1294,7 @@ SetObjectElementOperation(JSContext *cx, Handle<JSObject*> obj, HandleId id, con
|
|||
if ((uint32_t)i >= length) {
|
||||
// Annotate script if provided with information (e.g. baseline)
|
||||
if (script && script->hasBaselineScript() && *pc == JSOP_SETELEM)
|
||||
script->baselineScript()->noteArrayWriteHole(script->pcToOffset(pc));
|
||||
script->baselineScript()->noteArrayWriteHole(cx, script->pcToOffset(pc));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -360,7 +360,7 @@ js::ObjectImpl::markChildren(JSTracer *trc)
|
|||
|
||||
MarkShape(trc, &shape_, "shape");
|
||||
|
||||
const Class *clasp = type_->clasp;
|
||||
const Class *clasp = type_->clasp();
|
||||
JSObject *obj = asObjectPtr();
|
||||
if (clasp->trace)
|
||||
clasp->trace(trc, obj);
|
||||
|
@ -538,7 +538,7 @@ js::ArrayBufferDelegate(JSContext *cx, Handle<ObjectImpl*> obj)
|
|||
if (obj->getPrivate())
|
||||
return static_cast<JSObject *>(obj->getPrivate());
|
||||
JSObject *delegate = NewObjectWithGivenProto(cx, &JSObject::class_,
|
||||
obj->getProto(), nullptr);
|
||||
obj->getTaggedProto(), nullptr);
|
||||
obj->setPrivateGCThing(delegate);
|
||||
return delegate;
|
||||
}
|
||||
|
@ -684,7 +684,7 @@ js::GetProperty(JSContext *cx, Handle<ObjectImpl*> obj, Handle<ObjectImpl*> rece
|
|||
|
||||
/* No property? Recur or bottom out. */
|
||||
if (desc.isUndefined()) {
|
||||
current = current->getProto();
|
||||
current = current->getTaggedProto().toObjectOrNull();
|
||||
if (current)
|
||||
continue;
|
||||
|
||||
|
@ -746,7 +746,7 @@ js::GetElement(JSContext *cx, Handle<ObjectImpl*> obj, Handle<ObjectImpl*> recei
|
|||
|
||||
/* No property? Recur or bottom out. */
|
||||
if (desc.isUndefined()) {
|
||||
current = current->getProto();
|
||||
current = current->getTaggedProto().toObjectOrNull();
|
||||
if (current)
|
||||
continue;
|
||||
|
||||
|
@ -811,7 +811,7 @@ js::HasElement(JSContext *cx, Handle<ObjectImpl*> obj, uint32_t index, unsigned
|
|||
return true;
|
||||
}
|
||||
|
||||
current = current->getProto();
|
||||
current = current->getTaggedProto().toObjectOrNull();
|
||||
if (current)
|
||||
continue;
|
||||
|
||||
|
@ -1009,7 +1009,7 @@ js::SetElement(JSContext *cx, Handle<ObjectImpl*> obj, Handle<ObjectImpl*> recei
|
|||
MOZ_ASSUME_UNREACHABLE("NYI: setting PropertyOp-based property");
|
||||
}
|
||||
|
||||
current = current->getProto();
|
||||
current = current->getTaggedProto().toObjectOrNull();
|
||||
if (current)
|
||||
continue;
|
||||
|
||||
|
|
|
@ -980,12 +980,14 @@ class ObjectImpl : public gc::BarrieredCell<ObjectImpl>
|
|||
/* These functions are public, and they should remain public. */
|
||||
|
||||
public:
|
||||
JSObject * getProto() const {
|
||||
return type_->proto;
|
||||
js::TaggedProto getTaggedProto() const {
|
||||
return type_->proto();
|
||||
}
|
||||
|
||||
bool hasTenuredProto() const;
|
||||
|
||||
const Class *getClass() const {
|
||||
return type_->clasp;
|
||||
return type_->clasp();
|
||||
}
|
||||
|
||||
static inline bool
|
||||
|
@ -1172,10 +1174,6 @@ class ObjectImpl : public gc::BarrieredCell<ObjectImpl>
|
|||
*/
|
||||
|
||||
public:
|
||||
js::TaggedProto getTaggedProto() const {
|
||||
return TaggedProto(getProto());
|
||||
}
|
||||
|
||||
Shape * lastProperty() const {
|
||||
MOZ_ASSERT(shape_);
|
||||
return shape_;
|
||||
|
|
|
@ -75,6 +75,9 @@ PerThreadData::PerThreadData(JSRuntime *runtime)
|
|||
asmJSActivationStack_(nullptr),
|
||||
dtoaState(nullptr),
|
||||
suppressGC(0),
|
||||
#ifdef DEBUG
|
||||
ionCompiling(false),
|
||||
#endif
|
||||
activeCompilations(0)
|
||||
{}
|
||||
|
||||
|
@ -135,6 +138,12 @@ JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads)
|
|||
exclusiveAccessOwner(nullptr),
|
||||
mainThreadHasExclusiveAccess(false),
|
||||
numExclusiveThreads(0),
|
||||
compilationLock(nullptr),
|
||||
#ifdef DEBUG
|
||||
compilationLockOwner(nullptr),
|
||||
mainThreadHasCompilationLock(false),
|
||||
#endif
|
||||
numCompilationThreads(0),
|
||||
#endif
|
||||
systemZone(nullptr),
|
||||
numCompartments(0),
|
||||
|
@ -362,6 +371,10 @@ JSRuntime::init(uint32_t maxbytes)
|
|||
exclusiveAccessLock = PR_NewLock();
|
||||
if (!exclusiveAccessLock)
|
||||
return false;
|
||||
|
||||
compilationLock = PR_NewLock();
|
||||
if (!compilationLock)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
if (!mainThread.init())
|
||||
|
@ -483,6 +496,10 @@ JSRuntime::~JSRuntime()
|
|||
// Avoid bogus asserts during teardown.
|
||||
JS_ASSERT(!numExclusiveThreads);
|
||||
mainThreadHasExclusiveAccess = true;
|
||||
|
||||
JS_ASSERT(!compilationLockOwner);
|
||||
if (compilationLock)
|
||||
PR_DestroyLock(compilationLock);
|
||||
#endif
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
|
@ -816,7 +833,7 @@ JSRuntime::activeGCInAtomsZone()
|
|||
|
||||
#if defined(DEBUG) && !defined(XP_WIN)
|
||||
|
||||
AutoProtectHeapForCompilation::AutoProtectHeapForCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
|
||||
AutoProtectHeapForIonCompilation::AutoProtectHeapForIonCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
|
||||
: runtime(rt)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
|
@ -834,7 +851,7 @@ AutoProtectHeapForCompilation::AutoProtectHeapForCompilation(JSRuntime *rt MOZ_G
|
|||
}
|
||||
}
|
||||
|
||||
AutoProtectHeapForCompilation::~AutoProtectHeapForCompilation()
|
||||
AutoProtectHeapForIonCompilation::~AutoProtectHeapForIonCompilation()
|
||||
{
|
||||
JS_ASSERT(runtime->heapProtected_);
|
||||
JS_ASSERT(runtime->unprotectedArenas.empty());
|
||||
|
@ -936,7 +953,7 @@ js::CurrentThreadCanAccessZone(Zone *zone)
|
|||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // JS_THREADSAFE
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
|
@ -954,13 +971,73 @@ JSRuntime::assertCanLock(RuntimeLock which)
|
|||
JS_ASSERT_IF(workerThreadState, !workerThreadState->isLocked());
|
||||
case OperationCallbackLock:
|
||||
JS_ASSERT(!currentThreadOwnsOperationCallbackLock());
|
||||
case CompilationLock:
|
||||
JS_ASSERT(compilationLockOwner != PR_GetCurrentThread());
|
||||
case GCLock:
|
||||
JS_ASSERT(gcLockOwner != PR_GetCurrentThread());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
#endif // JS_THREADSAFE
|
||||
#endif // JS_WORKER_THREADS
|
||||
}
|
||||
|
||||
AutoEnterIonCompilation::AutoEnterIonCompilation(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
|
||||
#ifdef JS_WORKER_THREADS
|
||||
PerThreadData *pt = js::TlsPerThreadData.get();
|
||||
JS_ASSERT(!pt->ionCompiling);
|
||||
pt->ionCompiling = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
AutoEnterIonCompilation::~AutoEnterIonCompilation()
|
||||
{
|
||||
#ifdef JS_WORKER_THREADS
|
||||
PerThreadData *pt = js::TlsPerThreadData.get();
|
||||
JS_ASSERT(pt->ionCompiling);
|
||||
pt->ionCompiling = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
js::CurrentThreadCanWriteCompilationData()
|
||||
{
|
||||
#ifdef JS_WORKER_THREADS
|
||||
PerThreadData *pt = TlsPerThreadData.get();
|
||||
|
||||
// Data can only be read from during compilation.
|
||||
if (pt->ionCompiling)
|
||||
return false;
|
||||
|
||||
// Ignore what threads with exclusive contexts are doing; these never have
|
||||
// run scripts or have associated compilation threads.
|
||||
JSRuntime *rt = pt->runtimeIfOnOwnerThread();
|
||||
if (!rt)
|
||||
return true;
|
||||
|
||||
return rt->currentThreadHasCompilationLock();
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
js::CurrentThreadCanReadCompilationData()
|
||||
{
|
||||
#ifdef JS_WORKER_THREADS
|
||||
PerThreadData *pt = TlsPerThreadData.get();
|
||||
|
||||
// Data can always be read from freely outside of compilation.
|
||||
if (!pt || !pt->ionCompiling)
|
||||
return true;
|
||||
|
||||
return pt->runtime_->currentThreadHasCompilationLock();
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
|
|
|
@ -535,6 +535,9 @@ class PerThreadData : public PerThreadDataFriendFields,
|
|||
friend class js::ActivationIterator;
|
||||
friend class js::jit::JitActivation;
|
||||
friend class js::AsmJSActivation;
|
||||
#ifdef DEBUG
|
||||
friend bool js::CurrentThreadCanReadCompilationData();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Points to the most recent activation running on the thread.
|
||||
|
@ -577,7 +580,12 @@ class PerThreadData : public PerThreadDataFriendFields,
|
|||
*/
|
||||
int32_t suppressGC;
|
||||
|
||||
// Whether there is an active compilation on this thread.
|
||||
#ifdef DEBUG
|
||||
// Whether this thread is actively Ion compiling.
|
||||
bool ionCompiling;
|
||||
#endif
|
||||
|
||||
// Number of active bytecode compilation on this thread.
|
||||
unsigned activeCompilations;
|
||||
|
||||
PerThreadData(JSRuntime *runtime);
|
||||
|
@ -677,7 +685,8 @@ class MarkingValidator;
|
|||
typedef Vector<JS::Zone *, 4, SystemAllocPolicy> ZoneVector;
|
||||
|
||||
class AutoLockForExclusiveAccess;
|
||||
class AutoProtectHeapForCompilation;
|
||||
class AutoLockForCompilation;
|
||||
class AutoProtectHeapForIonCompilation;
|
||||
|
||||
void RecomputeStackLimit(JSRuntime *rt, StackKind kind);
|
||||
|
||||
|
@ -727,6 +736,7 @@ struct JSRuntime : public JS::shadow::Runtime,
|
|||
ExclusiveAccessLock,
|
||||
WorkerThreadStateLock,
|
||||
OperationCallbackLock,
|
||||
CompilationLock,
|
||||
GCLock
|
||||
};
|
||||
#ifdef DEBUG
|
||||
|
@ -805,20 +815,44 @@ struct JSRuntime : public JS::shadow::Runtime,
|
|||
|
||||
friend class js::AutoLockForExclusiveAccess;
|
||||
|
||||
/*
|
||||
* Lock taken when using data that can be modified by the main thread but
|
||||
* read by Ion compilation threads. Any time either the main thread writes
|
||||
* such data or the compilation thread reads it, this lock must be taken.
|
||||
* Note that no externally visible data is modified by the compilation
|
||||
* thread, so the main thread never needs to take this lock when reading.
|
||||
*/
|
||||
PRLock *compilationLock;
|
||||
#ifdef DEBUG
|
||||
PRThread *compilationLockOwner;
|
||||
bool mainThreadHasCompilationLock;
|
||||
#endif
|
||||
|
||||
/* Number of in flight Ion compilations. */
|
||||
size_t numCompilationThreads;
|
||||
|
||||
friend class js::AutoLockForCompilation;
|
||||
#ifdef DEBUG
|
||||
friend bool js::CurrentThreadCanWriteCompilationData();
|
||||
friend bool js::CurrentThreadCanReadCompilationData();
|
||||
#endif
|
||||
|
||||
public:
|
||||
void setUsedByExclusiveThread(JS::Zone *zone);
|
||||
void clearUsedByExclusiveThread(JS::Zone *zone);
|
||||
|
||||
#endif // JS_THREADSAFE && JS_ION
|
||||
|
||||
#ifdef DEBUG
|
||||
bool currentThreadHasExclusiveAccess() {
|
||||
#if defined(JS_WORKER_THREADS) && defined(DEBUG)
|
||||
#ifdef JS_WORKER_THREADS
|
||||
return (!numExclusiveThreads && mainThreadHasExclusiveAccess) ||
|
||||
exclusiveAccessOwner == PR_GetCurrentThread();
|
||||
exclusiveAccessOwner == PR_GetCurrentThread();
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
bool exclusiveThreadsPresent() const {
|
||||
#ifdef JS_WORKER_THREADS
|
||||
|
@ -828,6 +862,33 @@ struct JSRuntime : public JS::shadow::Runtime,
|
|||
#endif
|
||||
}
|
||||
|
||||
void addCompilationThread() {
|
||||
numCompilationThreads++;
|
||||
}
|
||||
void removeCompilationThread() {
|
||||
JS_ASSERT(numCompilationThreads);
|
||||
numCompilationThreads--;
|
||||
}
|
||||
|
||||
bool compilationThreadsPresent() const {
|
||||
#ifdef JS_WORKER_THREADS
|
||||
return numCompilationThreads > 0;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool currentThreadHasCompilationLock() {
|
||||
#ifdef JS_WORKER_THREADS
|
||||
return (!numCompilationThreads && mainThreadHasCompilationLock) ||
|
||||
compilationLockOwner == PR_GetCurrentThread();
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
/* Embedders can use this zone however they wish. */
|
||||
JS::Zone *systemZone;
|
||||
|
||||
|
@ -1431,7 +1492,7 @@ struct JSRuntime : public JS::shadow::Runtime,
|
|||
const char *numGrouping;
|
||||
#endif
|
||||
|
||||
friend class js::AutoProtectHeapForCompilation;
|
||||
friend class js::AutoProtectHeapForIonCompilation;
|
||||
friend class js::AutoThreadSafeAccess;
|
||||
mozilla::DebugOnly<bool> heapProtected_;
|
||||
#ifdef DEBUG
|
||||
|
@ -2049,16 +2110,36 @@ class RuntimeAllocPolicy
|
|||
|
||||
extern const JSSecurityCallbacks NullSecurityCallbacks;
|
||||
|
||||
class AutoProtectHeapForCompilation
|
||||
// Debugging RAII class which marks the current thread as performing an Ion
|
||||
// compilation, for use by CurrentThreadCan{Read,Write}CompilationData
|
||||
class AutoEnterIonCompilation
|
||||
{
|
||||
public:
|
||||
#ifdef DEBUG
|
||||
AutoEnterIonCompilation(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
|
||||
~AutoEnterIonCompilation();
|
||||
#else
|
||||
AutoEnterIonCompilation(MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
#endif
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
// Debugging RAII class which protects the entire GC heap for the duration of an
|
||||
// Ion compilation. When used only the main thread will be active and all
|
||||
// accesses to GC things must be wrapped by an AutoThreadSafeAccess instance.
|
||||
class AutoProtectHeapForIonCompilation
|
||||
{
|
||||
public:
|
||||
#if defined(DEBUG) && !defined(XP_WIN)
|
||||
JSRuntime *runtime;
|
||||
|
||||
AutoProtectHeapForCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
|
||||
~AutoProtectHeapForCompilation();
|
||||
AutoProtectHeapForIonCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
|
||||
~AutoProtectHeapForIonCompilation();
|
||||
#else
|
||||
AutoProtectHeapForCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
AutoProtectHeapForIonCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
|
|
|
@ -56,13 +56,14 @@ SPSProfiler::enable(bool enabled)
|
|||
if (enabled_ == enabled)
|
||||
return;
|
||||
|
||||
enabled_ = enabled;
|
||||
/*
|
||||
* Ensure all future generated code will be instrumented, or that all
|
||||
* currently instrumented code is discarded
|
||||
*/
|
||||
ReleaseAllJITCode(rt->defaultFreeOp());
|
||||
|
||||
enabled_ = enabled;
|
||||
|
||||
#ifdef JS_ION
|
||||
/* Toggle SPS-related jumps on baseline jitcode.
|
||||
* The call to |ReleaseAllJITCode| above will release most baseline jitcode, but not
|
||||
|
|
|
@ -958,10 +958,11 @@ JSRuntime::cloneSelfHostedFunctionScript(JSContext *cx, Handle<PropertyName*> na
|
|||
JSScript *cscript = CloneScript(cx, NullPtr(), targetFun, sourceScript);
|
||||
if (!cscript)
|
||||
return false;
|
||||
targetFun->setScript(cscript);
|
||||
cscript->setFunction(targetFun);
|
||||
|
||||
JS_ASSERT(sourceFun->nargs() == targetFun->nargs());
|
||||
targetFun->setFlags(sourceFun->flags() | JSFunction::EXTENDED);
|
||||
targetFun->setScript(cscript);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -338,7 +338,7 @@ ArrayBufferObject::neuterViews(JSContext *cx, Handle<ArrayBufferObject*> buffer)
|
|||
size_t numViews = 0;
|
||||
for (view = GetViewList(buffer); view; view = view->nextView()) {
|
||||
numViews++;
|
||||
view->neuter();
|
||||
view->neuter(cx);
|
||||
|
||||
// Notify compiled jit code that the base pointer has moved.
|
||||
MarkObjectStateChange(cx, view);
|
||||
|
@ -1182,8 +1182,10 @@ TypedArrayObject::isArrayIndex(jsid id, uint32_t *ip)
|
|||
}
|
||||
|
||||
void
|
||||
TypedArrayObject::neuter()
|
||||
TypedArrayObject::neuter(JSContext *cx)
|
||||
{
|
||||
AutoLockForCompilation lock(cx);
|
||||
|
||||
setSlot(LENGTH_SLOT, Int32Value(0));
|
||||
setSlot(BYTELENGTH_SLOT, Int32Value(0));
|
||||
setSlot(BYTEOFFSET_SLOT, Int32Value(0));
|
||||
|
@ -2625,12 +2627,12 @@ ArrayBufferViewObject::prependToViews(ArrayBufferViewObject *viewsHead)
|
|||
}
|
||||
|
||||
void
|
||||
ArrayBufferViewObject::neuter()
|
||||
ArrayBufferViewObject::neuter(JSContext *cx)
|
||||
{
|
||||
if (is<DataViewObject>())
|
||||
as<DataViewObject>().neuter();
|
||||
else
|
||||
as<TypedArrayObject>().neuter();
|
||||
as<TypedArrayObject>().neuter(cx);
|
||||
}
|
||||
|
||||
// this default implementation is only valid for integer types
|
||||
|
|
|
@ -276,7 +276,7 @@ class ArrayBufferViewObject : public JSObject
|
|||
|
||||
void prependToViews(ArrayBufferViewObject *viewsHead);
|
||||
|
||||
void neuter();
|
||||
void neuter(JSContext *cx);
|
||||
|
||||
static void trace(JSTracer *trc, JSObject *obj);
|
||||
};
|
||||
|
@ -353,7 +353,7 @@ class TypedArrayObject : public ArrayBufferViewObject
|
|||
inline bool isArrayIndex(jsid id, uint32_t *ip = nullptr);
|
||||
void copyTypedArrayElement(uint32_t index, MutableHandleValue vp);
|
||||
|
||||
void neuter();
|
||||
void neuter(JSContext *cx);
|
||||
|
||||
static uint32_t slotWidth(int atype) {
|
||||
switch (atype) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче