From b5e0c11e2f52c20f3af9fc728239afc06e664965 Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Wed, 23 Oct 2013 08:01:41 -0600 Subject: [PATCH] Bug 928776 - Create template call and decl env objects in baseline, r=jandem. --- js/src/jit/BaselineCompiler.cpp | 21 ++++++++++++-- js/src/jit/BaselineInspector.cpp | 18 ++++++++++++ js/src/jit/BaselineInspector.h | 3 ++ js/src/jit/BaselineJIT.cpp | 3 ++ js/src/jit/BaselineJIT.h | 12 ++++++++ js/src/jit/IonBuilder.cpp | 47 ++++++++++---------------------- js/src/jit/IonBuilder.h | 2 ++ js/src/jit/MIR.h | 8 +++--- js/src/jit/VMFunctions.cpp | 2 ++ js/src/vm/ScopeObject.cpp | 2 +- js/src/vm/ScopeObject.h | 2 +- 11 files changed, 80 insertions(+), 40 deletions(-) diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index e7511ddeff96..8f48a1536914 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -87,6 +87,8 @@ BaselineCompiler::compile() // Pin analysis info during compilation. types::AutoEnterAnalysis autoEnterAnalysis(cx); + JS_ASSERT(!script->hasBaselineScript()); + if (!emitPrologue()) return Method_Error; @@ -94,7 +96,6 @@ BaselineCompiler::compile() if (status != Method_Compiled) return status; - if (!emitEpilogue()) return Method_Error; @@ -111,7 +112,22 @@ BaselineCompiler::compile() if (!code) return Method_Error; - JS_ASSERT(!script->hasBaselineScript()); + JSObject *templateScope = nullptr; + if (script->function()) { + RootedFunction fun(cx, script->function()); + if (fun->isHeavyweight()) { + templateScope = CallObject::createTemplateObject(cx, script, gc::TenuredHeap); + if (!templateScope) + return Method_Error; + + if (fun->isNamedLambda()) { + RootedObject declEnvObject(cx, DeclEnvObject::createTemplateObject(cx, fun, gc::TenuredHeap)); + if (!declEnvObject) + return Method_Error; + templateScope->as().setEnclosingScope(declEnvObject); + } + } + } // Encode the pc mapping table. See PCMappingIndexEntry for // more information. @@ -168,6 +184,7 @@ BaselineCompiler::compile() return Method_Error; baselineScript->setMethod(code); + baselineScript->setTemplateScope(templateScope); script->setBaselineScript(baselineScript); diff --git a/js/src/jit/BaselineInspector.cpp b/js/src/jit/BaselineInspector.cpp index 29b938a0f811..62f43be134fc 100644 --- a/js/src/jit/BaselineInspector.cpp +++ b/js/src/jit/BaselineInspector.cpp @@ -423,3 +423,21 @@ BaselineInspector::getTemplateObjectForNative(jsbytecode *pc, Native native) return NULL; } + +DeclEnvObject * +BaselineInspector::templateDeclEnvObject() +{ + JSObject *res = &templateCallObject()->as().enclosingScope(); + JS_ASSERT(res); + + return &res->as(); +} + +CallObject * +BaselineInspector::templateCallObject() +{ + JSObject *res = baselineScript()->templateScope(); + JS_ASSERT(res); + + return &res->as(); +} diff --git a/js/src/jit/BaselineInspector.h b/js/src/jit/BaselineInspector.h index ae4bff7a509a..d021044631cd 100644 --- a/js/src/jit/BaselineInspector.h +++ b/js/src/jit/BaselineInspector.h @@ -113,6 +113,9 @@ class BaselineInspector JSObject *getTemplateObject(jsbytecode *pc); JSObject *getTemplateObjectForNative(jsbytecode *pc, Native native); + + DeclEnvObject *templateDeclEnvObject(); + CallObject *templateCallObject(); }; } // namespace jit diff --git a/js/src/jit/BaselineJIT.cpp b/js/src/jit/BaselineJIT.cpp index 471edc9a8b7f..3bec547efd9f 100644 --- a/js/src/jit/BaselineJIT.cpp +++ b/js/src/jit/BaselineJIT.cpp @@ -40,6 +40,7 @@ PCMappingSlotInfo::ToSlotLocation(const StackValue *stackVal) BaselineScript::BaselineScript(uint32_t prologueOffset, uint32_t spsPushToggleOffset) : method_(nullptr), + templateScope_(nullptr), fallbackStubSpace_(), prologueOffset_(prologueOffset), #ifdef DEBUG @@ -411,6 +412,8 @@ void BaselineScript::trace(JSTracer *trc) { MarkIonCode(trc, &method_, "baseline-method"); + if (templateScope_) + MarkObject(trc, &templateScope_, "baseline-template-scope"); // Mark all IC stub codes hanging off the IC stub entries. for (size_t i = 0; i < numICEntries(); i++) { diff --git a/js/src/jit/BaselineJIT.h b/js/src/jit/BaselineJIT.h index 16be67f7a25a..ea6159229871 100644 --- a/js/src/jit/BaselineJIT.h +++ b/js/src/jit/BaselineJIT.h @@ -104,6 +104,10 @@ struct BaselineScript // Code pointer containing the actual method. HeapPtr method_; + // For heavyweight scripts, template objects to use for the call object and + // decl env object (linked via the call object's enclosing scope). + HeapPtrObject templateScope_; + // Allocated space for fallback stubs. FallbackICStubSpace fallbackStubSpace_; @@ -225,6 +229,14 @@ struct BaselineScript method_ = code; } + JSObject *templateScope() const { + return templateScope_; + } + void setTemplateScope(JSObject *templateScope) { + JS_ASSERT(!templateScope_); + templateScope_ = templateScope; + } + void toggleBarriers(bool enabled) { method()->togglePreBarriers(enabled); } diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 39ed8663a514..d25dd5fbd1ad 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -4525,20 +4525,9 @@ IonBuilder::inlineCalls(CallInfo &callInfo, ObjectVector &targets, MInstruction * IonBuilder::createDeclEnvObject(MDefinition *callee, MDefinition *scope) { - // Create a template CallObject that we'll use to generate inline object - // creation. Even though this template will get discarded at the end of - // compilation, it is used by the background compilation thread and thus - // cannot use the Nursery. - - RootedFunction fun(cx, info().fun()); - RootedObject templateObj(cx, DeclEnvObject::createTemplateObject(cx, fun, gc::TenuredHeap)); - if (!templateObj) - return nullptr; - - // Add dummy values on the slot of the template object such as we do not try - // mark uninitialized values. - templateObj->setFixedSlot(DeclEnvObject::enclosingScopeSlot(), MagicValue(JS_GENERIC_MAGIC)); - templateObj->setFixedSlot(DeclEnvObject::lambdaSlot(), MagicValue(JS_GENERIC_MAGIC)); + // Get a template CallObject that we'll use to generate inline object + // creation. + DeclEnvObject *templateObj = inspector->templateDeclEnvObject(); // One field is added to the function to handle its name. This cannot be a // dynamic slot because there is still plenty of room on the DeclEnv object. @@ -4563,15 +4552,9 @@ IonBuilder::createDeclEnvObject(MDefinition *callee, MDefinition *scope) MInstruction * IonBuilder::createCallObject(MDefinition *callee, MDefinition *scope) { - // Create a template CallObject that we'll use to generate inline object - // creation. Even though this template will get discarded at the end of - // compilation, it is used by the background compilation thread and thus - // cannot use the Nursery. - - RootedScript scriptRoot(cx, script()); - RootedObject templateObj(cx, CallObject::createTemplateObject(cx, scriptRoot, gc::TenuredHeap)); - if (!templateObj) - return nullptr; + // Get a template CallObject that we'll use to generate inline object + // creation. + CallObject *templateObj = inspector->templateCallObject(); // If the CallObject needs dynamic slots, allocate those now. MInstruction *slots; @@ -4631,11 +4614,11 @@ IonBuilder::createThisScripted(MDefinition *callee) // and thus invalidation. MInstruction *getProto; if (!invalidatedIdempotentCache()) { - MGetPropertyCache *getPropCache = MGetPropertyCache::New(callee, cx->names().prototype); + MGetPropertyCache *getPropCache = MGetPropertyCache::New(callee, names().prototype); getPropCache->setIdempotent(); getProto = getPropCache; } else { - MCallGetProperty *callGetProp = MCallGetProperty::New(callee, cx->names().prototype, + MCallGetProperty *callGetProp = MCallGetProperty::New(callee, names().prototype, /* callprop = */ false); callGetProp->setIdempotent(); getProto = callGetProp; @@ -4658,7 +4641,7 @@ IonBuilder::getSingletonPrototype(JSFunction *target) if (targetType->unknownProperties()) return nullptr; - jsid protoid = NameToId(cx->names().prototype); + jsid protoid = NameToId(names().prototype); types::HeapTypeSetKey protoProperty = targetType->property(protoid); return protoProperty.singleton(constraints()); @@ -6216,12 +6199,12 @@ IonBuilder::getStaticName(JSObject *staticObject, PropertyName *name, bool *psuc if (staticObject->is()) { // Optimize undefined, NaN, and Infinity. - if (name == cx->names().undefined) + if (name == names().undefined) return pushConstant(UndefinedValue()); - if (name == cx->names().NaN) - return pushConstant(cx->runtime()->NaNValue); - if (name == cx->names().Infinity) - return pushConstant(cx->runtime()->positiveInfinityValue); + if (name == names().NaN) + return pushConstant(compartment->runtimeFromAnyThread()->NaNValue); + if (name == names().Infinity) + return pushConstant(compartment->runtimeFromAnyThread()->positiveInfinityValue); } // For the fastest path, the property must be found, and it must be found @@ -9448,7 +9431,7 @@ IonBuilder::jsop_instanceof() break; types::HeapTypeSetKey protoProperty = - rhsType->property(NameToId(cx->names().prototype)); + rhsType->property(NameToId(names().prototype)); JSObject *protoObject = protoProperty.singleton(constraints()); if (!protoObject) break; diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index 31d959bf591d..f8c2db41be9c 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -697,6 +697,8 @@ class IonBuilder : public MIRGenerator return NULL; } + JSAtomState &names() { return compartment->runtimeFromAnyThread()->atomState; } + private: bool init(); diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 0af3e50b13d5..578e6fd611ce 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -8266,7 +8266,7 @@ class MNewDeclEnvObject : public MNullaryInstruction { CompilerRootObject templateObj_; - MNewDeclEnvObject(HandleObject templateObj) + MNewDeclEnvObject(JSObject *templateObj) : MNullaryInstruction(), templateObj_(templateObj) { @@ -8276,7 +8276,7 @@ class MNewDeclEnvObject : public MNullaryInstruction public: INSTRUCTION_HEADER(NewDeclEnvObject); - static MNewDeclEnvObject *New(HandleObject templateObj) { + static MNewDeclEnvObject *New(JSObject *templateObj) { return new MNewDeclEnvObject(templateObj); } @@ -8293,7 +8293,7 @@ class MNewCallObject : public MUnaryInstruction CompilerRootObject templateObj_; bool needsSingletonType_; - MNewCallObject(HandleObject templateObj, bool needsSingletonType, MDefinition *slots) + MNewCallObject(JSObject *templateObj, bool needsSingletonType, MDefinition *slots) : MUnaryInstruction(slots), templateObj_(templateObj), needsSingletonType_(needsSingletonType) @@ -8304,7 +8304,7 @@ class MNewCallObject : public MUnaryInstruction public: INSTRUCTION_HEADER(NewCallObject) - static MNewCallObject *New(HandleObject templateObj, bool needsSingletonType, MDefinition *slots) { + static MNewCallObject *New(JSObject *templateObj, bool needsSingletonType, MDefinition *slots) { return new MNewCallObject(templateObj, needsSingletonType, slots); } diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 08da7b6bcf7e..88b9f333b3a7 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -491,6 +491,8 @@ NewCallObject(JSContext *cx, HandleScript script, HandleShape shape, HandleTypeObject type, HeapSlot *slots) { JSObject *obj = CallObject::create(cx, script, shape, type, slots); + if (!obj) + return nullptr; #ifdef JSGC_GENERATIONAL // The JIT creates call objects in the nursery, so elides barriers for diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 27e0afa3cfd1..89fd6c8564d5 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -165,7 +165,7 @@ js::ScopeCoordinateFunctionScript(JSContext *cx, JSScript *script, jsbytecode *p /*****************************************************************************/ -inline void +void ScopeObject::setEnclosingScope(HandleObject obj) { JS_ASSERT_IF(obj->is() || obj->is() || obj->is(), diff --git a/js/src/vm/ScopeObject.h b/js/src/vm/ScopeObject.h index bb39ff089eac..7d56b3e8b48d 100644 --- a/js/src/vm/ScopeObject.h +++ b/js/src/vm/ScopeObject.h @@ -171,7 +171,7 @@ class ScopeObject : public JSObject return getReservedSlot(SCOPE_CHAIN_SLOT).toObject(); } - inline void setEnclosingScope(HandleObject obj); + void setEnclosingScope(HandleObject obj); /* * Get or set an aliased variable contained in this scope. Unaliased