зеркало из https://github.com/mozilla/gecko-dev.git
Bug 505523 - Property cache can skip JSClass::resolve or JSClass::addProperty hooks. r=graydon, r=brendan.
--HG-- extra : rebase_source : a77b0e81203010aabe07b92b639762dce83200c0
This commit is contained in:
Родитель
e5ccb0b9ff
Коммит
4d092db314
|
@ -194,6 +194,7 @@ INSTALLED_HEADERS = \
|
|||
jsmath.h \
|
||||
jsnum.h \
|
||||
jsobj.h \
|
||||
jsobjinlines.h \
|
||||
json.h \
|
||||
jsopcode.tbl \
|
||||
jsopcode.h \
|
||||
|
|
|
@ -25,7 +25,6 @@ BEGIN_TEST(testPropCache_bug505798)
|
|||
EXEC("var arr = [x, y];\n"
|
||||
"for (var i = 0; i < arr.length; i++)\n"
|
||||
" arr[i].p = 1;\n");
|
||||
knownFail = true;
|
||||
CHECK(g_counter == 1);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1297,9 +1297,9 @@ js_MakeArraySlow(JSContext *cx, JSObject *obj)
|
|||
/* obj is Array.prototype. */
|
||||
emptyShape = js_GenerateShape(cx, false);
|
||||
} else {
|
||||
/* arrayProto is Array.prototype. */
|
||||
JS_ASSERT(arrayProto->getClass() == &js_SlowArrayClass);
|
||||
if (!OBJ_SCOPE(arrayProto)->getEmptyScopeShape(cx, &js_SlowArrayClass, &emptyShape))
|
||||
return JS_FALSE;
|
||||
emptyShape = OBJ_SCOPE(arrayProto)->emptyScope->shape;
|
||||
}
|
||||
JSScope *scope = JSScope::create(cx, &js_SlowArrayObjectOps, &js_SlowArrayClass, obj,
|
||||
emptyShape);
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
#include "jsvector.h"
|
||||
|
||||
#include "jsatominlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
#include "jsscopeinlines.h"
|
||||
|
||||
using namespace avmplus;
|
||||
|
@ -414,15 +415,8 @@ js_NewNullClosure(JSContext* cx, JSObject* funobj, JSObject* proto, JSObject* pa
|
|||
if (!closure)
|
||||
return NULL;
|
||||
|
||||
JSScope *scope = OBJ_SCOPE(proto)->getEmptyScope(cx, &js_FunctionClass);
|
||||
if (!scope) {
|
||||
JS_ASSERT(!closure->map);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
closure->map = scope;
|
||||
closure->init(&js_FunctionClass, proto, parent,
|
||||
reinterpret_cast<jsval>(fun));
|
||||
closure->initSharingEmptyScope(&js_FunctionClass, proto, parent,
|
||||
reinterpret_cast<jsval>(fun));
|
||||
return closure;
|
||||
}
|
||||
JS_DEFINE_CALLINFO_4(extern, OBJECT, js_NewNullClosure, CONTEXT, OBJECT, OBJECT, OBJECT, 0, 0)
|
||||
|
|
|
@ -295,8 +295,7 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj,
|
|||
return JS_NO_PROP_CACHE_FILL;
|
||||
JSScope *protoscope = OBJ_SCOPE(proto);
|
||||
if (!protoscope->emptyScope ||
|
||||
!js_ObjectIsSimilarToProto(cx, obj, obj->map->ops, OBJ_GET_CLASS(cx, obj),
|
||||
proto)) {
|
||||
protoscope->emptyScope->clasp != obj->getClass()) {
|
||||
return JS_NO_PROP_CACHE_FILL;
|
||||
}
|
||||
kshape = protoscope->emptyScope->shape;
|
||||
|
|
|
@ -97,6 +97,7 @@
|
|||
#endif
|
||||
|
||||
#include "jsatominlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
#include "jsscriptinlines.h"
|
||||
|
||||
#include "jsautooplen.h"
|
||||
|
@ -2194,8 +2195,9 @@ InitScopeForObject(JSContext* cx, JSObject* obj, JSObject* proto, JSObjectOps* o
|
|||
/* Share proto's emptyScope only if obj is similar to proto. */
|
||||
JSClass *clasp = OBJ_GET_CLASS(cx, obj);
|
||||
JSScope *scope;
|
||||
if (proto && js_ObjectIsSimilarToProto(cx, obj, ops, clasp, proto)) {
|
||||
scope = OBJ_SCOPE(proto)->getEmptyScope(cx, clasp);
|
||||
if (proto && OBJ_IS_NATIVE(proto) &&
|
||||
(scope = OBJ_SCOPE(proto))->canProvideEmptyScope(ops, clasp)) {
|
||||
scope = scope->getEmptyScope(cx, clasp);
|
||||
if (!scope)
|
||||
goto bad;
|
||||
} else {
|
||||
|
@ -2346,6 +2348,31 @@ js_Object(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||
|
||||
#ifdef JS_TRACER
|
||||
|
||||
JSObject*
|
||||
js_NewObjectWithClassProto(JSContext *cx, JSClass *clasp, JSObject *proto,
|
||||
jsval privateSlotValue)
|
||||
{
|
||||
JS_ASSERT(!clasp->getObjectOps);
|
||||
JS_ASSERT(proto->map->ops == &js_ObjectOps);
|
||||
|
||||
JSObject* obj = js_NewGCObject(cx);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
obj->initSharingEmptyScope(clasp, proto, proto->getParent(), privateSlotValue);
|
||||
return obj;
|
||||
}
|
||||
|
||||
JSObject* FASTCALL
|
||||
js_Object_tn(JSContext* cx, JSObject* proto)
|
||||
{
|
||||
JS_ASSERT(!(js_ObjectClass.flags & JSCLASS_HAS_PRIVATE));
|
||||
return js_NewObjectWithClassProto(cx, &js_ObjectClass, proto, JSVAL_VOID);
|
||||
}
|
||||
|
||||
JS_DEFINE_TRCINFO_1(js_Object,
|
||||
(2, (extern, CONSTRUCTOR_RETRY, js_Object_tn, CONTEXT, CALLEE_PROTOTYPE, 0, 0)))
|
||||
|
||||
static inline JSObject*
|
||||
NewNativeObject(JSContext* cx, JSClass* clasp, JSObject* proto,
|
||||
JSObject *parent, jsval privateSlotValue)
|
||||
|
@ -2359,17 +2386,6 @@ NewNativeObject(JSContext* cx, JSClass* clasp, JSObject* proto,
|
|||
return InitScopeForObject(cx, obj, proto, &js_ObjectOps) ? obj : NULL;
|
||||
}
|
||||
|
||||
JSObject* FASTCALL
|
||||
js_Object_tn(JSContext* cx, JSObject* proto)
|
||||
{
|
||||
JS_ASSERT(!(js_ObjectClass.flags & JSCLASS_HAS_PRIVATE));
|
||||
return NewNativeObject(cx, &js_ObjectClass, proto, proto->getParent(),
|
||||
JSVAL_VOID);
|
||||
}
|
||||
|
||||
JS_DEFINE_TRCINFO_1(js_Object,
|
||||
(2, (extern, CONSTRUCTOR_RETRY, js_Object_tn, CONTEXT, CALLEE_PROTOTYPE, 0, 0)))
|
||||
|
||||
JSObject* FASTCALL
|
||||
js_NewInstance(JSContext *cx, JSClass *clasp, JSObject *ctor)
|
||||
{
|
||||
|
@ -3118,6 +3134,21 @@ js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
|
|||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure proto's scope's emptyScope is available to be shared by
|
||||
* objects of this class. JSScope::emptyScope is a one-slot cache. If we
|
||||
* omit this, some other class could snap it up. (The risk is particularly
|
||||
* great for Object.prototype.)
|
||||
*
|
||||
* All callers of JSObject::initSharingEmptyScope depend on this.
|
||||
*/
|
||||
{
|
||||
JSScope *scope = OBJ_SCOPE(proto)->getEmptyScope(cx, clasp);
|
||||
if (!scope)
|
||||
goto bad;
|
||||
scope->drop(cx, NULL);
|
||||
}
|
||||
|
||||
/* If this is a standard class, cache its prototype. */
|
||||
if (key != JSProto_Null && !js_SetClassObject(cx, obj, key, ctor))
|
||||
goto bad;
|
||||
|
@ -3282,28 +3313,6 @@ js_GetClassId(JSContext *cx, JSClass *clasp, jsid *idp)
|
|||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
js_NewNativeObject(JSContext *cx, JSClass *clasp, JSObject *proto,
|
||||
jsval privateSlotValue)
|
||||
{
|
||||
JS_ASSERT(!clasp->getObjectOps);
|
||||
JS_ASSERT(proto->map->ops == &js_ObjectOps);
|
||||
JS_ASSERT(OBJ_GET_CLASS(cx, proto) == clasp);
|
||||
|
||||
JSObject* obj = js_NewGCObject(cx);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
JSScope *scope = OBJ_SCOPE(proto)->getEmptyScope(cx, clasp);
|
||||
if (!scope) {
|
||||
JS_ASSERT(!obj->map);
|
||||
return NULL;
|
||||
}
|
||||
obj->map = scope;
|
||||
obj->init(clasp, proto, proto->getParent(), privateSlotValue);
|
||||
return obj;
|
||||
}
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
static JSObject *
|
||||
|
|
|
@ -145,8 +145,8 @@ const uintptr_t JSSLOT_CLASS_MASK_BITS = 3;
|
|||
* records the number of available slots.
|
||||
*/
|
||||
struct JSObject {
|
||||
JSObjectMap *map; /* propery map, see jsscope.h */
|
||||
jsuword classword; /* classword, see above */
|
||||
JSObjectMap *map; /* property map, see jsscope.h */
|
||||
jsuword classword; /* JSClass ptr | bits, see above */
|
||||
jsval fslots[JS_INITIAL_NSLOTS]; /* small number of fixed slots */
|
||||
jsval *dslots; /* dynamically allocated slots */
|
||||
|
||||
|
@ -251,6 +251,13 @@ struct JSObject {
|
|||
dslots = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Like init, but also initializes map. The catch: proto must be the result
|
||||
* of a call to js_InitClass(...clasp, ...).
|
||||
*/
|
||||
inline void initSharingEmptyScope(JSClass *clasp, JSObject *proto, JSObject *parent,
|
||||
jsval privateSlotValue);
|
||||
|
||||
JSBool lookupProperty(JSContext *cx, jsid id,
|
||||
JSObject **objp, JSProperty **propp) {
|
||||
return map->ops->lookupProperty(cx, this, id, objp, propp);
|
||||
|
@ -622,14 +629,17 @@ js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
|
|||
* Allocate a new native object with the given value of the proto and private
|
||||
* slots. The parent slot is set to the value of proto's parent slot.
|
||||
*
|
||||
* clasp must be a native class. proto must be the result of a call to
|
||||
* js_InitClass(...clasp, ...).
|
||||
*
|
||||
* Note that this is the correct global object for native class instances, but
|
||||
* not for user-defined functions called as constructors. Functions used as
|
||||
* constructors must create instances parented by the parent of the function
|
||||
* object, not by the parent of its .prototype object value.
|
||||
*/
|
||||
extern JSObject*
|
||||
js_NewNativeObject(JSContext *cx, JSClass *clasp, JSObject *proto,
|
||||
jsval privateSlotValue);
|
||||
js_NewObjectWithClassProto(JSContext *cx, JSClass *clasp, JSObject *proto,
|
||||
jsval privateSlotValue);
|
||||
|
||||
/*
|
||||
* Fast access to immutable standard objects (constructors and prototypes).
|
||||
|
@ -986,36 +996,6 @@ js_ReportGetterOnlyAssignment(JSContext *cx);
|
|||
extern JS_FRIEND_API(JSBool)
|
||||
js_GetterOnlyPropertyStub(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
|
||||
|
||||
/*
|
||||
* If an object is "similar" to its prototype, it can share OBJ_SCOPE(proto)->emptyScope.
|
||||
* Similar objects have the same JSObjectOps and the same private and reserved slots.
|
||||
*
|
||||
* We assume that if prototype and object are of the same class, they always
|
||||
* have the same number of computed reserved slots (returned via
|
||||
* clasp->reserveSlots). This is true for builtin classes (except Block, and
|
||||
* for this reason among others Blocks must never be exposed to scripts).
|
||||
*
|
||||
* Otherwise, prototype and object classes must have the same (null or not)
|
||||
* reserveSlots hook.
|
||||
*
|
||||
* FIXME: This fails to distinguish between objects with different addProperty
|
||||
* hooks. See bug 505523.
|
||||
*/
|
||||
static inline bool
|
||||
js_ObjectIsSimilarToProto(JSContext *cx, JSObject *obj, const JSObjectOps *ops,
|
||||
JSClass *clasp, JSObject *proto)
|
||||
{
|
||||
JS_ASSERT(proto == OBJ_GET_PROTO(cx, obj));
|
||||
|
||||
JSClass *protoclasp;
|
||||
return (proto->map->ops == ops &&
|
||||
((protoclasp = OBJ_GET_CLASS(cx, proto)) == clasp ||
|
||||
(!((protoclasp->flags ^ clasp->flags) &
|
||||
(JSCLASS_HAS_PRIVATE |
|
||||
(JSCLASS_RESERVED_SLOTS_MASK << JSCLASS_RESERVED_SLOTS_SHIFT))) &&
|
||||
protoclasp->reserveSlots == clasp->reserveSlots)));
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
JS_FRIEND_API(void) js_DumpChars(const jschar *s, size_t n);
|
||||
JS_FRIEND_API(void) js_DumpString(JSString *str);
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=99:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef jsobjinlines_h___
|
||||
#define jsobjinlines_h___
|
||||
|
||||
#include "jsobj.h"
|
||||
#include "jsscope.h"
|
||||
|
||||
inline void
|
||||
JSObject::initSharingEmptyScope(JSClass *clasp, JSObject *proto, JSObject *parent,
|
||||
jsval privateSlotValue)
|
||||
{
|
||||
init(clasp, proto, parent, privateSlotValue);
|
||||
|
||||
JSEmptyScope *emptyScope = OBJ_SCOPE(proto)->emptyScope;
|
||||
JS_ASSERT(emptyScope->clasp == clasp);
|
||||
emptyScope->hold();
|
||||
map = emptyScope;
|
||||
}
|
||||
|
||||
#endif /* jsobjinlines_h___ */
|
|
@ -211,12 +211,12 @@ JSScope::create(JSContext *cx, const JSObjectOps *ops, JSClass *clasp,
|
|||
return scope;
|
||||
}
|
||||
|
||||
JSScope *
|
||||
JSEmptyScope *
|
||||
JSScope::createEmptyScope(JSContext *cx, JSClass *clasp)
|
||||
{
|
||||
JS_ASSERT(!emptyScope);
|
||||
|
||||
JSScope *scope = cx->create<JSScope>(ops);
|
||||
JSEmptyScope *scope = cx->create<JSEmptyScope>(ops, clasp);
|
||||
if (!scope)
|
||||
return NULL;
|
||||
|
||||
|
@ -1582,13 +1582,13 @@ JSScope::clear(JSContext *cx)
|
|||
|
||||
JSClass *clasp = object->getClass();
|
||||
JSObject *proto = object->getProto();
|
||||
uint32 newShape = 0;
|
||||
if (proto && clasp == proto->getClass()) {
|
||||
#ifdef DEBUG
|
||||
bool ok =
|
||||
#endif
|
||||
OBJ_SCOPE(proto)->getEmptyScopeShape(cx, clasp, &newShape);
|
||||
JS_ASSERT(ok);
|
||||
JSEmptyScope *emptyScope;
|
||||
uint32 newShape;
|
||||
if (proto &&
|
||||
OBJ_IS_NATIVE(proto) &&
|
||||
(emptyScope = OBJ_SCOPE(proto)->emptyScope) &&
|
||||
emptyScope->clasp == clasp) {
|
||||
newShape = emptyScope->shape;
|
||||
} else {
|
||||
newShape = js_GenerateShape(cx, false);
|
||||
}
|
||||
|
|
|
@ -200,6 +200,8 @@ JS_BEGIN_EXTERN_C
|
|||
* to find a given id, and save on the space overhead of a hash table.
|
||||
*/
|
||||
|
||||
struct JSEmptyScope;
|
||||
|
||||
struct JSScope : public JSObjectMap
|
||||
{
|
||||
#ifdef JS_THREADSAFE
|
||||
|
@ -208,7 +210,7 @@ struct JSScope : public JSObjectMap
|
|||
JSObject *object; /* object that owns this scope */
|
||||
jsrefcount nrefs; /* count of all referencing objects */
|
||||
uint32 freeslot; /* index of next free slot in object */
|
||||
JSScope *emptyScope; /* cache for getEmptyScope below */
|
||||
JSEmptyScope *emptyScope; /* cache for getEmptyScope below */
|
||||
uint8 flags; /* flags, see below */
|
||||
int8 hashShift; /* multiplicative hash shift */
|
||||
|
||||
|
@ -226,7 +228,7 @@ struct JSScope : public JSObjectMap
|
|||
void generateOwnShape(JSContext *cx);
|
||||
JSScopeProperty **searchTable(jsid id, bool adding);
|
||||
inline JSScopeProperty **search(jsid id, bool adding);
|
||||
JSScope *createEmptyScope(JSContext *cx, JSClass *clasp);
|
||||
JSEmptyScope *createEmptyScope(JSContext *cx, JSClass *clasp);
|
||||
|
||||
public:
|
||||
explicit JSScope(const JSObjectOps *ops, JSObject *obj = NULL)
|
||||
|
@ -238,6 +240,9 @@ struct JSScope : public JSObjectMap
|
|||
|
||||
static void destroy(JSContext *cx, JSScope *scope);
|
||||
|
||||
inline void hold();
|
||||
inline bool drop(JSContext *cx, JSObject *obj);
|
||||
|
||||
/*
|
||||
* Return an immutable, shareable, empty scope with the same ops as this
|
||||
* and the same freeslot as this had when empty.
|
||||
|
@ -245,30 +250,10 @@ struct JSScope : public JSObjectMap
|
|||
* If |this| is the scope of an object |proto|, the resulting scope can be
|
||||
* used as the scope of a new object whose prototype is |proto|.
|
||||
*/
|
||||
JSScope *getEmptyScope(JSContext *cx, JSClass *clasp) {
|
||||
if (emptyScope) {
|
||||
emptyScope->hold();
|
||||
return emptyScope;
|
||||
}
|
||||
return createEmptyScope(cx, clasp);
|
||||
}
|
||||
|
||||
bool getEmptyScopeShape(JSContext *cx, JSClass *clasp, uint32 *shapep) {
|
||||
if (emptyScope) {
|
||||
*shapep = emptyScope->shape;
|
||||
return true;
|
||||
}
|
||||
JSScope *e = getEmptyScope(cx, clasp);
|
||||
if (!e)
|
||||
return false;
|
||||
*shapep = e->shape;
|
||||
e->drop(cx, NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void hold();
|
||||
inline bool drop(JSContext *cx, JSObject *obj);
|
||||
inline JSEmptyScope *getEmptyScope(JSContext *cx, JSClass *clasp);
|
||||
|
||||
inline bool canProvideEmptyScope(JSObjectOps *ops, JSClass *clasp);
|
||||
|
||||
JSScopeProperty *lookup(jsid id);
|
||||
bool has(JSScopeProperty *sprop);
|
||||
|
||||
|
@ -405,6 +390,14 @@ struct JSScope : public JSObjectMap
|
|||
bool owned() { return object != NULL; }
|
||||
};
|
||||
|
||||
struct JSEmptyScope : public JSScope
|
||||
{
|
||||
JSClass * const clasp;
|
||||
|
||||
explicit JSEmptyScope(const JSObjectOps *ops, JSClass *clasp)
|
||||
: JSScope(ops), clasp(clasp) {}
|
||||
};
|
||||
|
||||
inline bool
|
||||
JS_IS_SCOPE_LOCKED(JSContext *cx, JSScope *scope)
|
||||
{
|
||||
|
@ -631,6 +624,23 @@ JSScope::search(jsid id, bool adding)
|
|||
|
||||
#undef METER
|
||||
|
||||
inline bool
|
||||
JSScope::canProvideEmptyScope(JSObjectOps *ops, JSClass *clasp)
|
||||
{
|
||||
return this->ops == ops && (!emptyScope || emptyScope->clasp == clasp);
|
||||
}
|
||||
|
||||
inline JSEmptyScope *
|
||||
JSScope::getEmptyScope(JSContext *cx, JSClass *clasp)
|
||||
{
|
||||
if (emptyScope) {
|
||||
JS_ASSERT(clasp == emptyScope->clasp);
|
||||
emptyScope->hold();
|
||||
return emptyScope;
|
||||
}
|
||||
return createEmptyScope(cx, clasp);
|
||||
}
|
||||
|
||||
inline void
|
||||
JSScope::hold()
|
||||
{
|
||||
|
|
|
@ -2912,7 +2912,7 @@ JSObject* FASTCALL
|
|||
js_String_tn(JSContext* cx, JSObject* proto, JSString* str)
|
||||
{
|
||||
JS_ASSERT(JS_ON_TRACE(cx));
|
||||
return js_NewNativeObject(cx, &js_StringClass, proto, STRING_TO_JSVAL(str));
|
||||
return js_NewObjectWithClassProto(cx, &js_StringClass, proto, STRING_TO_JSVAL(str));
|
||||
}
|
||||
JS_DEFINE_CALLINFO_3(extern, OBJECT, js_String_tn, CONTEXT, CALLEE_PROTOTYPE, STRING, 0, 0)
|
||||
|
||||
|
|
|
@ -10237,7 +10237,11 @@ TraceRecorder::record_JSOP_OBJTOP()
|
|||
RecordingStatus
|
||||
TraceRecorder::getClassPrototype(JSObject* ctor, LIns*& proto_ins)
|
||||
{
|
||||
// ctor must be a function created via js_InitClass.
|
||||
#ifdef DEBUG
|
||||
JSClass *clasp = FUN_CLASP(GET_FUNCTION_PRIVATE(cx, ctor));
|
||||
JS_ASSERT(clasp);
|
||||
|
||||
JSTraceMonitor &localtm = JS_TRACE_MONITOR(cx);
|
||||
#endif
|
||||
|
||||
|
@ -10245,11 +10249,10 @@ TraceRecorder::getClassPrototype(JSObject* ctor, LIns*& proto_ins)
|
|||
if (!ctor->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), &pval))
|
||||
RETURN_ERROR("error getting prototype from constructor");
|
||||
|
||||
/* For functions, this shold not reenter */
|
||||
// ctor.prototype is a permanent data property, so this lookup cannot have
|
||||
// deep-aborted.
|
||||
JS_ASSERT(localtm.recorder);
|
||||
|
||||
if (JSVAL_TAG(pval) != JSVAL_OBJECT)
|
||||
RETURN_STOP("got primitive prototype from constructor");
|
||||
#ifdef DEBUG
|
||||
JSBool ok, found;
|
||||
uintN attrs;
|
||||
|
@ -10258,7 +10261,14 @@ TraceRecorder::getClassPrototype(JSObject* ctor, LIns*& proto_ins)
|
|||
JS_ASSERT(found);
|
||||
JS_ASSERT((~attrs & (JSPROP_READONLY | JSPROP_PERMANENT)) == 0);
|
||||
#endif
|
||||
proto_ins = INS_CONSTOBJ(JSVAL_TO_OBJECT(pval));
|
||||
|
||||
// Since ctor was built by js_InitClass, we can assert (rather than check)
|
||||
// that pval is usable.
|
||||
JS_ASSERT(!JSVAL_IS_PRIMITIVE(pval));
|
||||
JSObject *proto = JSVAL_TO_OBJECT(pval);
|
||||
JS_ASSERT_IF(clasp != &js_ArrayClass, OBJ_SCOPE(proto)->emptyScope->clasp == clasp);
|
||||
|
||||
proto_ins = INS_CONSTOBJ(proto);
|
||||
return RECORD_CONTINUE;
|
||||
}
|
||||
|
||||
|
@ -10273,9 +10283,21 @@ TraceRecorder::getClassPrototype(JSProtoKey key, LIns*& proto_ins)
|
|||
if (!js_GetClassPrototype(cx, globalObj, INT_TO_JSID(key), &proto))
|
||||
RETURN_ERROR("error in js_GetClassPrototype");
|
||||
|
||||
/* For functions, this shold not reenter */
|
||||
// This should not have reentered.
|
||||
JS_ASSERT(localtm.recorder);
|
||||
|
||||
// If we might end up passing the proto to JSObject::initSharingEmptyScope,
|
||||
// we must check here that proto has a matching emptyScope. We skip the
|
||||
// check for Array.prototype because new arrays, being non-native, are
|
||||
// never initialized using initSharingEmptyScope.
|
||||
if (key != JSProto_Array) {
|
||||
if (!OBJ_IS_NATIVE(proto))
|
||||
RETURN_STOP("non-native class prototype");
|
||||
JSEmptyScope *emptyScope = OBJ_SCOPE(proto)->emptyScope;
|
||||
if (!emptyScope || JSCLASS_CACHED_PROTO_KEY(emptyScope->clasp) != key)
|
||||
RETURN_STOP("class prototype is not the standard one");
|
||||
}
|
||||
|
||||
proto_ins = INS_CONSTOBJ(proto);
|
||||
return RECORD_CONTINUE;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче