diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 77ff050f5b9b..e86b06cb2682 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -1296,6 +1296,21 @@ JSObject::makeDenseArraySlow(JSContext *cx) OBJECT_FLAG_NON_PACKED_ARRAY | OBJECT_FLAG_NON_DENSE_ARRAY); markDenseArrayNotPacked(cx); + backfillDenseArrayHoles(cx); + + uint32 arrayCapacity = getDenseArrayCapacity(); + uint32 arrayInitialized = getDenseArrayInitializedLength(); + + /* + * Adjust the slots to account for the different layout between dense + * arrays and other objects. The slots must be dynamic, and the fixed slots + * are now available for newly added properties. + */ + if (denseArrayHasInlineSlots()) { + if (!allocSlots(cx, numSlots())) + return false; + JS_ASSERT(!denseArrayHasInlineSlots()); + } /* * Save old map now, before calling InitScopeForObject. We'll have to undo @@ -1309,25 +1324,7 @@ JSObject::makeDenseArraySlow(JSContext *cx) if (!InitScopeForObject(cx, this, &SlowArrayClass, getProto()->getNewType(cx), kind)) return false; - backfillDenseArrayHoles(cx); - - uint32 arrayCapacity = getDenseArrayCapacity(); - uint32 arrayInitialized = getDenseArrayInitializedLength(); - - /* - * Adjust the slots to account for the different layout between dense - * arrays and other objects. The slots must be dynamic, and the fixed slots - * are now available for newly added properties. - */ - if (denseArrayHasInlineSlots()) { - if (!allocSlots(cx, numSlots())) { - setMap(oldMap); - return false; - } - JS_ASSERT(!denseArrayHasInlineSlots()); - } capacity = numFixedSlots() + arrayCapacity; - clasp = &SlowArrayClass; /* * Root all values in the array during conversion, as SlowArrayClass only @@ -1347,7 +1344,6 @@ JSObject::makeDenseArraySlow(JSContext *cx) setMap(oldMap); capacity = arrayCapacity; initializedLength = arrayInitialized; - clasp = &ArrayClass; return false; } @@ -1370,7 +1366,6 @@ JSObject::makeDenseArraySlow(JSContext *cx) setMap(oldMap); capacity = arrayCapacity; initializedLength = arrayInitialized; - clasp = &ArrayClass; return false; } diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index d3b62eae0a09..c98f1ee91e51 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -87,7 +87,8 @@ JSCompartment::JSCompartment(JSRuntime *rt) regExpAllocator(NULL), #endif propertyTree(thisForCtor()), - emptyArgumentsShape(NULL), + emptyStrictArgumentsShape(NULL), + emptyNormalArgumentsShape(NULL), emptyBlockShape(NULL), emptyCallShape(NULL), emptyDeclEnvShape(NULL), @@ -501,6 +502,14 @@ JSCompartment::markTypes(JSTracer *trc) MarkTypeObject(trc, i.get(), "mark_types_scan"); } +template +void +CheckWeakShape(JSContext *cx, T *&shape) +{ + if (shape && IsAboutToBeFinalized(cx, shape)) + shape = NULL; +} + void JSCompartment::sweep(JSContext *cx, uint32 releaseInterval) { @@ -516,23 +525,16 @@ JSCompartment::sweep(JSContext *cx, uint32 releaseInterval) } /* Remove dead empty shapes. */ - if (emptyArgumentsShape && IsAboutToBeFinalized(cx, emptyArgumentsShape)) - emptyArgumentsShape = NULL; - if (emptyBlockShape && IsAboutToBeFinalized(cx, emptyBlockShape)) - emptyBlockShape = NULL; - if (emptyCallShape && IsAboutToBeFinalized(cx, emptyCallShape)) - emptyCallShape = NULL; - if (emptyDeclEnvShape && IsAboutToBeFinalized(cx, emptyDeclEnvShape)) - emptyDeclEnvShape = NULL; - if (emptyEnumeratorShape && IsAboutToBeFinalized(cx, emptyEnumeratorShape)) - emptyEnumeratorShape = NULL; - if (emptyWithShape && IsAboutToBeFinalized(cx, emptyWithShape)) - emptyWithShape = NULL; + CheckWeakShape(cx, emptyStrictArgumentsShape); + CheckWeakShape(cx, emptyNormalArgumentsShape); + CheckWeakShape(cx, emptyBlockShape); + CheckWeakShape(cx, emptyCallShape); + CheckWeakShape(cx, emptyDeclEnvShape); + CheckWeakShape(cx, emptyEnumeratorShape); + CheckWeakShape(cx, emptyWithShape); - if (initialRegExpShape && IsAboutToBeFinalized(cx, initialRegExpShape)) - initialRegExpShape = NULL; - if (initialStringShape && IsAboutToBeFinalized(cx, initialStringShape)) - initialStringShape = NULL; + CheckWeakShape(cx, initialRegExpShape); + CheckWeakShape(cx, initialStringShape); /* Remove dead base shapes */ sweepBaseShapeTable(cx); diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index 52843708a16e..a52ec510a259 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -476,7 +476,8 @@ struct JS_FRIEND_API(JSCompartment) { * Runtime-shared empty scopes for well-known built-in objects that lack * class prototypes (the usual locus of an emptyShape). Mnemonic: ABCDEW */ - js::EmptyShape *emptyArgumentsShape; + js::EmptyShape *emptyStrictArgumentsShape; + js::EmptyShape *emptyNormalArgumentsShape; js::EmptyShape *emptyBlockShape; js::EmptyShape *emptyCallShape; js::EmptyShape *emptyDeclEnvShape; diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 3936ef8f334d..45af3f8afddd 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -203,7 +203,8 @@ ArgumentsObject::create(JSContext *cx, uint32 argc, JSObject &callee) if (!obj) return NULL; - EmptyShape *emptyArgumentsShape = EmptyShape::getEmptyArgumentsShape(cx); + bool strict = callee.getFunctionPrivate()->inStrictMode(); + EmptyShape *emptyArgumentsShape = EmptyShape::getEmptyArgumentsShape(cx, strict); if (!emptyArgumentsShape) return NULL; @@ -214,10 +215,7 @@ ArgumentsObject::create(JSContext *cx, uint32 argc, JSObject &callee) SetValueRangeToUndefined(data->slots, argc); /* Can't fail from here on, so initialize everything in argsobj. */ - obj->init(cx, callee.getFunctionPrivate()->inStrictMode() - ? &StrictArgumentsObjectClass - : &NormalArgumentsObjectClass, - type, proto->getParent(), NULL, false); + obj->init(cx, type, proto->getParent(), NULL, false); obj->setMap(emptyArgumentsShape); ArgumentsObject *argsobj = obj->asArguments(); @@ -766,7 +764,7 @@ NewDeclEnvObject(JSContext *cx, StackFrame *fp) EmptyShape *emptyDeclEnvShape = EmptyShape::getEmptyDeclEnvShape(cx); if (!emptyDeclEnvShape) return NULL; - envobj->init(cx, &DeclEnvClass, &emptyTypeObject, &fp->scopeChain(), fp, false); + envobj->init(cx, &emptyTypeObject, &fp->scopeChain(), fp, false); envobj->setMap(emptyDeclEnvShape); return envobj; diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index 3f5e6007166b..8f93a2d5e7a4 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -5609,7 +5609,7 @@ JSObject::makeLazyType(JSContext *cx) type->markUnknown(cx); #endif - if (clasp->ext.equality) + if (getClass()->ext.equality) type->flags |= OBJECT_FLAG_SPECIAL_EQUALITY; if (type->unknownProperties()) { @@ -5662,7 +5662,7 @@ JSObject::makeNewType(JSContext *cx, JSFunction *fun, bool unknown) type->flags |= OBJECT_FLAG_UNKNOWN_MASK; #endif - if (clasp->ext.equality) + if (getClass()->ext.equality) type->flags |= OBJECT_FLAG_SPECIAL_EQUALITY; /* diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index 1519f5b3fcc3..1dd070abc9c5 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -418,7 +418,7 @@ NewIteratorObject(JSContext *cx, uintN flags) EmptyShape *emptyEnumeratorShape = EmptyShape::getEmptyEnumeratorShape(cx); if (!emptyEnumeratorShape) return NULL; - obj->init(cx, &IteratorClass, &types::emptyTypeObject, NULL, NULL, false); + obj->init(cx, &types::emptyTypeObject, NULL, NULL, false); obj->setMap(emptyEnumeratorShape); return obj; } diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 5d7461ed8018..880e54c39f46 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -3479,7 +3479,7 @@ js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth) StackFrame *priv = js_FloatingFrameIfGenerator(cx, cx->fp()); - obj->init(cx, &WithClass, type, parent, priv, false); + obj->init(cx, type, parent, priv, false); EmptyShape *emptyWithShape = EmptyShape::getEmptyWithShape(cx); if (!emptyWithShape) @@ -3513,7 +3513,7 @@ js_NewBlockObject(JSContext *cx) EmptyShape *emptyBlockShape = EmptyShape::getEmptyBlockShape(cx); if (!emptyBlockShape) return NULL; - blockObj->init(cx, &BlockClass, &emptyTypeObject, NULL, NULL, false); + blockObj->init(cx, &emptyTypeObject, NULL, NULL, false); blockObj->setMap(emptyBlockShape); return blockObj; diff --git a/js/src/jsobj.h b/js/src/jsobj.h index e8499fe52360..8cdc796e5540 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -445,10 +445,6 @@ struct JSObject : js::gc::Cell { friend class js::TraceRecorder; friend class nanojit::ValidateWriter; -#if JS_BITS_PER_WORD == 32 - void *padding; -#endif - /* * Private pointer to the last added property and methods to manipulate the * list it links among properties in this scope. @@ -456,7 +452,6 @@ struct JSObject : js::gc::Cell { js::Shape *lastProp; private: - js::Class *clasp; inline void setLastProperty(const js::Shape *shape); inline void removeLastProperty(); @@ -544,17 +539,11 @@ struct JSObject : js::gc::Cell { inline bool isNative() const; inline bool isNewborn() const; - void setClass(js::Class *c) { clasp = c; } - js::Class *getClass() const { return clasp; } - JSClass *getJSClass() const { return Jsvalify(clasp); } - - bool hasClass(const js::Class *c) const { - return c == clasp; - } - - const js::ObjectOps *getOps() const { - return &getClass()->ops; - } + /* Inline functions defined in jsobjinlines.h */ + js::Class *getClass() const; + JSClass *getJSClass() const; + bool hasClass(const js::Class *c) const; + const js::ObjectOps *getOps() const; inline void trace(JSTracer *trc); inline void scanSlots(js::GCMarker *gcmarker); @@ -578,7 +567,7 @@ struct JSObject : js::gc::Cell { bool hasSpecialEquality() const { return !!(flags & HAS_EQUALITY); } void assertSpecialEqualitySynced() const { - JS_ASSERT(!!clasp->ext.equality == hasSpecialEquality()); + JS_ASSERT(!!getClass()->ext.equality == hasSpecialEquality()); } /* Sets an object's HAS_EQUALITY flag based on its clasp. */ @@ -1213,7 +1202,7 @@ struct JSObject : js::gc::Cell { } /* The map field is not initialized here and should be set separately. */ - void init(JSContext *cx, js::Class *aclasp, js::types::TypeObject *type, + void init(JSContext *cx, js::types::TypeObject *type, JSObject *parent, void *priv, bool denseArray); inline void finish(JSContext *cx); @@ -1419,56 +1408,52 @@ struct JSObject : js::gc::Cell { const js::Shape *defineBlockVariable(JSContext *cx, jsid id, intN index); inline bool isArguments() const { return isNormalArguments() || isStrictArguments(); } - inline bool isArrayBuffer() const { return clasp == &js::ArrayBufferClass; } - inline bool isNormalArguments() const { return clasp == &js::NormalArgumentsObjectClass; } - inline bool isStrictArguments() const { return clasp == &js::StrictArgumentsObjectClass; } + inline bool isArrayBuffer() const { return hasClass(&js::ArrayBufferClass); } + inline bool isNormalArguments() const { return hasClass(&js::NormalArgumentsObjectClass); } + inline bool isStrictArguments() const { return hasClass(&js::StrictArgumentsObjectClass); } inline bool isArray() const { return isSlowArray() || isDenseArray(); } - inline bool isDenseArray() const { return clasp == &js::ArrayClass; } - inline bool isSlowArray() const { return clasp == &js::SlowArrayClass; } - inline bool isNumber() const { return clasp == &js::NumberClass; } - inline bool isBoolean() const { return clasp == &js::BooleanClass; } - inline bool isString() const { return clasp == &js::StringClass; } + inline bool isDenseArray() const { return hasClass(&js::ArrayClass); } + inline bool isSlowArray() const { return hasClass(&js::SlowArrayClass); } + inline bool isNumber() const { return hasClass(&js::NumberClass); } + inline bool isBoolean() const { return hasClass(&js::BooleanClass); } + inline bool isString() const { return hasClass(&js::StringClass); } inline bool isPrimitive() const { return isNumber() || isString() || isBoolean(); } - inline bool isDate() const { return clasp == &js::DateClass; } - inline bool isFunction() const { return clasp == &js::FunctionClass; } - inline bool isObject() const { return clasp == &js::ObjectClass; } - inline bool isWith() const { return clasp == &js::WithClass; } - inline bool isBlock() const { return clasp == &js::BlockClass; } + inline bool isDate() const { return hasClass(&js::DateClass); } + inline bool isFunction() const { return hasClass(&js::FunctionClass); } + inline bool isObject() const { return hasClass(&js::ObjectClass); } + inline bool isWith() const { return hasClass(&js::WithClass); } + inline bool isBlock() const { return hasClass(&js::BlockClass); } inline bool isStaticBlock() const { return isBlock() && !getProto(); } inline bool isClonedBlock() const { return isBlock() && !!getProto(); } - inline bool isCall() const { return clasp == &js::CallClass; } - inline bool isDeclEnv() const { return clasp == &js::DeclEnvClass; } - inline bool isRegExp() const { return clasp == &js::RegExpClass; } - inline bool isScript() const { return clasp == &js::ScriptClass; } - inline bool isGenerator() const { return clasp == &js::GeneratorClass; } - inline bool isIterator() const { return clasp == &js::IteratorClass; } - inline bool isStopIteration() const { return clasp == &js::StopIterationClass; } - inline bool isError() const { return clasp == &js::ErrorClass; } - inline bool isXML() const { return clasp == &js::XMLClass; } - inline bool isNamespace() const { return clasp == &js::NamespaceClass; } - inline bool isWeakMap() const { return clasp == &js::WeakMapClass; } - inline bool isFunctionProxy() const { return clasp == &js::FunctionProxyClass; } + inline bool isCall() const { return hasClass(&js::CallClass); } + inline bool isDeclEnv() const { return hasClass(&js::DeclEnvClass); } + inline bool isRegExp() const { return hasClass(&js::RegExpClass); } + inline bool isScript() const { return hasClass(&js::ScriptClass); } + inline bool isGenerator() const { return hasClass(&js::GeneratorClass); } + inline bool isIterator() const { return hasClass(&js::IteratorClass); } + inline bool isStopIteration() const { return hasClass(&js::StopIterationClass); } + inline bool isError() const { return hasClass(&js::ErrorClass); } + inline bool isXML() const { return hasClass(&js::XMLClass); } + inline bool isNamespace() const { return hasClass(&js::NamespaceClass); } + inline bool isWeakMap() const { return hasClass(&js::WeakMapClass); } + inline bool isFunctionProxy() const { return hasClass(&js::FunctionProxyClass); } inline bool isProxy() const { return isObjectProxy() || isFunctionProxy(); } inline bool isXMLId() const { - return clasp == &js::QNameClass || clasp == &js::AttributeNameClass || clasp == &js::AnyNameClass; - } + return hasClass(&js::QNameClass) || hasClass(&js::AttributeNameClass) || hasClass(&js::AnyNameClass); +} inline bool isQName() const { - return clasp == &js::QNameClass || clasp == &js::AttributeNameClass || clasp == &js::AnyNameClass; - } + return hasClass(&js::QNameClass) || hasClass(&js::AttributeNameClass) || hasClass(&js::AnyNameClass); +} inline bool isObjectProxy() const { - return clasp == &js::ObjectProxyClass || clasp == &js::OuterWindowProxyClass; - } + return hasClass(&js::ObjectProxyClass) || hasClass(&js::OuterWindowProxyClass); +} JS_FRIEND_API(bool) isWrapper() const; bool isCrossCompartmentWrapper() const; JS_FRIEND_API(JSObject *) unwrap(uintN *flagsp = NULL); inline void initArrayClass(); - - /*** For jit compiler: ***/ - - static size_t offsetOfClassPointer() { return offsetof(JSObject, clasp); } }; /* Check alignment for any fixed slots allocated after the object. */ diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index dd2b8b70c8b3..f53a9fbe890e 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -181,9 +181,12 @@ JSObject::finalize(JSContext *cx) inline bool JSObject::initCall(JSContext *cx, const js::Bindings &bindings, JSObject *parent) { - init(cx, &js::CallClass, &js::types::emptyTypeObject, parent, NULL, false); + init(cx, &js::types::emptyTypeObject, parent, NULL, false); setMap(bindings.lastShape()); + JS_ASSERT(isCall()); + JS_ASSERT(!inDictionaryMode()); + /* * If |bindings| is for a function that has extensible parents, that means * its Call should have its own shape; see js::BaseShape::extensibleParents. @@ -200,12 +203,13 @@ JSObject::initCall(JSContext *cx, const js::Bindings &bindings, JSObject *parent inline bool JSObject::initClonedBlock(JSContext *cx, js::types::TypeObject *type, js::StackFrame *frame) { - init(cx, &js::BlockClass, type, NULL, frame, false); + init(cx, type, NULL, frame, false); - /* Cloned blocks copy their prototype's map; it had better be shareable. */ - JS_ASSERT(!getProto()->inDictionaryMode()); setMap(getProto()->lastProp); + JS_ASSERT(!inDictionaryMode()); + JS_ASSERT(isClonedBlock()); + if (lastProp->extensibleParents()) return generateOwnShape(cx); return true; @@ -767,14 +771,11 @@ JSObject::setType(js::types::TypeObject *newType) } inline void -JSObject::init(JSContext *cx, js::Class *aclasp, js::types::TypeObject *type, +JSObject::init(JSContext *cx, js::types::TypeObject *type, JSObject *parent, void *priv, bool denseArray) { - clasp = aclasp; flags = capacity << FIXED_SLOTS_SHIFT; - JS_ASSERT(denseArray == (aclasp == &js::ArrayClass)); - privateData = priv; /* @@ -813,15 +814,15 @@ JSObject::initSharingEmptyShape(JSContext *cx, void *privateValue, js::gc::AllocKind kind) { - init(cx, aclasp, type, parent, privateValue, false); - - JS_ASSERT(!isDenseArray()); + init(cx, type, parent, privateValue, false); js::EmptyShape *empty = type->getEmptyShape(cx, aclasp, kind); if (!empty) return false; setMap(empty); + + JS_ASSERT(!isDenseArray()); return true; } @@ -1124,24 +1125,25 @@ InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, js::types::Ty /* Share proto's emptyShape only if obj is similar to proto. */ js::EmptyShape *empty = NULL; - uint32 freeslot = JSSLOT_FREE(clasp); - if (freeslot > obj->numSlots() && !obj->allocSlots(cx, freeslot)) - goto bad; - if (type->canProvideEmptyShape(clasp)) empty = type->getEmptyShape(cx, clasp, kind); else empty = js::EmptyShape::create(cx, clasp); - if (!empty) - goto bad; + if (!empty) { + JS_ASSERT(obj->isNewborn()); + return false; + } obj->setMap(empty); - return true; - bad: - /* The GC nulls map initially. It should still be null on error. */ - JS_ASSERT(obj->isNewborn()); - return false; + uint32 freeslot = JSSLOT_FREE(clasp); + if (freeslot > obj->numSlots() && !obj->allocSlots(cx, freeslot)) { + obj->setMap(NULL); + JS_ASSERT(obj->isNewborn()); + return false; + } + + return true; } static inline bool @@ -1212,7 +1214,7 @@ NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto, * the parent of the prototype's constructor. */ bool denseArray = (clasp == &ArrayClass); - obj->init(cx, clasp, type, parent, NULL, denseArray); + obj->init(cx, type, parent, NULL, denseArray); JS_ASSERT(type->canProvideEmptyShape(clasp)); js::EmptyShape *empty = type->getEmptyShape(cx, clasp, kind); @@ -1375,7 +1377,7 @@ NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent, * Default parent to the parent of the prototype, which was set from * the parent of the prototype's constructor. */ - obj->init(cx, clasp, type, + obj->init(cx, type, (!parent && proto) ? proto->getParent() : parent, NULL, clasp == &ArrayClass); @@ -1462,7 +1464,7 @@ NewObjectWithType(JSContext *cx, types::TypeObject *type, JSObject *parent, gc:: * Default parent to the parent of the prototype, which was set from * the parent of the prototype's constructor. */ - obj->init(cx, &ObjectClass, type, + obj->init(cx, type, (!parent && type->proto) ? type->proto->getParent() : parent, NULL, false); @@ -1609,4 +1611,24 @@ js_GetProtoIfDenseArray(JSObject *obj) return obj->isDenseArray() ? obj->getProto() : obj; } +inline js::Class * +JSObject::getClass() const { + return lastProp->getClass(); +} + +inline JSClass * +JSObject::getJSClass() const { + return Jsvalify(getClass()); +} + +inline bool +JSObject::hasClass(const js::Class *c) const { + return getClass() == c; +} + +inline const js::ObjectOps * +JSObject::getOps() const { + return &getClass()->ops; +} + #endif /* jsobjinlines_h___ */ diff --git a/js/src/jsscope.h b/js/src/jsscope.h index 304ea52b9ff8..9473eaad53ab 100644 --- a/js/src/jsscope.h +++ b/js/src/jsscope.h @@ -764,6 +764,9 @@ struct Shape : public js::gc::Cell void finalize(JSContext *cx); void removeChild(js::Shape *child); void removeChildSlowly(js::Shape *child); + + /* For JIT usage */ + static inline size_t offsetOfBase() { return offsetof(Shape, base_); } }; struct EmptyShape : public js::Shape @@ -792,8 +795,7 @@ struct EmptyShape : public js::Shape return shape; } - static inline EmptyShape *getEmptyArgumentsShape(JSContext *cx); - + static inline EmptyShape *getEmptyArgumentsShape(JSContext *cx, bool strict); static inline EmptyShape *getEmptyBlockShape(JSContext *cx); static inline EmptyShape *getEmptyCallShape(JSContext *cx); static inline EmptyShape *getEmptyDeclEnvShape(JSContext *cx); diff --git a/js/src/jsscopeinlines.h b/js/src/jsscopeinlines.h index 8a9f5d978d36..3f55013ee1ce 100644 --- a/js/src/jsscopeinlines.h +++ b/js/src/jsscopeinlines.h @@ -324,9 +324,11 @@ EmptyShape::EmptyShape(BaseShape *base) } /* static */ inline EmptyShape * -EmptyShape::getEmptyArgumentsShape(JSContext *cx) +EmptyShape::getEmptyArgumentsShape(JSContext *cx, bool strict) { - return ensure(cx, &NormalArgumentsObjectClass, &cx->compartment->emptyArgumentsShape); + if (strict) + return ensure(cx, &StrictArgumentsObjectClass, &cx->compartment->emptyStrictArgumentsShape); + return ensure(cx, &NormalArgumentsObjectClass, &cx->compartment->emptyNormalArgumentsShape); } /* static */ inline EmptyShape * diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp index e1a31d0a147b..6a5ab9aeeb7b 100644 --- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -215,7 +215,6 @@ ArrayBuffer::create(JSContext *cx, int32 nbytes) if (!InitNonNativeObject(cx, obj, &ArrayBufferClass)) return NULL; - obj->setClass(&ArrayBufferClass); /* * The first 8 bytes hold the length. @@ -1290,7 +1289,6 @@ class TypedArrayTemplate if (!InitNonNativeObject(cx, obj, fastClass())) return NULL; - obj->setClass(fastClass()); // FIXME Bug 599008: make it ok to call preventExtensions here. obj->flags |= JSObject::NOT_EXTENSIBLE; diff --git a/js/src/methodjit/BaseAssembler.h b/js/src/methodjit/BaseAssembler.h index 1ccfd0e3c10a..831c8cc9ab4a 100644 --- a/js/src/methodjit/BaseAssembler.h +++ b/js/src/methodjit/BaseAssembler.h @@ -194,11 +194,6 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::SparcRegist ImmPtr(obj->lastProperty())); } - Jump testFunction(Condition cond, RegisterID fun) { - return branchPtr(cond, Address(fun, JSObject::offsetOfClassPointer()), - ImmPtr(&FunctionClass)); - } - /* * Finds and returns the address of a known object and slot. */ @@ -818,16 +813,24 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::SparcRegist addPtr(JSFrameReg, reg); } - void loadObjClass(RegisterID objReg, RegisterID destReg) { - loadPtr(Address(objReg, JSObject::offsetOfClassPointer()), destReg); + void loadObjClass(RegisterID obj, RegisterID dest) { + loadPtr(Address(obj, offsetof(JSObject, lastProp)), dest); + loadPtr(Address(dest, Shape::offsetOfBase()), dest); + loadPtr(Address(dest, offsetof(BaseShape, clasp)), dest); } Jump testClass(Condition cond, RegisterID claspReg, js::Class *clasp) { return branchPtr(cond, claspReg, ImmPtr(clasp)); } - Jump testObjClass(Condition cond, RegisterID objReg, js::Class *clasp) { - return branchPtr(cond, Address(objReg, JSObject::offsetOfClassPointer()), ImmPtr(clasp)); + Jump testObjClass(Condition cond, RegisterID obj, RegisterID temp, js::Class *clasp) { + loadPtr(Address(obj, offsetof(JSObject, lastProp)), temp); + loadPtr(Address(temp, Shape::offsetOfBase()), temp); + return branchPtr(cond, Address(temp, offsetof(BaseShape, clasp)), ImmPtr(clasp)); + } + + Jump testFunction(Condition cond, RegisterID fun, RegisterID temp) { + return testObjClass(cond, fun, temp, &js::FunctionClass); } void branchValue(Condition cond, RegisterID reg, int32 value, RegisterID result) @@ -1294,7 +1297,6 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::SparcRegist } storePtr(ImmPtr(templateObject->lastProp), Address(result, offsetof(JSObject, lastProp))); - storePtr(ImmPtr(templateObject->getClass()), Address(result, JSObject::offsetOfClassPointer())); store32(Imm32(templateObject->flags), Address(result, offsetof(JSObject, flags))); storePtr(ImmPtr(templateObject->newType), Address(result, offsetof(JSObject, newType))); storePtr(ImmPtr(templateObject->parent), Address(result, offsetof(JSObject, parent))); diff --git a/js/src/methodjit/Compiler.cpp b/js/src/methodjit/Compiler.cpp index 4af068725c8b..2ece1f155679 100644 --- a/js/src/methodjit/Compiler.cpp +++ b/js/src/methodjit/Compiler.cpp @@ -123,6 +123,7 @@ mjit::Compiler::Compiler(JSContext *cx, JSScript *outerScript, bool isConstructi jumpTableOffsets(CompilerAllocPolicy(cx, *thisFromCtor())), loopEntries(CompilerAllocPolicy(cx, *thisFromCtor())), rootedObjects(CompilerAllocPolicy(cx, *thisFromCtor())), + denseArrayShape(NULL), stubcc(cx, *thisFromCtor(), frame), debugMode_(cx->compartment->debugMode()), #if defined JS_TRACER @@ -996,6 +997,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp) jit->fastEntry = fullCode.locationOf(invokeLabel).executableAddress(); } jit->pcLengths = pcLengths; + jit->denseArrayShape = denseArrayShape; /* * WARNING: mics(), callICs() et al depend on the ordering of these @@ -1313,10 +1315,10 @@ mjit::Compiler::finishThisUp(JITScript **jitp) to.inlineTypeGuard = inlineTypeGuard; JS_ASSERT(to.inlineTypeGuard == inlineTypeGuard); } - int inlineClaspGuard = fullCode.locationOf(from.claspGuard) - + int inlineShapeGuard = fullCode.locationOf(from.shapeGuard) - fullCode.locationOf(from.fastPathStart); - to.inlineClaspGuard = inlineClaspGuard; - JS_ASSERT(to.inlineClaspGuard == inlineClaspGuard); + to.inlineShapeGuard = inlineShapeGuard; + JS_ASSERT(to.inlineShapeGuard == inlineShapeGuard); stubCode.patch(from.paramAddr, &to); } @@ -1343,10 +1345,10 @@ mjit::Compiler::finishThisUp(JITScript **jitp) else to.keyReg = from.key.reg(); - int inlineClaspGuard = fullCode.locationOf(from.claspGuard) - + int inlineShapeGuard = fullCode.locationOf(from.shapeGuard) - fullCode.locationOf(from.fastPathStart); - to.inlineClaspGuard = inlineClaspGuard; - JS_ASSERT(to.inlineClaspGuard == inlineClaspGuard); + to.inlineShapeGuard = inlineShapeGuard; + JS_ASSERT(to.inlineShapeGuard == inlineShapeGuard); int inlineHoleGuard = fullCode.locationOf(from.holeGuard) - fullCode.locationOf(from.fastPathStart); @@ -3320,6 +3322,16 @@ mjit::Compiler::checkCallApplySpeculation(uint32 callImmArgc, uint32 speculatedA { JS_ASSERT(IsLowerableFunCallOrApply(PC)); + RegisterID temp; + Registers tempRegs(Registers::AvailRegs); + if (origCalleeType.isSet()) + tempRegs.takeReg(origCalleeType.reg()); + tempRegs.takeReg(origCalleeData); + if (origThisType.isSet()) + tempRegs.takeReg(origThisType.reg()); + tempRegs.takeReg(origThisData); + temp = tempRegs.takeAnyReg().reg(); + /* * if (origCallee.isObject() && * origCallee.toObject().isFunction && @@ -3328,7 +3340,7 @@ mjit::Compiler::checkCallApplySpeculation(uint32 callImmArgc, uint32 speculatedA MaybeJump isObj; if (origCalleeType.isSet()) isObj = masm.testObject(Assembler::NotEqual, origCalleeType.reg()); - Jump isFun = masm.testFunction(Assembler::NotEqual, origCalleeData); + Jump isFun = masm.testFunction(Assembler::NotEqual, origCalleeData, temp); masm.loadObjPrivate(origCalleeData, origCalleeData); Native native = *PC == JSOP_FUNCALL ? js_fun_call : js_fun_apply; Jump isNative = masm.branchPtr(Assembler::NotEqual, @@ -3601,14 +3613,15 @@ mjit::Compiler::inlineCallHelper(uint32 callImmArgc, bool callingNew, FrameSize stubcc.linkExitDirect(j, stubcc.masm.label()); callIC.slowPathStart = stubcc.masm.label(); + RegisterID tmp = tempRegs.takeAnyReg().reg(); + /* * Test if the callee is even a function. If this doesn't match, we * take a _really_ slow path later. */ - Jump notFunction = stubcc.masm.testFunction(Assembler::NotEqual, icCalleeData); + Jump notFunction = stubcc.masm.testFunction(Assembler::NotEqual, icCalleeData, tmp); /* Test if the function is scripted. */ - RegisterID tmp = tempRegs.takeAnyReg().reg(); stubcc.masm.loadObjPrivate(icCalleeData, funPtrReg); stubcc.masm.load16(Address(funPtrReg, offsetof(JSFunction, flags)), tmp); stubcc.masm.and32(Imm32(JSFUN_KINDMASK), tmp); @@ -5740,7 +5753,7 @@ mjit::Compiler::iterNext(ptrdiff_t offset) frame.unpinReg(reg); /* Test clasp */ - Jump notFast = masm.testObjClass(Assembler::NotEqual, reg, &IteratorClass); + Jump notFast = masm.testObjClass(Assembler::NotEqual, reg, T1, &IteratorClass); stubcc.linkExit(notFast, Uses(1)); /* Get private from iter obj. */ @@ -5795,7 +5808,7 @@ mjit::Compiler::iterMore(jsbytecode *target) RegisterID tempreg = frame.allocReg(); /* Test clasp */ - Jump notFast = masm.testObjClass(Assembler::NotEqual, reg, &IteratorClass); + Jump notFast = masm.testObjClass(Assembler::NotEqual, reg, tempreg, &IteratorClass); stubcc.linkExitForBranch(notFast); /* Get private from iter obj. */ @@ -5834,7 +5847,7 @@ mjit::Compiler::iterEnd() frame.unpinReg(reg); /* Test clasp */ - Jump notIterator = masm.testObjClass(Assembler::NotEqual, reg, &IteratorClass); + Jump notIterator = masm.testObjClass(Assembler::NotEqual, reg, T1, &IteratorClass); stubcc.linkExit(notIterator, Uses(1)); /* Get private from iter obj. */ @@ -6094,6 +6107,7 @@ mjit::Compiler::jsop_callgname_epilogue() /* If the callee is not an object, jump to the inline fast path. */ MaybeRegisterID typeReg = frame.maybePinType(fval); RegisterID objReg = frame.copyDataIntoReg(fval); + RegisterID tempReg = frame.allocReg(); MaybeJump isNotObj; if (!fval->isType(JSVAL_TYPE_OBJECT)) { @@ -6104,7 +6118,7 @@ mjit::Compiler::jsop_callgname_epilogue() /* * If the callee is not a function, jump to OOL slow path. */ - Jump notFunction = masm.testFunction(Assembler::NotEqual, objReg); + Jump notFunction = masm.testFunction(Assembler::NotEqual, objReg, tempReg); stubcc.linkExit(notFunction, Uses(1)); /* @@ -6115,6 +6129,7 @@ mjit::Compiler::jsop_callgname_epilogue() Jump globalMismatch = masm.branchPtr(Assembler::NotEqual, objReg, ImmPtr(globalObj)); stubcc.linkExit(globalMismatch, Uses(1)); frame.freeReg(objReg); + frame.freeReg(tempReg); /* OOL stub call path. */ stubcc.leave(); @@ -6292,10 +6307,14 @@ mjit::Compiler::jsop_instanceof() frame.forgetMismatchedObject(lhs); frame.forgetMismatchedObject(rhs); + RegisterID tmp = frame.allocReg(); RegisterID obj = frame.tempRegForData(rhs); - Jump notFunction = masm.testFunction(Assembler::NotEqual, obj); + + Jump notFunction = masm.testFunction(Assembler::NotEqual, obj, tmp); stubcc.linkExit(notFunction, Uses(2)); + frame.freeReg(tmp); + /* Test for bound functions. */ Jump isBound = masm.branchTest32(Assembler::NonZero, Address(obj, offsetof(JSObject, flags)), Imm32(JSObject::BOUND_FUNCTION)); diff --git a/js/src/methodjit/Compiler.h b/js/src/methodjit/Compiler.h index eb822cb57119..8b0c437f57e9 100644 --- a/js/src/methodjit/Compiler.h +++ b/js/src/methodjit/Compiler.h @@ -214,7 +214,7 @@ class Compiler : public BaseCompiler RegisterID objReg; ValueRemat id; MaybeJump typeGuard; - Jump claspGuard; + Jump shapeGuard; }; struct SetElementICInfo : public BaseICInfo { @@ -224,7 +224,7 @@ class Compiler : public BaseCompiler StateRemat objRemat; ValueRemat vr; Jump capacityGuard; - Jump claspGuard; + Jump shapeGuard; Jump holeGuard; Int32Key key; uint32 volatileMask; @@ -436,6 +436,7 @@ class Compiler : public BaseCompiler js::Vector jumpTableOffsets; js::Vector loopEntries; js::Vector rootedObjects; + Shape *denseArrayShape; StubCompiler stubcc; Label invokeLabel; Label arityLabel; diff --git a/js/src/methodjit/FastOps.cpp b/js/src/methodjit/FastOps.cpp index af4b127c325c..cf1ddd21a904 100644 --- a/js/src/methodjit/FastOps.cpp +++ b/js/src/methodjit/FastOps.cpp @@ -1555,9 +1555,17 @@ mjit::Compiler::jsop_setelem(bool popGuaranteed) RESERVE_OOL_SPACE(stubcc.masm); ic.slowPathStart = stubcc.syncExit(Uses(3)); + if (!denseArrayShape) { + denseArrayShape = BaseShape::lookupEmpty(cx, &ArrayClass); + if (!denseArrayShape) + return false; + } + // Guard obj is a dense array. - ic.claspGuard = masm.testObjClass(Assembler::NotEqual, ic.objReg, &ArrayClass); - stubcc.linkExitDirect(ic.claspGuard, ic.slowPathStart); + ic.shapeGuard = masm.branchPtr(Assembler::NotEqual, + Address(ic.objReg, offsetof(JSObject, lastProp)), + ImmPtr(denseArrayShape)); + stubcc.linkExitDirect(ic.shapeGuard, ic.slowPathStart); // Guard in range of initialized length. Jump initlenGuard = masm.guardArrayExtent(offsetof(JSObject, initializedLength), @@ -2108,9 +2116,17 @@ mjit::Compiler::jsop_getelem(bool isCall) stubcc.linkExitDirect(ic.typeGuard.get(), ic.slowPathStart); } - // Guard on the clasp. - ic.claspGuard = masm.testObjClass(Assembler::NotEqual, ic.objReg, &ArrayClass); - stubcc.linkExitDirect(ic.claspGuard, ic.slowPathStart); + if (!denseArrayShape) { + denseArrayShape = BaseShape::lookupEmpty(cx, &ArrayClass); + if (!denseArrayShape) + return false; + } + + // Guard obj is a dense array. + ic.shapeGuard = masm.branchPtr(Assembler::NotEqual, + Address(ic.objReg, offsetof(JSObject, lastProp)), + ImmPtr(denseArrayShape)); + stubcc.linkExitDirect(ic.shapeGuard, ic.slowPathStart); Int32Key key = id->isConstant() ? Int32Key::FromConstant(id->getValue().toInt32()) @@ -2132,8 +2148,8 @@ mjit::Compiler::jsop_getelem(bool isCall) } else { // The type is known to not be dense-friendly ahead of time, so always // fall back to a slow path. - ic.claspGuard = masm.jump(); - stubcc.linkExitDirect(ic.claspGuard, ic.slowPathStart); + ic.shapeGuard = masm.jump(); + stubcc.linkExitDirect(ic.shapeGuard, ic.slowPathStart); } stubcc.leave(); diff --git a/js/src/methodjit/MethodJIT.cpp b/js/src/methodjit/MethodJIT.cpp index 00d2ba28dfd5..df2b88ac43f0 100644 --- a/js/src/methodjit/MethodJIT.cpp +++ b/js/src/methodjit/MethodJIT.cpp @@ -1325,6 +1325,9 @@ JITScript::trace(JSTracer *trc) for (uint32 i = 0; i < nRootedObjects; ++i) MarkObject(trc, *rootedObjects()[i], "mjit rooted object"); + + if (denseArrayShape) + MarkShape(trc, denseArrayShape, "mjit rooted shape"); } /* static */ const double mjit::Assembler::oneDouble = 1.0; diff --git a/js/src/methodjit/MethodJIT.h b/js/src/methodjit/MethodJIT.h index e20eb400d77e..2ffbed13baa1 100644 --- a/js/src/methodjit/MethodJIT.h +++ b/js/src/methodjit/MethodJIT.h @@ -640,6 +640,9 @@ struct JITScript { // Additional ExecutablePools for native call and getter stubs. Vector nativeCallStubs; + // Rooted shape for dense arrays. :XXX: bug 685358 remove + Shape *denseArrayShape; + NativeMapEntry *nmap() const; js::mjit::InlineFrame *inlineFrames() const; js::mjit::CallSite *callSites() const; diff --git a/js/src/methodjit/MonoIC.cpp b/js/src/methodjit/MonoIC.cpp index 8096ca4ff894..054d44e3cb12 100644 --- a/js/src/methodjit/MonoIC.cpp +++ b/js/src/methodjit/MonoIC.cpp @@ -743,7 +743,7 @@ class CallCompiler : public BaseCompiler RegisterID t0 = tempRegs.takeAnyReg().reg(); /* Guard that it's actually a function object. */ - Jump claspGuard = masm.testObjClass(Assembler::NotEqual, ic.funObjReg, &FunctionClass); + Jump claspGuard = masm.testObjClass(Assembler::NotEqual, ic.funObjReg, t0, &FunctionClass); /* Guard that it's the same function. */ JSFunction *fun = obj->getFunctionPrivate(); diff --git a/js/src/methodjit/PolyIC.cpp b/js/src/methodjit/PolyIC.cpp index ce8cfb39ed7d..62d0ae2d85c5 100644 --- a/js/src/methodjit/PolyIC.cpp +++ b/js/src/methodjit/PolyIC.cpp @@ -815,7 +815,7 @@ class GetPropCompiler : public PICStubCompiler { Assembler masm; - Jump notArgs = masm.testObjClass(Assembler::NotEqual, pic.objReg, obj->getClass()); + Jump notArgs = masm.guardShape(pic.objReg, obj); masm.load32(Address(pic.objReg, JSObject::getFixedSlotOffset(ArgumentsObject::INITIAL_LENGTH_SLOT)), pic.objReg); masm.move(pic.objReg, pic.shapeReg); @@ -896,7 +896,7 @@ class GetPropCompiler : public PICStubCompiler { Assembler masm; - Jump notStringObj = masm.testObjClass(Assembler::NotEqual, pic.objReg, obj->getClass()); + Jump notStringObj = masm.guardShape(pic.objReg, obj); masm.loadPayload(Address(pic.objReg, JSObject::getPrimitiveThisOffset()), pic.objReg); masm.loadPtr(Address(pic.objReg, JSString::offsetOfLengthAndFlags()), pic.objReg); @@ -1185,7 +1185,9 @@ class GetPropCompiler : public PICStubCompiler bool setStubShapeOffset = true; if (obj->isDenseArray()) { start = masm.label(); - shapeGuardJump = masm.testObjClass(Assembler::NotEqual, pic.objReg, obj->getClass()); + shapeGuardJump = masm.branchPtr(Assembler::NotEqual, + Address(pic.objReg, offsetof(JSObject, lastProp)), + ImmPtr(obj->lastProperty())); /* * No need to assert validity of GETPROP_STUB_SHAPE_JUMP in this case: @@ -2331,8 +2333,8 @@ GetElementIC::purge(Repatcher &repatcher) // Repatch the inline jumps. if (inlineTypeGuardPatched) repatcher.relink(fastPathStart.jumpAtOffset(inlineTypeGuard), slowPathStart); - if (inlineClaspGuardPatched) - repatcher.relink(fastPathStart.jumpAtOffset(inlineClaspGuard), slowPathStart); + if (inlineShapeGuardPatched) + repatcher.relink(fastPathStart.jumpAtOffset(inlineShapeGuard), slowPathStart); if (slowCallPatched) { if (op == JSOP_GETELEM) { @@ -2392,13 +2394,8 @@ GetElementIC::attachGetProp(VMFrame &f, JSContext *cx, JSObject *obj, const Valu if (!idRemat.isConstant()) atomIdGuard = masm.branchPtr(Assembler::NotEqual, idRemat.dataReg(), ImmPtr(v.toString())); - // Guard on the base shape (or in the dense array case, the clasp). - Jump shapeGuard; - if (obj->isDenseArray()) { - shapeGuard = masm.testObjClass(Assembler::NotEqual, objReg, obj->getClass()); - } else { - shapeGuard = masm.branchPtr(Assembler::NotEqual, typeReg, ImmPtr(obj->lastProperty())); - } + // Guard on the base shape. + Jump shapeGuard = masm.branchPtr(Assembler::NotEqual, typeReg, ImmPtr(obj->lastProperty())); // Guard on the prototype, if applicable. MaybeJump protoGuard; @@ -2455,7 +2452,7 @@ GetElementIC::attachGetProp(VMFrame &f, JSContext *cx, JSObject *obj, const Valu #endif // Update the inline guards, if needed. - if (shouldPatchInlineTypeGuard() || shouldPatchUnconditionalClaspGuard()) { + if (shouldPatchInlineTypeGuard() || shouldPatchUnconditionalShapeGuard()) { Repatcher repatcher(cx->fp()->jit()); if (shouldPatchInlineTypeGuard()) { @@ -2468,15 +2465,15 @@ GetElementIC::attachGetProp(VMFrame &f, JSContext *cx, JSObject *obj, const Valu inlineTypeGuardPatched = true; } - if (shouldPatchUnconditionalClaspGuard()) { - // The clasp guard is unconditional, meaning there is no type + if (shouldPatchUnconditionalShapeGuard()) { + // The shape guard is unconditional, meaning there is no type // check. This is the first stub, so it has to be patched. Note - // that it is wrong to patch the inline clasp guard otherwise, + // that it is wrong to patch the inline shape guard otherwise, // because it follows an integer-id guard. JS_ASSERT(!hasInlineTypeGuard()); - repatcher.relink(fastPathStart.jumpAtOffset(inlineClaspGuard), cs); - inlineClaspGuardPatched = true; + repatcher.relink(fastPathStart.jumpAtOffset(inlineShapeGuard), cs); + inlineShapeGuardPatched = true; } } @@ -2536,7 +2533,7 @@ GetElementIC::attachArguments(JSContext *cx, JSObject *obj, const Value &v, jsid Assembler masm; - Jump claspGuard = masm.testObjClass(Assembler::NotEqual, objReg, obj->getClass()); + Jump shapeGuard = masm.guardShape(objReg, obj); masm.move(objReg, typeReg); masm.load32(Address(objReg, JSObject::getFixedSlotOffset(ArgumentsObject::INITIAL_LENGTH_SLOT)), @@ -2642,7 +2639,7 @@ GetElementIC::attachArguments(JSContext *cx, JSObject *obj, const Value &v, jsid if (!buffer.verifyRange(cx->fp()->jit())) return disable(cx, "code memory is out of range"); - buffer.link(claspGuard, slowPathStart); + buffer.link(shapeGuard, slowPathStart); buffer.link(overridden, slowPathStart); buffer.link(outOfBounds, slowPathStart); buffer.link(holeCheck, slowPathStart); @@ -2654,12 +2651,12 @@ GetElementIC::attachArguments(JSContext *cx, JSObject *obj, const Value &v, jsid JaegerSpew(JSpew_PICs, "generated getelem arguments stub at %p\n", cs.executableAddress()); Repatcher repatcher(cx->fp()->jit()); - repatcher.relink(fastPathStart.jumpAtOffset(inlineClaspGuard), cs); + repatcher.relink(fastPathStart.jumpAtOffset(inlineShapeGuard), cs); - JS_ASSERT(!shouldPatchUnconditionalClaspGuard()); - JS_ASSERT(!inlineClaspGuardPatched); + JS_ASSERT(!shouldPatchUnconditionalShapeGuard()); + JS_ASSERT(!inlineShapeGuardPatched); - inlineClaspGuardPatched = true; + inlineShapeGuardPatched = true; stubsGenerated++; if (stubsGenerated == MAX_GETELEM_IC_STUBS) @@ -2683,14 +2680,14 @@ GetElementIC::attachTypedArray(JSContext *cx, JSObject *obj, const Value &v, jsi if (op == JSOP_CALLELEM) return disable(cx, "typed array with call"); - // The fast-path guarantees that after the dense clasp guard, the type is + // The fast-path guarantees that after the dense shape guard, the type is // known to be int32, either via type inference or the inline type check. JS_ASSERT(hasInlineTypeGuard() || idRemat.knownType() == JSVAL_TYPE_INT32); Assembler masm; - // Guard on this typed array's clasp. - Jump claspGuard = masm.testObjClass(Assembler::NotEqual, objReg, obj->getClass()); + // Guard on this typed array's shape/class. + Jump shapeGuard = masm.guardShape(objReg, obj); // Bounds check. Jump outOfBounds; @@ -2724,21 +2721,21 @@ GetElementIC::attachTypedArray(JSContext *cx, JSObject *obj, const Value &v, jsi if (!buffer.verifyRange(cx->fp()->jit())) return disable(cx, "code memory is out of range"); - buffer.link(claspGuard, slowPathStart); + buffer.link(shapeGuard, slowPathStart); buffer.link(outOfBounds, slowPathStart); buffer.link(done, fastPathRejoin); CodeLocationLabel cs = buffer.finalizeCodeAddendum(); JaegerSpew(JSpew_PICs, "generated getelem typed array stub at %p\n", cs.executableAddress()); - // If we can generate a typed array stub, the clasp guard is conditional. + // If we can generate a typed array stub, the shape guard is conditional. // Also, we only support one typed array. - JS_ASSERT(!shouldPatchUnconditionalClaspGuard()); - JS_ASSERT(!inlineClaspGuardPatched); + JS_ASSERT(!shouldPatchUnconditionalShapeGuard()); + JS_ASSERT(!inlineShapeGuardPatched); Repatcher repatcher(cx->fp()->jit()); - repatcher.relink(fastPathStart.jumpAtOffset(inlineClaspGuard), cs); - inlineClaspGuardPatched = true; + repatcher.relink(fastPathStart.jumpAtOffset(inlineShapeGuard), cs); + inlineShapeGuardPatched = true; stubsGenerated++; @@ -2914,8 +2911,8 @@ void SetElementIC::purge(Repatcher &repatcher) { // Repatch the inline jumps. - if (inlineClaspGuardPatched) - repatcher.relink(fastPathStart.jumpAtOffset(inlineClaspGuard), slowPathStart); + if (inlineShapeGuardPatched) + repatcher.relink(fastPathStart.jumpAtOffset(inlineShapeGuard), slowPathStart); if (inlineHoleGuardPatched) repatcher.relink(fastPathStart.jumpAtOffset(inlineHoleGuard), slowPathStart); @@ -3028,13 +3025,13 @@ SetElementIC::attachHoleStub(JSContext *cx, JSObject *obj, int32 keyval) LookupStatus SetElementIC::attachTypedArray(JSContext *cx, JSObject *obj, int32 key) { - // Right now, only one clasp guard extension is supported. - JS_ASSERT(!inlineClaspGuardPatched); + // Right now, only one shape guard extension is supported. + JS_ASSERT(!inlineShapeGuardPatched); Assembler masm; - // Guard on this typed array's clasp. - Jump claspGuard = masm.testObjClass(Assembler::NotEqual, objReg, obj->getClass()); + // Guard on this typed array's shape. + Jump shapeGuard = masm.guardShape(objReg, obj); // Bounds check. Jump outOfBounds; @@ -3089,7 +3086,7 @@ SetElementIC::attachTypedArray(JSContext *cx, JSObject *obj, int32 key) return disable(cx, "code memory is out of range"); // Note that the out-of-bounds path simply does nothing. - buffer.link(claspGuard, slowPathStart); + buffer.link(shapeGuard, slowPathStart); buffer.link(outOfBounds, fastPathRejoin); buffer.link(done, fastPathRejoin); masm.finalize(buffer); @@ -3098,8 +3095,8 @@ SetElementIC::attachTypedArray(JSContext *cx, JSObject *obj, int32 key) JaegerSpew(JSpew_PICs, "generated setelem typed array stub at %p\n", cs.executableAddress()); Repatcher repatcher(cx->fp()->jit()); - repatcher.relink(fastPathStart.jumpAtOffset(inlineClaspGuard), cs); - inlineClaspGuardPatched = true; + repatcher.relink(fastPathStart.jumpAtOffset(inlineShapeGuard), cs); + inlineShapeGuardPatched = true; stubsGenerated++; diff --git a/js/src/methodjit/PolyIC.h b/js/src/methodjit/PolyIC.h index cfb8fc3840e6..9cd5b017d2b8 100644 --- a/js/src/methodjit/PolyIC.h +++ b/js/src/methodjit/PolyIC.h @@ -236,22 +236,22 @@ struct GetElementIC : public BasePolyIC { // This is only set if hasInlineTypeCheck() is true. unsigned inlineTypeGuard : 8; - // Offset from the fast path to the inline clasp guard. This is always + // Offset from the fast path to the inline shape guard. This is always // set; if |id| is known to not be int32, then it's an unconditional // jump to the slow path. - unsigned inlineClaspGuard : 8; + unsigned inlineShapeGuard : 8; // This is usable if hasInlineTypeGuard() returns true, which implies // that a dense array fast path exists. The inline type guard serves as // the head of the chain of all string-based element stubs. bool inlineTypeGuardPatched : 1; - // This is always usable, and specifies whether the inline clasp guard + // This is always usable, and specifies whether the inline shape guard // has been patched. If hasInlineTypeGuard() is true, it guards against // a dense array, and guarantees the inline type guard has passed. - // Otherwise, there is no inline type guard, and the clasp guard is just + // Otherwise, there is no inline type guard, and the shape guard is just // an unconditional jump. - bool inlineClaspGuardPatched : 1; + bool inlineShapeGuardPatched : 1; //////////////////////////////////////////// // State for string-based property stubs. // @@ -285,18 +285,18 @@ struct GetElementIC : public BasePolyIC { bool shouldPatchInlineTypeGuard() { return hasInlineTypeGuard() && !inlineTypeGuardPatched; } - bool shouldPatchUnconditionalClaspGuard() { - // The clasp guard is only unconditional if the type is known to not + bool shouldPatchUnconditionalShapeGuard() { + // The shape guard is only unconditional if the type is known to not // be an int32. if (idRemat.isTypeKnown() && idRemat.knownType() != JSVAL_TYPE_INT32) - return !inlineClaspGuardPatched; + return !inlineShapeGuardPatched; return false; } void reset() { BasePolyIC::reset(); inlineTypeGuardPatched = false; - inlineClaspGuardPatched = false; + inlineShapeGuardPatched = false; typeRegHasBaseShape = false; hasLastStringStub = false; } @@ -329,11 +329,11 @@ struct SetElementIC : public BaseIC { // Information on how to rematerialize |objReg|. int32 objRemat : MIN_STATE_REMAT_BITS; - // Offset from the start of the fast path to the inline clasp guard. - unsigned inlineClaspGuard : 6; + // Offset from the start of the fast path to the inline shape guard. + unsigned inlineShapeGuard : 6; - // True if the clasp guard has been patched; false otherwise. - bool inlineClaspGuardPatched : 1; + // True if the shape guard has been patched; false otherwise. + bool inlineShapeGuardPatched : 1; // Offset from the start of the fast path to the inline hole guard. unsigned inlineHoleGuard : 8; @@ -367,7 +367,7 @@ struct SetElementIC : public BaseIC { if (execPool != NULL) execPool->release(); execPool = NULL; - inlineClaspGuardPatched = false; + inlineShapeGuardPatched = false; inlineHoleGuardPatched = false; } void purge(Repatcher &repatcher); diff --git a/js/src/tracejit/Writer.cpp b/js/src/tracejit/Writer.cpp index 7fe7dabc4095..d9eeaac96115 100644 --- a/js/src/tracejit/Writer.cpp +++ b/js/src/tracejit/Writer.cpp @@ -410,7 +410,8 @@ void ValidateWriter::checkAccSet(LOpcode op, LIns *base, int32_t disp, AccSet ac couldBeObjectOrString(base)) case ACCSET_OBJ_CLASP: - ok = OK_OBJ_FIELD(LIR_ldp, clasp); + ok = false; + //ok = OK_OBJ_FIELD(LIR_ldp, clasp); break; case ACCSET_OBJ_FLAGS: diff --git a/js/src/tracejit/Writer.h b/js/src/tracejit/Writer.h index 6819b5f30e9b..f6d0a9425b6f 100644 --- a/js/src/tracejit/Writer.h +++ b/js/src/tracejit/Writer.h @@ -480,7 +480,8 @@ class Writer } nj::LIns *ldpObjClasp(nj::LIns *obj, nj::LoadQual loadQual) const { - return name(lir->insLoad(nj::LIR_ldp, obj, JSObject::offsetOfClassPointer(), ACCSET_OBJ_CLASP, + JS_NOT_REACHED("FIXME"); + return name(lir->insLoad(nj::LIR_ldp, obj, 0, ACCSET_OBJ_CLASP, loadQual), "clasp"); }