Remove direct class pointer from JSObject, bug 690133.

This commit is contained in:
Brian Hackett
2011-09-29 08:20:06 -07:00
parent b18259bebf
commit b9dce9b51c
23 changed files with 273 additions and 225 deletions

View File

@@ -1296,6 +1296,21 @@ JSObject::makeDenseArraySlow(JSContext *cx)
OBJECT_FLAG_NON_PACKED_ARRAY | OBJECT_FLAG_NON_PACKED_ARRAY |
OBJECT_FLAG_NON_DENSE_ARRAY); OBJECT_FLAG_NON_DENSE_ARRAY);
markDenseArrayNotPacked(cx); 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 * 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)) if (!InitScopeForObject(cx, this, &SlowArrayClass, getProto()->getNewType(cx), kind))
return false; 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; capacity = numFixedSlots() + arrayCapacity;
clasp = &SlowArrayClass;
/* /*
* Root all values in the array during conversion, as SlowArrayClass only * Root all values in the array during conversion, as SlowArrayClass only
@@ -1347,7 +1344,6 @@ JSObject::makeDenseArraySlow(JSContext *cx)
setMap(oldMap); setMap(oldMap);
capacity = arrayCapacity; capacity = arrayCapacity;
initializedLength = arrayInitialized; initializedLength = arrayInitialized;
clasp = &ArrayClass;
return false; return false;
} }
@@ -1370,7 +1366,6 @@ JSObject::makeDenseArraySlow(JSContext *cx)
setMap(oldMap); setMap(oldMap);
capacity = arrayCapacity; capacity = arrayCapacity;
initializedLength = arrayInitialized; initializedLength = arrayInitialized;
clasp = &ArrayClass;
return false; return false;
} }

View File

@@ -87,7 +87,8 @@ JSCompartment::JSCompartment(JSRuntime *rt)
regExpAllocator(NULL), regExpAllocator(NULL),
#endif #endif
propertyTree(thisForCtor()), propertyTree(thisForCtor()),
emptyArgumentsShape(NULL), emptyStrictArgumentsShape(NULL),
emptyNormalArgumentsShape(NULL),
emptyBlockShape(NULL), emptyBlockShape(NULL),
emptyCallShape(NULL), emptyCallShape(NULL),
emptyDeclEnvShape(NULL), emptyDeclEnvShape(NULL),
@@ -501,6 +502,14 @@ JSCompartment::markTypes(JSTracer *trc)
MarkTypeObject(trc, i.get<types::TypeObject>(), "mark_types_scan"); MarkTypeObject(trc, i.get<types::TypeObject>(), "mark_types_scan");
} }
template <class T>
void
CheckWeakShape(JSContext *cx, T *&shape)
{
if (shape && IsAboutToBeFinalized(cx, shape))
shape = NULL;
}
void void
JSCompartment::sweep(JSContext *cx, uint32 releaseInterval) JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
{ {
@@ -516,23 +525,16 @@ JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
} }
/* Remove dead empty shapes. */ /* Remove dead empty shapes. */
if (emptyArgumentsShape && IsAboutToBeFinalized(cx, emptyArgumentsShape)) CheckWeakShape(cx, emptyStrictArgumentsShape);
emptyArgumentsShape = NULL; CheckWeakShape(cx, emptyNormalArgumentsShape);
if (emptyBlockShape && IsAboutToBeFinalized(cx, emptyBlockShape)) CheckWeakShape(cx, emptyBlockShape);
emptyBlockShape = NULL; CheckWeakShape(cx, emptyCallShape);
if (emptyCallShape && IsAboutToBeFinalized(cx, emptyCallShape)) CheckWeakShape(cx, emptyDeclEnvShape);
emptyCallShape = NULL; CheckWeakShape(cx, emptyEnumeratorShape);
if (emptyDeclEnvShape && IsAboutToBeFinalized(cx, emptyDeclEnvShape)) CheckWeakShape(cx, emptyWithShape);
emptyDeclEnvShape = NULL;
if (emptyEnumeratorShape && IsAboutToBeFinalized(cx, emptyEnumeratorShape))
emptyEnumeratorShape = NULL;
if (emptyWithShape && IsAboutToBeFinalized(cx, emptyWithShape))
emptyWithShape = NULL;
if (initialRegExpShape && IsAboutToBeFinalized(cx, initialRegExpShape)) CheckWeakShape(cx, initialRegExpShape);
initialRegExpShape = NULL; CheckWeakShape(cx, initialStringShape);
if (initialStringShape && IsAboutToBeFinalized(cx, initialStringShape))
initialStringShape = NULL;
/* Remove dead base shapes */ /* Remove dead base shapes */
sweepBaseShapeTable(cx); sweepBaseShapeTable(cx);

View File

@@ -476,7 +476,8 @@ struct JS_FRIEND_API(JSCompartment) {
* Runtime-shared empty scopes for well-known built-in objects that lack * Runtime-shared empty scopes for well-known built-in objects that lack
* class prototypes (the usual locus of an emptyShape). Mnemonic: ABCDEW * class prototypes (the usual locus of an emptyShape). Mnemonic: ABCDEW
*/ */
js::EmptyShape *emptyArgumentsShape; js::EmptyShape *emptyStrictArgumentsShape;
js::EmptyShape *emptyNormalArgumentsShape;
js::EmptyShape *emptyBlockShape; js::EmptyShape *emptyBlockShape;
js::EmptyShape *emptyCallShape; js::EmptyShape *emptyCallShape;
js::EmptyShape *emptyDeclEnvShape; js::EmptyShape *emptyDeclEnvShape;

View File

@@ -203,7 +203,8 @@ ArgumentsObject::create(JSContext *cx, uint32 argc, JSObject &callee)
if (!obj) if (!obj)
return NULL; return NULL;
EmptyShape *emptyArgumentsShape = EmptyShape::getEmptyArgumentsShape(cx); bool strict = callee.getFunctionPrivate()->inStrictMode();
EmptyShape *emptyArgumentsShape = EmptyShape::getEmptyArgumentsShape(cx, strict);
if (!emptyArgumentsShape) if (!emptyArgumentsShape)
return NULL; return NULL;
@@ -214,10 +215,7 @@ ArgumentsObject::create(JSContext *cx, uint32 argc, JSObject &callee)
SetValueRangeToUndefined(data->slots, argc); SetValueRangeToUndefined(data->slots, argc);
/* Can't fail from here on, so initialize everything in argsobj. */ /* Can't fail from here on, so initialize everything in argsobj. */
obj->init(cx, callee.getFunctionPrivate()->inStrictMode() obj->init(cx, type, proto->getParent(), NULL, false);
? &StrictArgumentsObjectClass
: &NormalArgumentsObjectClass,
type, proto->getParent(), NULL, false);
obj->setMap(emptyArgumentsShape); obj->setMap(emptyArgumentsShape);
ArgumentsObject *argsobj = obj->asArguments(); ArgumentsObject *argsobj = obj->asArguments();
@@ -766,7 +764,7 @@ NewDeclEnvObject(JSContext *cx, StackFrame *fp)
EmptyShape *emptyDeclEnvShape = EmptyShape::getEmptyDeclEnvShape(cx); EmptyShape *emptyDeclEnvShape = EmptyShape::getEmptyDeclEnvShape(cx);
if (!emptyDeclEnvShape) if (!emptyDeclEnvShape)
return NULL; return NULL;
envobj->init(cx, &DeclEnvClass, &emptyTypeObject, &fp->scopeChain(), fp, false); envobj->init(cx, &emptyTypeObject, &fp->scopeChain(), fp, false);
envobj->setMap(emptyDeclEnvShape); envobj->setMap(emptyDeclEnvShape);
return envobj; return envobj;

View File

@@ -5609,7 +5609,7 @@ JSObject::makeLazyType(JSContext *cx)
type->markUnknown(cx); type->markUnknown(cx);
#endif #endif
if (clasp->ext.equality) if (getClass()->ext.equality)
type->flags |= OBJECT_FLAG_SPECIAL_EQUALITY; type->flags |= OBJECT_FLAG_SPECIAL_EQUALITY;
if (type->unknownProperties()) { if (type->unknownProperties()) {
@@ -5662,7 +5662,7 @@ JSObject::makeNewType(JSContext *cx, JSFunction *fun, bool unknown)
type->flags |= OBJECT_FLAG_UNKNOWN_MASK; type->flags |= OBJECT_FLAG_UNKNOWN_MASK;
#endif #endif
if (clasp->ext.equality) if (getClass()->ext.equality)
type->flags |= OBJECT_FLAG_SPECIAL_EQUALITY; type->flags |= OBJECT_FLAG_SPECIAL_EQUALITY;
/* /*

View File

@@ -418,7 +418,7 @@ NewIteratorObject(JSContext *cx, uintN flags)
EmptyShape *emptyEnumeratorShape = EmptyShape::getEmptyEnumeratorShape(cx); EmptyShape *emptyEnumeratorShape = EmptyShape::getEmptyEnumeratorShape(cx);
if (!emptyEnumeratorShape) if (!emptyEnumeratorShape)
return NULL; return NULL;
obj->init(cx, &IteratorClass, &types::emptyTypeObject, NULL, NULL, false); obj->init(cx, &types::emptyTypeObject, NULL, NULL, false);
obj->setMap(emptyEnumeratorShape); obj->setMap(emptyEnumeratorShape);
return obj; return obj;
} }

View File

@@ -3479,7 +3479,7 @@ js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth)
StackFrame *priv = js_FloatingFrameIfGenerator(cx, cx->fp()); 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); EmptyShape *emptyWithShape = EmptyShape::getEmptyWithShape(cx);
if (!emptyWithShape) if (!emptyWithShape)
@@ -3513,7 +3513,7 @@ js_NewBlockObject(JSContext *cx)
EmptyShape *emptyBlockShape = EmptyShape::getEmptyBlockShape(cx); EmptyShape *emptyBlockShape = EmptyShape::getEmptyBlockShape(cx);
if (!emptyBlockShape) if (!emptyBlockShape)
return NULL; return NULL;
blockObj->init(cx, &BlockClass, &emptyTypeObject, NULL, NULL, false); blockObj->init(cx, &emptyTypeObject, NULL, NULL, false);
blockObj->setMap(emptyBlockShape); blockObj->setMap(emptyBlockShape);
return blockObj; return blockObj;

View File

@@ -445,10 +445,6 @@ struct JSObject : js::gc::Cell {
friend class js::TraceRecorder; friend class js::TraceRecorder;
friend class nanojit::ValidateWriter; 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 * Private pointer to the last added property and methods to manipulate the
* list it links among properties in this scope. * list it links among properties in this scope.
@@ -456,7 +452,6 @@ struct JSObject : js::gc::Cell {
js::Shape *lastProp; js::Shape *lastProp;
private: private:
js::Class *clasp;
inline void setLastProperty(const js::Shape *shape); inline void setLastProperty(const js::Shape *shape);
inline void removeLastProperty(); inline void removeLastProperty();
@@ -544,17 +539,11 @@ struct JSObject : js::gc::Cell {
inline bool isNative() const; inline bool isNative() const;
inline bool isNewborn() const; inline bool isNewborn() const;
void setClass(js::Class *c) { clasp = c; } /* Inline functions defined in jsobjinlines.h */
js::Class *getClass() const { return clasp; } js::Class *getClass() const;
JSClass *getJSClass() const { return Jsvalify(clasp); } JSClass *getJSClass() const;
bool hasClass(const js::Class *c) const;
bool hasClass(const js::Class *c) const { const js::ObjectOps *getOps() const;
return c == clasp;
}
const js::ObjectOps *getOps() const {
return &getClass()->ops;
}
inline void trace(JSTracer *trc); inline void trace(JSTracer *trc);
inline void scanSlots(js::GCMarker *gcmarker); inline void scanSlots(js::GCMarker *gcmarker);
@@ -578,7 +567,7 @@ struct JSObject : js::gc::Cell {
bool hasSpecialEquality() const { return !!(flags & HAS_EQUALITY); } bool hasSpecialEquality() const { return !!(flags & HAS_EQUALITY); }
void assertSpecialEqualitySynced() const { 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. */ /* 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. */ /* 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); JSObject *parent, void *priv, bool denseArray);
inline void finish(JSContext *cx); inline void finish(JSContext *cx);
@@ -1419,56 +1408,52 @@ struct JSObject : js::gc::Cell {
const js::Shape *defineBlockVariable(JSContext *cx, jsid id, intN index); const js::Shape *defineBlockVariable(JSContext *cx, jsid id, intN index);
inline bool isArguments() const { return isNormalArguments() || isStrictArguments(); } inline bool isArguments() const { return isNormalArguments() || isStrictArguments(); }
inline bool isArrayBuffer() const { return clasp == &js::ArrayBufferClass; } inline bool isArrayBuffer() const { return hasClass(&js::ArrayBufferClass); }
inline bool isNormalArguments() const { return clasp == &js::NormalArgumentsObjectClass; } inline bool isNormalArguments() const { return hasClass(&js::NormalArgumentsObjectClass); }
inline bool isStrictArguments() const { return clasp == &js::StrictArgumentsObjectClass; } inline bool isStrictArguments() const { return hasClass(&js::StrictArgumentsObjectClass); }
inline bool isArray() const { return isSlowArray() || isDenseArray(); } inline bool isArray() const { return isSlowArray() || isDenseArray(); }
inline bool isDenseArray() const { return clasp == &js::ArrayClass; } inline bool isDenseArray() const { return hasClass(&js::ArrayClass); }
inline bool isSlowArray() const { return clasp == &js::SlowArrayClass; } inline bool isSlowArray() const { return hasClass(&js::SlowArrayClass); }
inline bool isNumber() const { return clasp == &js::NumberClass; } inline bool isNumber() const { return hasClass(&js::NumberClass); }
inline bool isBoolean() const { return clasp == &js::BooleanClass; } inline bool isBoolean() const { return hasClass(&js::BooleanClass); }
inline bool isString() const { return clasp == &js::StringClass; } inline bool isString() const { return hasClass(&js::StringClass); }
inline bool isPrimitive() const { return isNumber() || isString() || isBoolean(); } inline bool isPrimitive() const { return isNumber() || isString() || isBoolean(); }
inline bool isDate() const { return clasp == &js::DateClass; } inline bool isDate() const { return hasClass(&js::DateClass); }
inline bool isFunction() const { return clasp == &js::FunctionClass; } inline bool isFunction() const { return hasClass(&js::FunctionClass); }
inline bool isObject() const { return clasp == &js::ObjectClass; } inline bool isObject() const { return hasClass(&js::ObjectClass); }
inline bool isWith() const { return clasp == &js::WithClass; } inline bool isWith() const { return hasClass(&js::WithClass); }
inline bool isBlock() const { return clasp == &js::BlockClass; } inline bool isBlock() const { return hasClass(&js::BlockClass); }
inline bool isStaticBlock() const { return isBlock() && !getProto(); } inline bool isStaticBlock() const { return isBlock() && !getProto(); }
inline bool isClonedBlock() const { return isBlock() && !!getProto(); } inline bool isClonedBlock() const { return isBlock() && !!getProto(); }
inline bool isCall() const { return clasp == &js::CallClass; } inline bool isCall() const { return hasClass(&js::CallClass); }
inline bool isDeclEnv() const { return clasp == &js::DeclEnvClass; } inline bool isDeclEnv() const { return hasClass(&js::DeclEnvClass); }
inline bool isRegExp() const { return clasp == &js::RegExpClass; } inline bool isRegExp() const { return hasClass(&js::RegExpClass); }
inline bool isScript() const { return clasp == &js::ScriptClass; } inline bool isScript() const { return hasClass(&js::ScriptClass); }
inline bool isGenerator() const { return clasp == &js::GeneratorClass; } inline bool isGenerator() const { return hasClass(&js::GeneratorClass); }
inline bool isIterator() const { return clasp == &js::IteratorClass; } inline bool isIterator() const { return hasClass(&js::IteratorClass); }
inline bool isStopIteration() const { return clasp == &js::StopIterationClass; } inline bool isStopIteration() const { return hasClass(&js::StopIterationClass); }
inline bool isError() const { return clasp == &js::ErrorClass; } inline bool isError() const { return hasClass(&js::ErrorClass); }
inline bool isXML() const { return clasp == &js::XMLClass; } inline bool isXML() const { return hasClass(&js::XMLClass); }
inline bool isNamespace() const { return clasp == &js::NamespaceClass; } inline bool isNamespace() const { return hasClass(&js::NamespaceClass); }
inline bool isWeakMap() const { return clasp == &js::WeakMapClass; } inline bool isWeakMap() const { return hasClass(&js::WeakMapClass); }
inline bool isFunctionProxy() const { return clasp == &js::FunctionProxyClass; } inline bool isFunctionProxy() const { return hasClass(&js::FunctionProxyClass); }
inline bool isProxy() const { return isObjectProxy() || isFunctionProxy(); } inline bool isProxy() const { return isObjectProxy() || isFunctionProxy(); }
inline bool isXMLId() const { 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 { 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 { inline bool isObjectProxy() const {
return clasp == &js::ObjectProxyClass || clasp == &js::OuterWindowProxyClass; return hasClass(&js::ObjectProxyClass) || hasClass(&js::OuterWindowProxyClass);
} }
JS_FRIEND_API(bool) isWrapper() const; JS_FRIEND_API(bool) isWrapper() const;
bool isCrossCompartmentWrapper() const; bool isCrossCompartmentWrapper() const;
JS_FRIEND_API(JSObject *) unwrap(uintN *flagsp = NULL); JS_FRIEND_API(JSObject *) unwrap(uintN *flagsp = NULL);
inline void initArrayClass(); inline void initArrayClass();
/*** For jit compiler: ***/
static size_t offsetOfClassPointer() { return offsetof(JSObject, clasp); }
}; };
/* Check alignment for any fixed slots allocated after the object. */ /* Check alignment for any fixed slots allocated after the object. */

View File

@@ -181,9 +181,12 @@ JSObject::finalize(JSContext *cx)
inline bool inline bool
JSObject::initCall(JSContext *cx, const js::Bindings &bindings, JSObject *parent) 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()); setMap(bindings.lastShape());
JS_ASSERT(isCall());
JS_ASSERT(!inDictionaryMode());
/* /*
* If |bindings| is for a function that has extensible parents, that means * If |bindings| is for a function that has extensible parents, that means
* its Call should have its own shape; see js::BaseShape::extensibleParents. * 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 inline bool
JSObject::initClonedBlock(JSContext *cx, js::types::TypeObject *type, js::StackFrame *frame) 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); setMap(getProto()->lastProp);
JS_ASSERT(!inDictionaryMode());
JS_ASSERT(isClonedBlock());
if (lastProp->extensibleParents()) if (lastProp->extensibleParents())
return generateOwnShape(cx); return generateOwnShape(cx);
return true; return true;
@@ -767,14 +771,11 @@ JSObject::setType(js::types::TypeObject *newType)
} }
inline void 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) JSObject *parent, void *priv, bool denseArray)
{ {
clasp = aclasp;
flags = capacity << FIXED_SLOTS_SHIFT; flags = capacity << FIXED_SLOTS_SHIFT;
JS_ASSERT(denseArray == (aclasp == &js::ArrayClass));
privateData = priv; privateData = priv;
/* /*
@@ -813,15 +814,15 @@ JSObject::initSharingEmptyShape(JSContext *cx,
void *privateValue, void *privateValue,
js::gc::AllocKind kind) js::gc::AllocKind kind)
{ {
init(cx, aclasp, type, parent, privateValue, false); init(cx, type, parent, privateValue, false);
JS_ASSERT(!isDenseArray());
js::EmptyShape *empty = type->getEmptyShape(cx, aclasp, kind); js::EmptyShape *empty = type->getEmptyShape(cx, aclasp, kind);
if (!empty) if (!empty)
return false; return false;
setMap(empty); setMap(empty);
JS_ASSERT(!isDenseArray());
return true; 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. */ /* Share proto's emptyShape only if obj is similar to proto. */
js::EmptyShape *empty = NULL; js::EmptyShape *empty = NULL;
uint32 freeslot = JSSLOT_FREE(clasp);
if (freeslot > obj->numSlots() && !obj->allocSlots(cx, freeslot))
goto bad;
if (type->canProvideEmptyShape(clasp)) if (type->canProvideEmptyShape(clasp))
empty = type->getEmptyShape(cx, clasp, kind); empty = type->getEmptyShape(cx, clasp, kind);
else else
empty = js::EmptyShape::create(cx, clasp); empty = js::EmptyShape::create(cx, clasp);
if (!empty) if (!empty) {
goto bad; JS_ASSERT(obj->isNewborn());
return false;
}
obj->setMap(empty); obj->setMap(empty);
return true;
bad: uint32 freeslot = JSSLOT_FREE(clasp);
/* The GC nulls map initially. It should still be null on error. */ if (freeslot > obj->numSlots() && !obj->allocSlots(cx, freeslot)) {
JS_ASSERT(obj->isNewborn()); obj->setMap(NULL);
return false; JS_ASSERT(obj->isNewborn());
return false;
}
return true;
} }
static inline bool static inline bool
@@ -1212,7 +1214,7 @@ NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto,
* the parent of the prototype's constructor. * the parent of the prototype's constructor.
*/ */
bool denseArray = (clasp == &ArrayClass); 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_ASSERT(type->canProvideEmptyShape(clasp));
js::EmptyShape *empty = type->getEmptyShape(cx, clasp, kind); 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 * Default parent to the parent of the prototype, which was set from
* the parent of the prototype's constructor. * the parent of the prototype's constructor.
*/ */
obj->init(cx, clasp, type, obj->init(cx, type,
(!parent && proto) ? proto->getParent() : parent, (!parent && proto) ? proto->getParent() : parent,
NULL, clasp == &ArrayClass); 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 * Default parent to the parent of the prototype, which was set from
* the parent of the prototype's constructor. * the parent of the prototype's constructor.
*/ */
obj->init(cx, &ObjectClass, type, obj->init(cx, type,
(!parent && type->proto) ? type->proto->getParent() : parent, (!parent && type->proto) ? type->proto->getParent() : parent,
NULL, false); NULL, false);
@@ -1609,4 +1611,24 @@ js_GetProtoIfDenseArray(JSObject *obj)
return obj->isDenseArray() ? obj->getProto() : 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___ */ #endif /* jsobjinlines_h___ */

View File

@@ -764,6 +764,9 @@ struct Shape : public js::gc::Cell
void finalize(JSContext *cx); void finalize(JSContext *cx);
void removeChild(js::Shape *child); void removeChild(js::Shape *child);
void removeChildSlowly(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 struct EmptyShape : public js::Shape
@@ -792,8 +795,7 @@ struct EmptyShape : public js::Shape
return 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 *getEmptyBlockShape(JSContext *cx);
static inline EmptyShape *getEmptyCallShape(JSContext *cx); static inline EmptyShape *getEmptyCallShape(JSContext *cx);
static inline EmptyShape *getEmptyDeclEnvShape(JSContext *cx); static inline EmptyShape *getEmptyDeclEnvShape(JSContext *cx);

View File

@@ -324,9 +324,11 @@ EmptyShape::EmptyShape(BaseShape *base)
} }
/* static */ inline EmptyShape * /* 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 * /* static */ inline EmptyShape *

View File

@@ -215,7 +215,6 @@ ArrayBuffer::create(JSContext *cx, int32 nbytes)
if (!InitNonNativeObject(cx, obj, &ArrayBufferClass)) if (!InitNonNativeObject(cx, obj, &ArrayBufferClass))
return NULL; return NULL;
obj->setClass(&ArrayBufferClass);
/* /*
* The first 8 bytes hold the length. * The first 8 bytes hold the length.
@@ -1290,7 +1289,6 @@ class TypedArrayTemplate
if (!InitNonNativeObject(cx, obj, fastClass())) if (!InitNonNativeObject(cx, obj, fastClass()))
return NULL; return NULL;
obj->setClass(fastClass());
// FIXME Bug 599008: make it ok to call preventExtensions here. // FIXME Bug 599008: make it ok to call preventExtensions here.
obj->flags |= JSObject::NOT_EXTENSIBLE; obj->flags |= JSObject::NOT_EXTENSIBLE;

View File

@@ -194,11 +194,6 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::SparcRegist
ImmPtr(obj->lastProperty())); 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. * 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); addPtr(JSFrameReg, reg);
} }
void loadObjClass(RegisterID objReg, RegisterID destReg) { void loadObjClass(RegisterID obj, RegisterID dest) {
loadPtr(Address(objReg, JSObject::offsetOfClassPointer()), destReg); 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) { Jump testClass(Condition cond, RegisterID claspReg, js::Class *clasp) {
return branchPtr(cond, claspReg, ImmPtr(clasp)); return branchPtr(cond, claspReg, ImmPtr(clasp));
} }
Jump testObjClass(Condition cond, RegisterID objReg, js::Class *clasp) { Jump testObjClass(Condition cond, RegisterID obj, RegisterID temp, js::Class *clasp) {
return branchPtr(cond, Address(objReg, JSObject::offsetOfClassPointer()), ImmPtr(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) 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->lastProp), Address(result, offsetof(JSObject, lastProp)));
storePtr(ImmPtr(templateObject->getClass()), Address(result, JSObject::offsetOfClassPointer()));
store32(Imm32(templateObject->flags), Address(result, offsetof(JSObject, flags))); store32(Imm32(templateObject->flags), Address(result, offsetof(JSObject, flags)));
storePtr(ImmPtr(templateObject->newType), Address(result, offsetof(JSObject, newType))); storePtr(ImmPtr(templateObject->newType), Address(result, offsetof(JSObject, newType)));
storePtr(ImmPtr(templateObject->parent), Address(result, offsetof(JSObject, parent))); storePtr(ImmPtr(templateObject->parent), Address(result, offsetof(JSObject, parent)));

View File

@@ -123,6 +123,7 @@ mjit::Compiler::Compiler(JSContext *cx, JSScript *outerScript, bool isConstructi
jumpTableOffsets(CompilerAllocPolicy(cx, *thisFromCtor())), jumpTableOffsets(CompilerAllocPolicy(cx, *thisFromCtor())),
loopEntries(CompilerAllocPolicy(cx, *thisFromCtor())), loopEntries(CompilerAllocPolicy(cx, *thisFromCtor())),
rootedObjects(CompilerAllocPolicy(cx, *thisFromCtor())), rootedObjects(CompilerAllocPolicy(cx, *thisFromCtor())),
denseArrayShape(NULL),
stubcc(cx, *thisFromCtor(), frame), stubcc(cx, *thisFromCtor(), frame),
debugMode_(cx->compartment->debugMode()), debugMode_(cx->compartment->debugMode()),
#if defined JS_TRACER #if defined JS_TRACER
@@ -996,6 +997,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
jit->fastEntry = fullCode.locationOf(invokeLabel).executableAddress(); jit->fastEntry = fullCode.locationOf(invokeLabel).executableAddress();
} }
jit->pcLengths = pcLengths; jit->pcLengths = pcLengths;
jit->denseArrayShape = denseArrayShape;
/* /*
* WARNING: mics(), callICs() et al depend on the ordering of these * WARNING: mics(), callICs() et al depend on the ordering of these
@@ -1313,10 +1315,10 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
to.inlineTypeGuard = inlineTypeGuard; to.inlineTypeGuard = inlineTypeGuard;
JS_ASSERT(to.inlineTypeGuard == inlineTypeGuard); JS_ASSERT(to.inlineTypeGuard == inlineTypeGuard);
} }
int inlineClaspGuard = fullCode.locationOf(from.claspGuard) - int inlineShapeGuard = fullCode.locationOf(from.shapeGuard) -
fullCode.locationOf(from.fastPathStart); fullCode.locationOf(from.fastPathStart);
to.inlineClaspGuard = inlineClaspGuard; to.inlineShapeGuard = inlineShapeGuard;
JS_ASSERT(to.inlineClaspGuard == inlineClaspGuard); JS_ASSERT(to.inlineShapeGuard == inlineShapeGuard);
stubCode.patch(from.paramAddr, &to); stubCode.patch(from.paramAddr, &to);
} }
@@ -1343,10 +1345,10 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
else else
to.keyReg = from.key.reg(); to.keyReg = from.key.reg();
int inlineClaspGuard = fullCode.locationOf(from.claspGuard) - int inlineShapeGuard = fullCode.locationOf(from.shapeGuard) -
fullCode.locationOf(from.fastPathStart); fullCode.locationOf(from.fastPathStart);
to.inlineClaspGuard = inlineClaspGuard; to.inlineShapeGuard = inlineShapeGuard;
JS_ASSERT(to.inlineClaspGuard == inlineClaspGuard); JS_ASSERT(to.inlineShapeGuard == inlineShapeGuard);
int inlineHoleGuard = fullCode.locationOf(from.holeGuard) - int inlineHoleGuard = fullCode.locationOf(from.holeGuard) -
fullCode.locationOf(from.fastPathStart); fullCode.locationOf(from.fastPathStart);
@@ -3320,6 +3322,16 @@ mjit::Compiler::checkCallApplySpeculation(uint32 callImmArgc, uint32 speculatedA
{ {
JS_ASSERT(IsLowerableFunCallOrApply(PC)); 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() && * if (origCallee.isObject() &&
* origCallee.toObject().isFunction && * origCallee.toObject().isFunction &&
@@ -3328,7 +3340,7 @@ mjit::Compiler::checkCallApplySpeculation(uint32 callImmArgc, uint32 speculatedA
MaybeJump isObj; MaybeJump isObj;
if (origCalleeType.isSet()) if (origCalleeType.isSet())
isObj = masm.testObject(Assembler::NotEqual, origCalleeType.reg()); 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); masm.loadObjPrivate(origCalleeData, origCalleeData);
Native native = *PC == JSOP_FUNCALL ? js_fun_call : js_fun_apply; Native native = *PC == JSOP_FUNCALL ? js_fun_call : js_fun_apply;
Jump isNative = masm.branchPtr(Assembler::NotEqual, Jump isNative = masm.branchPtr(Assembler::NotEqual,
@@ -3601,14 +3613,15 @@ mjit::Compiler::inlineCallHelper(uint32 callImmArgc, bool callingNew, FrameSize
stubcc.linkExitDirect(j, stubcc.masm.label()); stubcc.linkExitDirect(j, stubcc.masm.label());
callIC.slowPathStart = 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 * Test if the callee is even a function. If this doesn't match, we
* take a _really_ slow path later. * 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. */ /* Test if the function is scripted. */
RegisterID tmp = tempRegs.takeAnyReg().reg();
stubcc.masm.loadObjPrivate(icCalleeData, funPtrReg); stubcc.masm.loadObjPrivate(icCalleeData, funPtrReg);
stubcc.masm.load16(Address(funPtrReg, offsetof(JSFunction, flags)), tmp); stubcc.masm.load16(Address(funPtrReg, offsetof(JSFunction, flags)), tmp);
stubcc.masm.and32(Imm32(JSFUN_KINDMASK), tmp); stubcc.masm.and32(Imm32(JSFUN_KINDMASK), tmp);
@@ -5740,7 +5753,7 @@ mjit::Compiler::iterNext(ptrdiff_t offset)
frame.unpinReg(reg); frame.unpinReg(reg);
/* Test clasp */ /* Test clasp */
Jump notFast = masm.testObjClass(Assembler::NotEqual, reg, &IteratorClass); Jump notFast = masm.testObjClass(Assembler::NotEqual, reg, T1, &IteratorClass);
stubcc.linkExit(notFast, Uses(1)); stubcc.linkExit(notFast, Uses(1));
/* Get private from iter obj. */ /* Get private from iter obj. */
@@ -5795,7 +5808,7 @@ mjit::Compiler::iterMore(jsbytecode *target)
RegisterID tempreg = frame.allocReg(); RegisterID tempreg = frame.allocReg();
/* Test clasp */ /* Test clasp */
Jump notFast = masm.testObjClass(Assembler::NotEqual, reg, &IteratorClass); Jump notFast = masm.testObjClass(Assembler::NotEqual, reg, tempreg, &IteratorClass);
stubcc.linkExitForBranch(notFast); stubcc.linkExitForBranch(notFast);
/* Get private from iter obj. */ /* Get private from iter obj. */
@@ -5834,7 +5847,7 @@ mjit::Compiler::iterEnd()
frame.unpinReg(reg); frame.unpinReg(reg);
/* Test clasp */ /* Test clasp */
Jump notIterator = masm.testObjClass(Assembler::NotEqual, reg, &IteratorClass); Jump notIterator = masm.testObjClass(Assembler::NotEqual, reg, T1, &IteratorClass);
stubcc.linkExit(notIterator, Uses(1)); stubcc.linkExit(notIterator, Uses(1));
/* Get private from iter obj. */ /* 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. */ /* If the callee is not an object, jump to the inline fast path. */
MaybeRegisterID typeReg = frame.maybePinType(fval); MaybeRegisterID typeReg = frame.maybePinType(fval);
RegisterID objReg = frame.copyDataIntoReg(fval); RegisterID objReg = frame.copyDataIntoReg(fval);
RegisterID tempReg = frame.allocReg();
MaybeJump isNotObj; MaybeJump isNotObj;
if (!fval->isType(JSVAL_TYPE_OBJECT)) { 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. * 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)); stubcc.linkExit(notFunction, Uses(1));
/* /*
@@ -6115,6 +6129,7 @@ mjit::Compiler::jsop_callgname_epilogue()
Jump globalMismatch = masm.branchPtr(Assembler::NotEqual, objReg, ImmPtr(globalObj)); Jump globalMismatch = masm.branchPtr(Assembler::NotEqual, objReg, ImmPtr(globalObj));
stubcc.linkExit(globalMismatch, Uses(1)); stubcc.linkExit(globalMismatch, Uses(1));
frame.freeReg(objReg); frame.freeReg(objReg);
frame.freeReg(tempReg);
/* OOL stub call path. */ /* OOL stub call path. */
stubcc.leave(); stubcc.leave();
@@ -6292,10 +6307,14 @@ mjit::Compiler::jsop_instanceof()
frame.forgetMismatchedObject(lhs); frame.forgetMismatchedObject(lhs);
frame.forgetMismatchedObject(rhs); frame.forgetMismatchedObject(rhs);
RegisterID tmp = frame.allocReg();
RegisterID obj = frame.tempRegForData(rhs); 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)); stubcc.linkExit(notFunction, Uses(2));
frame.freeReg(tmp);
/* Test for bound functions. */ /* Test for bound functions. */
Jump isBound = masm.branchTest32(Assembler::NonZero, Address(obj, offsetof(JSObject, flags)), Jump isBound = masm.branchTest32(Assembler::NonZero, Address(obj, offsetof(JSObject, flags)),
Imm32(JSObject::BOUND_FUNCTION)); Imm32(JSObject::BOUND_FUNCTION));

View File

@@ -214,7 +214,7 @@ class Compiler : public BaseCompiler
RegisterID objReg; RegisterID objReg;
ValueRemat id; ValueRemat id;
MaybeJump typeGuard; MaybeJump typeGuard;
Jump claspGuard; Jump shapeGuard;
}; };
struct SetElementICInfo : public BaseICInfo { struct SetElementICInfo : public BaseICInfo {
@@ -224,7 +224,7 @@ class Compiler : public BaseCompiler
StateRemat objRemat; StateRemat objRemat;
ValueRemat vr; ValueRemat vr;
Jump capacityGuard; Jump capacityGuard;
Jump claspGuard; Jump shapeGuard;
Jump holeGuard; Jump holeGuard;
Int32Key key; Int32Key key;
uint32 volatileMask; uint32 volatileMask;
@@ -436,6 +436,7 @@ class Compiler : public BaseCompiler
js::Vector<uint32, 16> jumpTableOffsets; js::Vector<uint32, 16> jumpTableOffsets;
js::Vector<LoopEntry, 16> loopEntries; js::Vector<LoopEntry, 16> loopEntries;
js::Vector<JSObject *, 0, CompilerAllocPolicy> rootedObjects; js::Vector<JSObject *, 0, CompilerAllocPolicy> rootedObjects;
Shape *denseArrayShape;
StubCompiler stubcc; StubCompiler stubcc;
Label invokeLabel; Label invokeLabel;
Label arityLabel; Label arityLabel;

View File

@@ -1555,9 +1555,17 @@ mjit::Compiler::jsop_setelem(bool popGuaranteed)
RESERVE_OOL_SPACE(stubcc.masm); RESERVE_OOL_SPACE(stubcc.masm);
ic.slowPathStart = stubcc.syncExit(Uses(3)); ic.slowPathStart = stubcc.syncExit(Uses(3));
if (!denseArrayShape) {
denseArrayShape = BaseShape::lookupEmpty(cx, &ArrayClass);
if (!denseArrayShape)
return false;
}
// Guard obj is a dense array. // Guard obj is a dense array.
ic.claspGuard = masm.testObjClass(Assembler::NotEqual, ic.objReg, &ArrayClass); ic.shapeGuard = masm.branchPtr(Assembler::NotEqual,
stubcc.linkExitDirect(ic.claspGuard, ic.slowPathStart); Address(ic.objReg, offsetof(JSObject, lastProp)),
ImmPtr(denseArrayShape));
stubcc.linkExitDirect(ic.shapeGuard, ic.slowPathStart);
// Guard in range of initialized length. // Guard in range of initialized length.
Jump initlenGuard = masm.guardArrayExtent(offsetof(JSObject, initializedLength), Jump initlenGuard = masm.guardArrayExtent(offsetof(JSObject, initializedLength),
@@ -2108,9 +2116,17 @@ mjit::Compiler::jsop_getelem(bool isCall)
stubcc.linkExitDirect(ic.typeGuard.get(), ic.slowPathStart); stubcc.linkExitDirect(ic.typeGuard.get(), ic.slowPathStart);
} }
// Guard on the clasp. if (!denseArrayShape) {
ic.claspGuard = masm.testObjClass(Assembler::NotEqual, ic.objReg, &ArrayClass); denseArrayShape = BaseShape::lookupEmpty(cx, &ArrayClass);
stubcc.linkExitDirect(ic.claspGuard, ic.slowPathStart); 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 key = id->isConstant()
? Int32Key::FromConstant(id->getValue().toInt32()) ? Int32Key::FromConstant(id->getValue().toInt32())
@@ -2132,8 +2148,8 @@ mjit::Compiler::jsop_getelem(bool isCall)
} else { } else {
// The type is known to not be dense-friendly ahead of time, so always // The type is known to not be dense-friendly ahead of time, so always
// fall back to a slow path. // fall back to a slow path.
ic.claspGuard = masm.jump(); ic.shapeGuard = masm.jump();
stubcc.linkExitDirect(ic.claspGuard, ic.slowPathStart); stubcc.linkExitDirect(ic.shapeGuard, ic.slowPathStart);
} }
stubcc.leave(); stubcc.leave();

View File

@@ -1325,6 +1325,9 @@ JITScript::trace(JSTracer *trc)
for (uint32 i = 0; i < nRootedObjects; ++i) for (uint32 i = 0; i < nRootedObjects; ++i)
MarkObject(trc, *rootedObjects()[i], "mjit rooted object"); MarkObject(trc, *rootedObjects()[i], "mjit rooted object");
if (denseArrayShape)
MarkShape(trc, denseArrayShape, "mjit rooted shape");
} }
/* static */ const double mjit::Assembler::oneDouble = 1.0; /* static */ const double mjit::Assembler::oneDouble = 1.0;

View File

@@ -640,6 +640,9 @@ struct JITScript {
// Additional ExecutablePools for native call and getter stubs. // Additional ExecutablePools for native call and getter stubs.
Vector<NativeCallStub, 0, SystemAllocPolicy> nativeCallStubs; Vector<NativeCallStub, 0, SystemAllocPolicy> nativeCallStubs;
// Rooted shape for dense arrays. :XXX: bug 685358 remove
Shape *denseArrayShape;
NativeMapEntry *nmap() const; NativeMapEntry *nmap() const;
js::mjit::InlineFrame *inlineFrames() const; js::mjit::InlineFrame *inlineFrames() const;
js::mjit::CallSite *callSites() const; js::mjit::CallSite *callSites() const;

View File

@@ -743,7 +743,7 @@ class CallCompiler : public BaseCompiler
RegisterID t0 = tempRegs.takeAnyReg().reg(); RegisterID t0 = tempRegs.takeAnyReg().reg();
/* Guard that it's actually a function object. */ /* 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. */ /* Guard that it's the same function. */
JSFunction *fun = obj->getFunctionPrivate(); JSFunction *fun = obj->getFunctionPrivate();

View File

@@ -815,7 +815,7 @@ class GetPropCompiler : public PICStubCompiler
{ {
Assembler masm; 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.load32(Address(pic.objReg, JSObject::getFixedSlotOffset(ArgumentsObject::INITIAL_LENGTH_SLOT)), pic.objReg);
masm.move(pic.objReg, pic.shapeReg); masm.move(pic.objReg, pic.shapeReg);
@@ -896,7 +896,7 @@ class GetPropCompiler : public PICStubCompiler
{ {
Assembler masm; 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.loadPayload(Address(pic.objReg, JSObject::getPrimitiveThisOffset()), pic.objReg);
masm.loadPtr(Address(pic.objReg, JSString::offsetOfLengthAndFlags()), pic.objReg); masm.loadPtr(Address(pic.objReg, JSString::offsetOfLengthAndFlags()), pic.objReg);
@@ -1185,7 +1185,9 @@ class GetPropCompiler : public PICStubCompiler
bool setStubShapeOffset = true; bool setStubShapeOffset = true;
if (obj->isDenseArray()) { if (obj->isDenseArray()) {
start = masm.label(); 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: * 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. // Repatch the inline jumps.
if (inlineTypeGuardPatched) if (inlineTypeGuardPatched)
repatcher.relink(fastPathStart.jumpAtOffset(inlineTypeGuard), slowPathStart); repatcher.relink(fastPathStart.jumpAtOffset(inlineTypeGuard), slowPathStart);
if (inlineClaspGuardPatched) if (inlineShapeGuardPatched)
repatcher.relink(fastPathStart.jumpAtOffset(inlineClaspGuard), slowPathStart); repatcher.relink(fastPathStart.jumpAtOffset(inlineShapeGuard), slowPathStart);
if (slowCallPatched) { if (slowCallPatched) {
if (op == JSOP_GETELEM) { if (op == JSOP_GETELEM) {
@@ -2392,13 +2394,8 @@ GetElementIC::attachGetProp(VMFrame &f, JSContext *cx, JSObject *obj, const Valu
if (!idRemat.isConstant()) if (!idRemat.isConstant())
atomIdGuard = masm.branchPtr(Assembler::NotEqual, idRemat.dataReg(), ImmPtr(v.toString())); atomIdGuard = masm.branchPtr(Assembler::NotEqual, idRemat.dataReg(), ImmPtr(v.toString()));
// Guard on the base shape (or in the dense array case, the clasp). // Guard on the base shape.
Jump shapeGuard; Jump shapeGuard = masm.branchPtr(Assembler::NotEqual, typeReg, ImmPtr(obj->lastProperty()));
if (obj->isDenseArray()) {
shapeGuard = masm.testObjClass(Assembler::NotEqual, objReg, obj->getClass());
} else {
shapeGuard = masm.branchPtr(Assembler::NotEqual, typeReg, ImmPtr(obj->lastProperty()));
}
// Guard on the prototype, if applicable. // Guard on the prototype, if applicable.
MaybeJump protoGuard; MaybeJump protoGuard;
@@ -2455,7 +2452,7 @@ GetElementIC::attachGetProp(VMFrame &f, JSContext *cx, JSObject *obj, const Valu
#endif #endif
// Update the inline guards, if needed. // Update the inline guards, if needed.
if (shouldPatchInlineTypeGuard() || shouldPatchUnconditionalClaspGuard()) { if (shouldPatchInlineTypeGuard() || shouldPatchUnconditionalShapeGuard()) {
Repatcher repatcher(cx->fp()->jit()); Repatcher repatcher(cx->fp()->jit());
if (shouldPatchInlineTypeGuard()) { if (shouldPatchInlineTypeGuard()) {
@@ -2468,15 +2465,15 @@ GetElementIC::attachGetProp(VMFrame &f, JSContext *cx, JSObject *obj, const Valu
inlineTypeGuardPatched = true; inlineTypeGuardPatched = true;
} }
if (shouldPatchUnconditionalClaspGuard()) { if (shouldPatchUnconditionalShapeGuard()) {
// The clasp guard is unconditional, meaning there is no type // The shape guard is unconditional, meaning there is no type
// check. This is the first stub, so it has to be patched. Note // 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. // because it follows an integer-id guard.
JS_ASSERT(!hasInlineTypeGuard()); JS_ASSERT(!hasInlineTypeGuard());
repatcher.relink(fastPathStart.jumpAtOffset(inlineClaspGuard), cs); repatcher.relink(fastPathStart.jumpAtOffset(inlineShapeGuard), cs);
inlineClaspGuardPatched = true; inlineShapeGuardPatched = true;
} }
} }
@@ -2536,7 +2533,7 @@ GetElementIC::attachArguments(JSContext *cx, JSObject *obj, const Value &v, jsid
Assembler masm; Assembler masm;
Jump claspGuard = masm.testObjClass(Assembler::NotEqual, objReg, obj->getClass()); Jump shapeGuard = masm.guardShape(objReg, obj);
masm.move(objReg, typeReg); masm.move(objReg, typeReg);
masm.load32(Address(objReg, JSObject::getFixedSlotOffset(ArgumentsObject::INITIAL_LENGTH_SLOT)), 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())) if (!buffer.verifyRange(cx->fp()->jit()))
return disable(cx, "code memory is out of range"); return disable(cx, "code memory is out of range");
buffer.link(claspGuard, slowPathStart); buffer.link(shapeGuard, slowPathStart);
buffer.link(overridden, slowPathStart); buffer.link(overridden, slowPathStart);
buffer.link(outOfBounds, slowPathStart); buffer.link(outOfBounds, slowPathStart);
buffer.link(holeCheck, 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()); JaegerSpew(JSpew_PICs, "generated getelem arguments stub at %p\n", cs.executableAddress());
Repatcher repatcher(cx->fp()->jit()); Repatcher repatcher(cx->fp()->jit());
repatcher.relink(fastPathStart.jumpAtOffset(inlineClaspGuard), cs); repatcher.relink(fastPathStart.jumpAtOffset(inlineShapeGuard), cs);
JS_ASSERT(!shouldPatchUnconditionalClaspGuard()); JS_ASSERT(!shouldPatchUnconditionalShapeGuard());
JS_ASSERT(!inlineClaspGuardPatched); JS_ASSERT(!inlineShapeGuardPatched);
inlineClaspGuardPatched = true; inlineShapeGuardPatched = true;
stubsGenerated++; stubsGenerated++;
if (stubsGenerated == MAX_GETELEM_IC_STUBS) if (stubsGenerated == MAX_GETELEM_IC_STUBS)
@@ -2683,14 +2680,14 @@ GetElementIC::attachTypedArray(JSContext *cx, JSObject *obj, const Value &v, jsi
if (op == JSOP_CALLELEM) if (op == JSOP_CALLELEM)
return disable(cx, "typed array with call"); 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. // known to be int32, either via type inference or the inline type check.
JS_ASSERT(hasInlineTypeGuard() || idRemat.knownType() == JSVAL_TYPE_INT32); JS_ASSERT(hasInlineTypeGuard() || idRemat.knownType() == JSVAL_TYPE_INT32);
Assembler masm; Assembler masm;
// Guard on this typed array's clasp. // Guard on this typed array's shape/class.
Jump claspGuard = masm.testObjClass(Assembler::NotEqual, objReg, obj->getClass()); Jump shapeGuard = masm.guardShape(objReg, obj);
// Bounds check. // Bounds check.
Jump outOfBounds; Jump outOfBounds;
@@ -2724,21 +2721,21 @@ GetElementIC::attachTypedArray(JSContext *cx, JSObject *obj, const Value &v, jsi
if (!buffer.verifyRange(cx->fp()->jit())) if (!buffer.verifyRange(cx->fp()->jit()))
return disable(cx, "code memory is out of range"); return disable(cx, "code memory is out of range");
buffer.link(claspGuard, slowPathStart); buffer.link(shapeGuard, slowPathStart);
buffer.link(outOfBounds, slowPathStart); buffer.link(outOfBounds, slowPathStart);
buffer.link(done, fastPathRejoin); buffer.link(done, fastPathRejoin);
CodeLocationLabel cs = buffer.finalizeCodeAddendum(); CodeLocationLabel cs = buffer.finalizeCodeAddendum();
JaegerSpew(JSpew_PICs, "generated getelem typed array stub at %p\n", cs.executableAddress()); 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. // Also, we only support one typed array.
JS_ASSERT(!shouldPatchUnconditionalClaspGuard()); JS_ASSERT(!shouldPatchUnconditionalShapeGuard());
JS_ASSERT(!inlineClaspGuardPatched); JS_ASSERT(!inlineShapeGuardPatched);
Repatcher repatcher(cx->fp()->jit()); Repatcher repatcher(cx->fp()->jit());
repatcher.relink(fastPathStart.jumpAtOffset(inlineClaspGuard), cs); repatcher.relink(fastPathStart.jumpAtOffset(inlineShapeGuard), cs);
inlineClaspGuardPatched = true; inlineShapeGuardPatched = true;
stubsGenerated++; stubsGenerated++;
@@ -2914,8 +2911,8 @@ void
SetElementIC::purge(Repatcher &repatcher) SetElementIC::purge(Repatcher &repatcher)
{ {
// Repatch the inline jumps. // Repatch the inline jumps.
if (inlineClaspGuardPatched) if (inlineShapeGuardPatched)
repatcher.relink(fastPathStart.jumpAtOffset(inlineClaspGuard), slowPathStart); repatcher.relink(fastPathStart.jumpAtOffset(inlineShapeGuard), slowPathStart);
if (inlineHoleGuardPatched) if (inlineHoleGuardPatched)
repatcher.relink(fastPathStart.jumpAtOffset(inlineHoleGuard), slowPathStart); repatcher.relink(fastPathStart.jumpAtOffset(inlineHoleGuard), slowPathStart);
@@ -3028,13 +3025,13 @@ SetElementIC::attachHoleStub(JSContext *cx, JSObject *obj, int32 keyval)
LookupStatus LookupStatus
SetElementIC::attachTypedArray(JSContext *cx, JSObject *obj, int32 key) SetElementIC::attachTypedArray(JSContext *cx, JSObject *obj, int32 key)
{ {
// Right now, only one clasp guard extension is supported. // Right now, only one shape guard extension is supported.
JS_ASSERT(!inlineClaspGuardPatched); JS_ASSERT(!inlineShapeGuardPatched);
Assembler masm; Assembler masm;
// Guard on this typed array's clasp. // Guard on this typed array's shape.
Jump claspGuard = masm.testObjClass(Assembler::NotEqual, objReg, obj->getClass()); Jump shapeGuard = masm.guardShape(objReg, obj);
// Bounds check. // Bounds check.
Jump outOfBounds; Jump outOfBounds;
@@ -3089,7 +3086,7 @@ SetElementIC::attachTypedArray(JSContext *cx, JSObject *obj, int32 key)
return disable(cx, "code memory is out of range"); return disable(cx, "code memory is out of range");
// Note that the out-of-bounds path simply does nothing. // Note that the out-of-bounds path simply does nothing.
buffer.link(claspGuard, slowPathStart); buffer.link(shapeGuard, slowPathStart);
buffer.link(outOfBounds, fastPathRejoin); buffer.link(outOfBounds, fastPathRejoin);
buffer.link(done, fastPathRejoin); buffer.link(done, fastPathRejoin);
masm.finalize(buffer); 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()); JaegerSpew(JSpew_PICs, "generated setelem typed array stub at %p\n", cs.executableAddress());
Repatcher repatcher(cx->fp()->jit()); Repatcher repatcher(cx->fp()->jit());
repatcher.relink(fastPathStart.jumpAtOffset(inlineClaspGuard), cs); repatcher.relink(fastPathStart.jumpAtOffset(inlineShapeGuard), cs);
inlineClaspGuardPatched = true; inlineShapeGuardPatched = true;
stubsGenerated++; stubsGenerated++;

View File

@@ -236,22 +236,22 @@ struct GetElementIC : public BasePolyIC {
// This is only set if hasInlineTypeCheck() is true. // This is only set if hasInlineTypeCheck() is true.
unsigned inlineTypeGuard : 8; 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 // set; if |id| is known to not be int32, then it's an unconditional
// jump to the slow path. // jump to the slow path.
unsigned inlineClaspGuard : 8; unsigned inlineShapeGuard : 8;
// This is usable if hasInlineTypeGuard() returns true, which implies // This is usable if hasInlineTypeGuard() returns true, which implies
// that a dense array fast path exists. The inline type guard serves as // that a dense array fast path exists. The inline type guard serves as
// the head of the chain of all string-based element stubs. // the head of the chain of all string-based element stubs.
bool inlineTypeGuardPatched : 1; 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 // has been patched. If hasInlineTypeGuard() is true, it guards against
// a dense array, and guarantees the inline type guard has passed. // 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. // an unconditional jump.
bool inlineClaspGuardPatched : 1; bool inlineShapeGuardPatched : 1;
//////////////////////////////////////////// ////////////////////////////////////////////
// State for string-based property stubs. // // State for string-based property stubs. //
@@ -285,18 +285,18 @@ struct GetElementIC : public BasePolyIC {
bool shouldPatchInlineTypeGuard() { bool shouldPatchInlineTypeGuard() {
return hasInlineTypeGuard() && !inlineTypeGuardPatched; return hasInlineTypeGuard() && !inlineTypeGuardPatched;
} }
bool shouldPatchUnconditionalClaspGuard() { bool shouldPatchUnconditionalShapeGuard() {
// The clasp guard is only unconditional if the type is known to not // The shape guard is only unconditional if the type is known to not
// be an int32. // be an int32.
if (idRemat.isTypeKnown() && idRemat.knownType() != JSVAL_TYPE_INT32) if (idRemat.isTypeKnown() && idRemat.knownType() != JSVAL_TYPE_INT32)
return !inlineClaspGuardPatched; return !inlineShapeGuardPatched;
return false; return false;
} }
void reset() { void reset() {
BasePolyIC::reset(); BasePolyIC::reset();
inlineTypeGuardPatched = false; inlineTypeGuardPatched = false;
inlineClaspGuardPatched = false; inlineShapeGuardPatched = false;
typeRegHasBaseShape = false; typeRegHasBaseShape = false;
hasLastStringStub = false; hasLastStringStub = false;
} }
@@ -329,11 +329,11 @@ struct SetElementIC : public BaseIC {
// Information on how to rematerialize |objReg|. // Information on how to rematerialize |objReg|.
int32 objRemat : MIN_STATE_REMAT_BITS; int32 objRemat : MIN_STATE_REMAT_BITS;
// Offset from the start of the fast path to the inline clasp guard. // Offset from the start of the fast path to the inline shape guard.
unsigned inlineClaspGuard : 6; unsigned inlineShapeGuard : 6;
// True if the clasp guard has been patched; false otherwise. // True if the shape guard has been patched; false otherwise.
bool inlineClaspGuardPatched : 1; bool inlineShapeGuardPatched : 1;
// Offset from the start of the fast path to the inline hole guard. // Offset from the start of the fast path to the inline hole guard.
unsigned inlineHoleGuard : 8; unsigned inlineHoleGuard : 8;
@@ -367,7 +367,7 @@ struct SetElementIC : public BaseIC {
if (execPool != NULL) if (execPool != NULL)
execPool->release(); execPool->release();
execPool = NULL; execPool = NULL;
inlineClaspGuardPatched = false; inlineShapeGuardPatched = false;
inlineHoleGuardPatched = false; inlineHoleGuardPatched = false;
} }
void purge(Repatcher &repatcher); void purge(Repatcher &repatcher);

View File

@@ -410,7 +410,8 @@ void ValidateWriter::checkAccSet(LOpcode op, LIns *base, int32_t disp, AccSet ac
couldBeObjectOrString(base)) couldBeObjectOrString(base))
case ACCSET_OBJ_CLASP: case ACCSET_OBJ_CLASP:
ok = OK_OBJ_FIELD(LIR_ldp, clasp); ok = false;
//ok = OK_OBJ_FIELD(LIR_ldp, clasp);
break; break;
case ACCSET_OBJ_FLAGS: case ACCSET_OBJ_FLAGS:

View File

@@ -480,7 +480,8 @@ class Writer
} }
nj::LIns *ldpObjClasp(nj::LIns *obj, nj::LoadQual loadQual) const { 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), loadQual),
"clasp"); "clasp");
} }