Remove direct class pointer from JSObject, bug 690133.
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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. */
|
||||||
|
|||||||
@@ -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___ */
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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 *
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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)));
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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++;
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user