Bug 785905 - Build Ion MIR graph off thread, r=jandem.

This commit is contained in:
Brian Hackett 2013-12-16 10:53:02 -08:00
Родитель d3040f3cad
Коммит 03fbbbdef7
52 изменённых файлов: 1086 добавлений и 506 удалений

Просмотреть файл

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

Просмотреть файл

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