Bug 725888 - Remove some js_GetClassPrototype calls, using faster methods on GlobalObject instead. Also introduce JS_GetObjectPrototype to retrieve Object.prototype so that a friend API can be made un-friendly. r=dmandelin

--HG--
extra : rebase_source : d68d7f1fdcc1bc9a1a027c08ea62bebd8e9d0178
This commit is contained in:
Jeff Walden 2012-02-07 11:45:18 -08:00
parent 4b2e0194ff
commit 3252341ae4
15 changed files with 81 additions and 55 deletions

View File

@ -2172,6 +2172,14 @@ JS_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, JSObject **objp)
return js_GetClassObject(cx, obj, key, objp);
}
JS_PUBLIC_API(JSObject *)
JS_GetObjectPrototype(JSContext *cx, JSObject *forObj)
{
CHECK_REQUEST(cx);
assertSameCompartment(cx, forObj);
return forObj->global().getOrCreateObjectPrototype(cx);
}
JS_PUBLIC_API(JSObject *)
JS_GetGlobalForObject(JSContext *cx, JSObject *obj)
{

View File

@ -2728,6 +2728,13 @@ extern JS_PUBLIC_API(JSBool)
JS_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key,
JSObject **objp);
/*
* Returns the original value of |Object.prototype| from the global object in
* which |forObj| was created.
*/
extern JS_PUBLIC_API(JSObject *)
JS_GetObjectPrototype(JSContext *cx, JSObject *forObj);
extern JS_PUBLIC_API(JSObject *)
JS_GetGlobalForObject(JSContext *cx, JSObject *obj);

View File

@ -971,14 +971,6 @@ JS_STATIC_ASSERT(JSProto_Error + JSEXN_SYNTAXERR == JSProto_SyntaxError);
JS_STATIC_ASSERT(JSProto_Error + JSEXN_TYPEERR == JSProto_TypeError);
JS_STATIC_ASSERT(JSProto_Error + JSEXN_URIERR == JSProto_URIError);
static JS_INLINE JSProtoKey
GetExceptionProtoKey(intN exn)
{
JS_ASSERT(JSEXN_ERR <= exn);
JS_ASSERT(exn < JSEXN_LIMIT);
return JSProtoKey(JSProto_Error + exn);
}
static JSObject *
InitErrorClass(JSContext *cx, GlobalObject *global, intN type, JSObject &proto)
{
@ -1031,8 +1023,8 @@ js_InitExceptionClasses(JSContext *cx, JSObject *obj)
GlobalObject *global = &obj->asGlobal();
JSObject *objectProto;
if (!js_GetClassPrototype(cx, global, JSProto_Object, &objectProto))
JSObject *objectProto = global->getOrCreateObjectPrototype(cx);
if (!objectProto)
return NULL;
/* Initialize the base Error class first. */
@ -1331,8 +1323,8 @@ js_CopyErrorObject(JSContext *cx, JSObject *errobj, JSObject *scope)
copy->exnType = priv->exnType;
// Create the Error object.
JSObject *proto;
if (!js_GetClassPrototype(cx, &scope->global(), GetExceptionProtoKey(copy->exnType), &proto))
JSObject *proto = scope->global().getOrCreateCustomErrorPrototype(cx, copy->exnType);
if (!proto)
return NULL;
JSObject *copyobj = NewObjectWithGivenProto(cx, &ErrorClass, proto, NULL);
SetExnPrivate(cx, copyobj, copy);

View File

@ -101,4 +101,12 @@ js_GetLocalizedErrorMessage(JSContext* cx, void *userRef, const char *locale,
extern JSObject *
js_CopyErrorObject(JSContext *cx, JSObject *errobj, JSObject *scope);
static JS_INLINE JSProtoKey
GetExceptionProtoKey(intN exn)
{
JS_ASSERT(JSEXN_ERR <= exn);
JS_ASSERT(exn < JSEXN_LIMIT);
return JSProtoKey(JSProto_Error + exn);
}
#endif /* jsexn_h___ */

View File

@ -755,14 +755,6 @@ class ObjectPtr
} /* namespace js */
/*
* If protoKey is not JSProto_Null, then clasp is ignored. If protoKey is
* JSProto_Null, clasp must non-null.
*/
extern JS_FRIEND_API(JSBool)
js_GetClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey,
JSObject **protop, js::Class *clasp = NULL);
#endif
/* Implemented in jsdate.cpp. */

View File

@ -1244,8 +1244,8 @@ ResolveInterpretedFunctionPrototype(JSContext *cx, JSObject *obj)
* Make the prototype object an instance of Object with the same parent
* as the function object itself.
*/
JSObject *objProto;
if (!js_GetClassPrototype(cx, obj->getParent(), JSProto_Object, &objProto))
JSObject *objProto = obj->global().getOrCreateObjectPrototype(cx);
if (!objProto)
return NULL;
JSObject *proto = NewObjectWithGivenProto(cx, &ObjectClass, objProto, NULL);
if (!proto || !proto->setSingletonType(cx))

View File

@ -2094,11 +2094,11 @@ types::ArrayPrototypeHasIndexedProperty(JSContext *cx, JSScript *script)
if (!cx->typeInferenceEnabled() || !script->hasGlobal())
return true;
JSObject *proto;
if (!js_GetClassPrototype(cx, NULL, JSProto_Array, &proto, NULL))
JSObject *proto = script->global()->getOrCreateArrayPrototype(cx);
if (!proto)
return true;
while (proto) {
do {
TypeObject *type = proto->getType(cx);
if (type->unknownProperties())
return true;
@ -2106,7 +2106,7 @@ types::ArrayPrototypeHasIndexedProperty(JSContext *cx, JSScript *script)
if (!indexTypes || indexTypes->isOwnProperty(cx, type, true) || indexTypes->knownNonEmpty(cx))
return true;
proto = proto->getProto();
}
} while (proto);
return false;
}

View File

@ -2612,7 +2612,7 @@ BEGIN_CASE(JSOP_CALLELEM)
{
/* Find the object on which to look for |this|'s properties. */
Value thisv = regs.sp[-2];
JSObject *thisObj = ValuePropertyBearer(cx, thisv, -2);
JSObject *thisObj = ValuePropertyBearer(cx, regs.fp(), thisv, -2);
if (!thisObj)
goto error;

View File

@ -153,28 +153,23 @@ ComputeThis(JSContext *cx, StackFrame *fp)
* problem to the value at |spindex| on the stack.
*/
JS_ALWAYS_INLINE JSObject *
ValuePropertyBearer(JSContext *cx, const Value &v, int spindex)
ValuePropertyBearer(JSContext *cx, StackFrame *fp, const Value &v, int spindex)
{
if (v.isObject())
return &v.toObject();
JSProtoKey protoKey;
if (v.isString()) {
protoKey = JSProto_String;
} else if (v.isNumber()) {
protoKey = JSProto_Number;
} else if (v.isBoolean()) {
protoKey = JSProto_Boolean;
} else {
JS_ASSERT(v.isNull() || v.isUndefined());
js_ReportIsNullOrUndefined(cx, spindex, v, NULL);
return NULL;
}
GlobalObject &global = fp->scopeChain().global();
JSObject *pobj;
if (!js_GetClassPrototype(cx, NULL, protoKey, &pobj))
return NULL;
return pobj;
if (v.isString())
return global.getOrCreateStringPrototype(cx);
if (v.isNumber())
return global.getOrCreateNumberPrototype(cx);
if (v.isBoolean())
return global.getOrCreateBooleanPrototype(cx);
JS_ASSERT(v.isNull() || v.isUndefined());
js_ReportIsNullOrUndefined(cx, spindex, v, NULL);
return NULL;
}
inline bool

View File

@ -2000,6 +2000,17 @@ js_InferFlags(JSContext *cx, uintN defaultFlags);
JSBool
js_Object(JSContext *cx, uintN argc, js::Value *vp);
/*
* If protoKey is not JSProto_Null, then clasp is ignored. If protoKey is
* JSProto_Null, clasp must non-null.
*
* If protoKey is constant and scope is non-null, use GlobalObject's prototype
* methods instead.
*/
extern JS_FRIEND_API(JSBool)
js_GetClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey,
JSObject **protop, js::Class *clasp = NULL);
namespace js {
extern bool

View File

@ -4507,8 +4507,8 @@ mjit::Compiler::callArrayBuiltin(uint32_t argc, bool callingNew)
if (!js_GetClassObject(cx, globalObj, JSProto_Array, &arrayObj))
return Compile_Error;
JSObject *arrayProto;
if (!js_GetClassPrototype(cx, globalObj, JSProto_Array, &arrayProto))
JSObject *arrayProto = globalObj->global().getOrCreateArrayPrototype(cx);
if (!arrayProto)
return Compile_Error;
if (argc > 1)

View File

@ -1518,8 +1518,8 @@ GetDenseArrayShape(JSContext *cx, JSObject *globalObj)
{
JS_ASSERT(globalObj);
JSObject *proto;
if (!js_GetClassPrototype(cx, globalObj, JSProto_Array, &proto, NULL))
JSObject *proto = globalObj->global().getOrCreateArrayPrototype(cx);
if (!proto)
return NULL;
return EmptyShape::getInitialShape(cx, &ArrayClass, proto,

View File

@ -2633,8 +2633,8 @@ DebuggerFrame_getArguments(JSContext *cx, uintN argc, Value *vp)
/* Create an arguments object. */
RootedVar<GlobalObject*> global(cx);
global = &args.callee().global();
JSObject *proto;
if (!js_GetClassPrototype(cx, global, JSProto_Array, &proto))
JSObject *proto = global->getOrCreateArrayPrototype(cx);
if (!proto)
return false;
argsobj = NewObjectWithGivenProto(cx, &DebuggerArguments_class, proto, global);
if (!argsobj)
@ -3791,7 +3791,8 @@ JS_DefineDebuggerObject(JSContext *cx, JSObject *obj)
scriptProto(cx),
objectProto(cx);
if (!js_GetClassPrototype(cx, obj, JSProto_Object, objProto.address()))
objProto = obj->asGlobal().getOrCreateObjectPrototype(cx);
if (!objProto)
return false;

View File

@ -45,6 +45,7 @@
#include "jsarray.h"
#include "jsbool.h"
#include "jsexn.h"
#include "jsfun.h"
#include "jsiter.h"
#include "jsnum.h"
@ -186,6 +187,9 @@ class GlobalObject : public JSObject {
bool arrayBufferClassInitialized() const {
return classIsInitialized(JSProto_ArrayBuffer);
}
bool errorClassesInitialized() const {
return classIsInitialized(JSProto_Error);
}
public:
static GlobalObject *create(JSContext *cx, Class *clasp);
@ -294,6 +298,17 @@ class GlobalObject : public JSObject {
return &self->getPrototype(JSProto_ArrayBuffer).toObject();
}
JSObject *getOrCreateCustomErrorPrototype(JSContext *cx, intN exnType) {
GlobalObject *self = this;
JSProtoKey key = GetExceptionProtoKey(exnType);
if (!errorClassesInitialized()) {
Root<GlobalObject*> root(cx, &self);
if (!js_InitExceptionClasses(cx, this))
return NULL;
}
return &self->getPrototype(key).toObject();
}
JSObject *getOrCreateGeneratorPrototype(JSContext *cx) {
GlobalObject *self = this;
Value v = getSlotRef(GENERATOR_PROTO);

View File

@ -1312,10 +1312,7 @@ NoBase::getPrototype(JSContext *cx, XPCWrappedNativeScope *scope)
// We need to pass the object prototype to JS_NewObject. If we pass NULL then the JS engine
// will look up a prototype on the global by using the class' name and we'll recurse into
// getPrototype.
JSObject* proto;
if (!js_GetClassPrototype(cx, scope->GetGlobalJSObject(), JSProto_Object, &proto))
return NULL;
return proto;
return JS_GetObjectPrototype(cx, scope->GetGlobalJSObject());
}