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_DENSE_ARRAY);
markDenseArrayNotPacked(cx);
backfillDenseArrayHoles(cx);
uint32 arrayCapacity = getDenseArrayCapacity();
uint32 arrayInitialized = getDenseArrayInitializedLength();
/*
* Adjust the slots to account for the different layout between dense
* arrays and other objects. The slots must be dynamic, and the fixed slots
* are now available for newly added properties.
*/
if (denseArrayHasInlineSlots()) {
if (!allocSlots(cx, numSlots()))
return false;
JS_ASSERT(!denseArrayHasInlineSlots());
}
/*
* Save old map now, before calling InitScopeForObject. We'll have to undo
@@ -1309,25 +1324,7 @@ JSObject::makeDenseArraySlow(JSContext *cx)
if (!InitScopeForObject(cx, this, &SlowArrayClass, getProto()->getNewType(cx), kind))
return false;
backfillDenseArrayHoles(cx);
uint32 arrayCapacity = getDenseArrayCapacity();
uint32 arrayInitialized = getDenseArrayInitializedLength();
/*
* Adjust the slots to account for the different layout between dense
* arrays and other objects. The slots must be dynamic, and the fixed slots
* are now available for newly added properties.
*/
if (denseArrayHasInlineSlots()) {
if (!allocSlots(cx, numSlots())) {
setMap(oldMap);
return false;
}
JS_ASSERT(!denseArrayHasInlineSlots());
}
capacity = numFixedSlots() + arrayCapacity;
clasp = &SlowArrayClass;
/*
* Root all values in the array during conversion, as SlowArrayClass only
@@ -1347,7 +1344,6 @@ JSObject::makeDenseArraySlow(JSContext *cx)
setMap(oldMap);
capacity = arrayCapacity;
initializedLength = arrayInitialized;
clasp = &ArrayClass;
return false;
}
@@ -1370,7 +1366,6 @@ JSObject::makeDenseArraySlow(JSContext *cx)
setMap(oldMap);
capacity = arrayCapacity;
initializedLength = arrayInitialized;
clasp = &ArrayClass;
return false;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -764,6 +764,9 @@ struct Shape : public js::gc::Cell
void finalize(JSContext *cx);
void removeChild(js::Shape *child);
void removeChildSlowly(js::Shape *child);
/* For JIT usage */
static inline size_t offsetOfBase() { return offsetof(Shape, base_); }
};
struct EmptyShape : public js::Shape
@@ -792,8 +795,7 @@ struct EmptyShape : public js::Shape
return shape;
}
static inline EmptyShape *getEmptyArgumentsShape(JSContext *cx);
static inline EmptyShape *getEmptyArgumentsShape(JSContext *cx, bool strict);
static inline EmptyShape *getEmptyBlockShape(JSContext *cx);
static inline EmptyShape *getEmptyCallShape(JSContext *cx);
static inline EmptyShape *getEmptyDeclEnvShape(JSContext *cx);

View File

@@ -324,9 +324,11 @@ EmptyShape::EmptyShape(BaseShape *base)
}
/* static */ inline EmptyShape *
EmptyShape::getEmptyArgumentsShape(JSContext *cx)
EmptyShape::getEmptyArgumentsShape(JSContext *cx, bool strict)
{
return ensure(cx, &NormalArgumentsObjectClass, &cx->compartment->emptyArgumentsShape);
if (strict)
return ensure(cx, &StrictArgumentsObjectClass, &cx->compartment->emptyStrictArgumentsShape);
return ensure(cx, &NormalArgumentsObjectClass, &cx->compartment->emptyNormalArgumentsShape);
}
/* static */ inline EmptyShape *

View File

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

View File

@@ -194,11 +194,6 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::SparcRegist
ImmPtr(obj->lastProperty()));
}
Jump testFunction(Condition cond, RegisterID fun) {
return branchPtr(cond, Address(fun, JSObject::offsetOfClassPointer()),
ImmPtr(&FunctionClass));
}
/*
* Finds and returns the address of a known object and slot.
*/
@@ -818,16 +813,24 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::SparcRegist
addPtr(JSFrameReg, reg);
}
void loadObjClass(RegisterID objReg, RegisterID destReg) {
loadPtr(Address(objReg, JSObject::offsetOfClassPointer()), destReg);
void loadObjClass(RegisterID obj, RegisterID dest) {
loadPtr(Address(obj, offsetof(JSObject, lastProp)), dest);
loadPtr(Address(dest, Shape::offsetOfBase()), dest);
loadPtr(Address(dest, offsetof(BaseShape, clasp)), dest);
}
Jump testClass(Condition cond, RegisterID claspReg, js::Class *clasp) {
return branchPtr(cond, claspReg, ImmPtr(clasp));
}
Jump testObjClass(Condition cond, RegisterID objReg, js::Class *clasp) {
return branchPtr(cond, Address(objReg, JSObject::offsetOfClassPointer()), ImmPtr(clasp));
Jump testObjClass(Condition cond, RegisterID obj, RegisterID temp, js::Class *clasp) {
loadPtr(Address(obj, offsetof(JSObject, lastProp)), temp);
loadPtr(Address(temp, Shape::offsetOfBase()), temp);
return branchPtr(cond, Address(temp, offsetof(BaseShape, clasp)), ImmPtr(clasp));
}
Jump testFunction(Condition cond, RegisterID fun, RegisterID temp) {
return testObjClass(cond, fun, temp, &js::FunctionClass);
}
void branchValue(Condition cond, RegisterID reg, int32 value, RegisterID result)
@@ -1294,7 +1297,6 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::SparcRegist
}
storePtr(ImmPtr(templateObject->lastProp), Address(result, offsetof(JSObject, lastProp)));
storePtr(ImmPtr(templateObject->getClass()), Address(result, JSObject::offsetOfClassPointer()));
store32(Imm32(templateObject->flags), Address(result, offsetof(JSObject, flags)));
storePtr(ImmPtr(templateObject->newType), Address(result, offsetof(JSObject, newType)));
storePtr(ImmPtr(templateObject->parent), Address(result, offsetof(JSObject, parent)));

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -743,7 +743,7 @@ class CallCompiler : public BaseCompiler
RegisterID t0 = tempRegs.takeAnyReg().reg();
/* Guard that it's actually a function object. */
Jump claspGuard = masm.testObjClass(Assembler::NotEqual, ic.funObjReg, &FunctionClass);
Jump claspGuard = masm.testObjClass(Assembler::NotEqual, ic.funObjReg, t0, &FunctionClass);
/* Guard that it's the same function. */
JSFunction *fun = obj->getFunctionPrivate();

View File

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

View File

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

View File

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

View File

@@ -480,7 +480,8 @@ class Writer
}
nj::LIns *ldpObjClasp(nj::LIns *obj, nj::LoadQual loadQual) const {
return name(lir->insLoad(nj::LIR_ldp, obj, JSObject::offsetOfClassPointer(), ACCSET_OBJ_CLASP,
JS_NOT_REACHED("FIXME");
return name(lir->insLoad(nj::LIR_ldp, obj, 0, ACCSET_OBJ_CLASP,
loadQual),
"clasp");
}