Bug 851763 - part 1: add support for wrapping self-hosted functions instead of cloning them. r=jwalden

--HG--
extra : rebase_source : 12bbbd1bc17bedc97a9da6189dd5c1c0773e54c1
This commit is contained in:
Till Schneidereit 2013-03-30 03:06:33 +01:00
parent 023c73bf41
commit 08e5f52d0d
7 changed files with 91 additions and 28 deletions

View File

@ -70,16 +70,15 @@ var std_WeakMap_set = WeakMap.prototype.set;
/* Spec: ECMAScript Language Specification, 5.1 edition, 8.8 */
function List() {
if (List.prototype === undefined) {
var proto = std_Object_create(null);
proto.indexOf = std_Array_indexOf;
proto.join = std_Array_join;
proto.push = std_Array_push;
proto.slice = std_Array_slice;
proto.sort = std_Array_sort;
List.prototype = proto;
}
function List() {}
{
let ListProto = std_Object_create(null);
ListProto.indexOf = std_Array_indexOf;
ListProto.join = std_Array_join;
ListProto.push = std_Array_push;
ListProto.slice = std_Array_slice;
ListProto.sort = std_Array_sort;
List.prototype = ListProto;
}
MakeConstructible(List);

View File

@ -5051,21 +5051,31 @@ JS_DefineFunctions(JSContext *cx, JSObject *objArg, const JSFunctionSpec *fs)
if (cx->runtime->isSelfHostingGlobal(cx->global()))
continue;
RootedFunction fun(cx, DefineFunction(cx, obj, id, /* native = */ NULL, fs->nargs, 0,
JSFunction::ExtendedFinalizeKind, SingletonObject));
if (!fun)
return JS_FALSE;
fun->setIsSelfHostedBuiltin();
fun->setExtendedSlot(0, PrivateValue(const_cast<JSFunctionSpec*>(fs)));
RootedAtom shAtom(cx, Atomize(cx, fs->selfHostedName, strlen(fs->selfHostedName)));
if (!shAtom)
return JS_FALSE;
RootedObject holder(cx, cx->global()->intrinsicsHolder());
if (!JS_DefinePropertyById(cx,holder, AtomToId(shAtom),
ObjectValue(*fun), NULL, NULL, 0))
{
RootedPropertyName shName(cx, shAtom->asPropertyName());
RootedValue funVal(cx);
if (!cx->runtime->maybeWrappedSelfHostedFunction(cx, shName, &funVal))
return JS_FALSE;
if (!funVal.isUndefined()) {
if (!JSObject::defineProperty(cx, obj, atom->asPropertyName(), funVal,
NULL, NULL, flags & ~JSFUN_FLAGS_MASK))
{
return JS_FALSE;
}
} else {
RawFunction fun = DefineFunction(cx, obj, id, /* native = */ NULL, fs->nargs, 0,
JSFunction::ExtendedFinalizeKind, SingletonObject);
if (!fun)
return JS_FALSE;
fun->setIsSelfHostedBuiltin();
fun->setExtendedSlot(0, PrivateValue(const_cast<JSFunctionSpec*>(fs)));
funVal.setObject(*fun);
}
RootedObject holder(cx, cx->global()->intrinsicsHolder());
if (!JSObject::defineProperty(cx, holder, shName, funVal))
return JS_FALSE;
} else {
JSFunction *fun = DefineFunction(cx, obj, id, fs->call.op, fs->nargs, flags);
if (!fun)

View File

@ -776,6 +776,8 @@ struct JSRuntime : private JS::shadow::Runtime,
js::Handle<JSFunction*> targetFun);
bool cloneSelfHostedValue(JSContext *cx, js::Handle<js::PropertyName*> name,
js::MutableHandleValue vp);
bool maybeWrappedSelfHostedFunction(JSContext *cx, js::Handle<js::PropertyName*> name,
js::MutableHandleValue funVal);
//-------------------------------------------------------------------------
// Locale information

View File

@ -44,6 +44,7 @@ class JSFunction : public JSObject
HAS_DEFAULTS = 0x0800, /* function has at least one default parameter */
INTERPRETED_LAZY = 0x1000, /* function is interpreted but doesn't have a script yet */
ARROW = 0x2000, /* ES6 '(args) => body' syntax */
SH_WRAPPABLE = 0x4000, /* self-hosted function is wrappable, doesn't need to be cloned */
/* Derived Flags values for convenience: */
NATIVE_FUN = 0,
@ -100,6 +101,10 @@ class JSFunction : public JSObject
bool isSelfHostedConstructor() const { return flags & SELF_HOSTED_CTOR; }
bool hasRest() const { return flags & HAS_REST; }
bool hasDefaults() const { return flags & HAS_DEFAULTS; }
bool isWrappable() const {
JS_ASSERT_IF(flags & SH_WRAPPABLE, isSelfHostedBuiltin());
return flags & SH_WRAPPABLE;
}
// Arrow functions are a little weird.
//
@ -155,6 +160,12 @@ class JSFunction : public JSObject
flags |= SELF_HOSTED_CTOR;
}
void makeWrappable() {
JS_ASSERT(isSelfHostedBuiltin());
JS_ASSERT(!isWrappable());
flags |= SH_WRAPPABLE;
}
void setIsFunctionPrototype() {
JS_ASSERT(!isFunctionPrototype());
flags |= IS_FUN_PROTO;

View File

@ -2489,7 +2489,7 @@ BEGIN_CASE(JSOP_CALLINTRINSIC)
{
RootedValue &rval = rootValue0;
if (!GetIntrinsicOperation(cx, script, regs.pc, &rval))
if (!GetIntrinsicOperation(cx, regs.pc, &rval))
goto error;
PUSH_COPY(rval);

View File

@ -418,10 +418,9 @@ FetchNameNoGC(JSObject *pobj, Shape *shape, MutableHandleValue vp)
}
inline bool
GetIntrinsicOperation(JSContext *cx, JSScript *script, jsbytecode *pc, MutableHandleValue vp)
GetIntrinsicOperation(JSContext *cx, jsbytecode *pc, MutableHandleValue vp)
{
JSOp op = JSOp(*pc);
RootedPropertyName name(cx, GetNameFromBytecode(cx, script, pc, op));
RootedPropertyName name(cx, cx->stack.currentScript()->getName(pc));
return cx->global()->getIntrinsicValue(cx, name, vp);
}

View File

@ -142,6 +142,19 @@ intrinsic_MakeConstructible(JSContext *cx, unsigned argc, Value *vp)
JS_ASSERT(args[0].isObject());
JS_ASSERT(args[0].toObject().isFunction());
args[0].toObject().toFunction()->setIsSelfHostedConstructor();
args.rval().setUndefined();
return true;
}
static JSBool
intrinsic_MakeWrappable(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
JS_ASSERT(args.length() >= 1);
JS_ASSERT(args[0].isObject());
JS_ASSERT(args[0].toObject().isFunction());
args[0].toObject().toFunction()->makeWrappable();
args.rval().setUndefined();
return true;
}
@ -204,6 +217,7 @@ intrinsic_SetScriptHints(JSContext *cx, unsigned argc, Value *vp)
if (ToBoolean(propv))
funScript->shouldCloneAtCallsite = true;
args.rval().setUndefined();
return true;
}
@ -217,7 +231,6 @@ js::intrinsic_Dump(JSContext *cx, unsigned argc, Value *vp)
CallArgs args = CallArgsFromVp(argc, vp);
RootedValue val(cx, args[0]);
js_DumpValue(val);
fprintf(stderr, "\n");
args.rval().setUndefined();
return true;
}
@ -458,6 +471,7 @@ JSFunctionSpec intrinsic_functions[] = {
JS_FN("AssertionFailed", intrinsic_AssertionFailed, 1,0),
JS_FN("SetScriptHints", intrinsic_SetScriptHints, 2,0),
JS_FN("MakeConstructible", intrinsic_MakeConstructible, 1,0),
JS_FN("MakeWrappable", intrinsic_MakeWrappable, 1,0),
JS_FN("DecompileArg", intrinsic_DecompileArg, 2,0),
JS_FN("RuntimeDefaultLocale", intrinsic_RuntimeDefaultLocale, 0,0),
@ -515,6 +529,8 @@ JSRuntime::initSelfHosting(JSContext *cx)
CompileOptions options(cx);
options.setFileAndLine("self-hosted", 1);
options.setSelfHostingMode(true);
options.setSourcePolicy(CompileOptions::NO_SOURCE);
options.setVersion(JSVERSION_LATEST);
/*
* Set a temporary error reporter printing to stderr because it is too
@ -606,8 +622,14 @@ CloneObject(JSContext *cx, HandleObject srcObj, CloneMemory &clonedObjects)
return p->value;
RootedObject clone(cx);
if (srcObj->isFunction()) {
RootedFunction fun(cx, srcObj->toFunction());
clone = CloneFunctionObject(cx, fun, cx->global(), fun->getAllocKind());
if (srcObj->toFunction()->isWrappable()) {
clone = srcObj;
if (!cx->compartment->wrap(cx, clone.address()))
return NULL;
} else {
RootedFunction fun(cx, srcObj->toFunction());
clone = CloneFunctionObject(cx, fun, cx->global(), fun->getAllocKind());
}
} else if (srcObj->isRegExp()) {
RegExpObject &reobj = srcObj->asRegExp();
RootedAtom source(cx, reobj.getSource());
@ -679,7 +701,7 @@ JSRuntime::cloneSelfHostedFunctionScript(JSContext *cx, Handle<PropertyName*> na
return false;
RootedFunction sourceFun(cx, funVal.toObject().toFunction());
Rooted<JSScript*> sourceScript(cx, sourceFun->nonLazyScript());
RootedScript sourceScript(cx, sourceFun->nonLazyScript());
JS_ASSERT(!sourceScript->enclosingStaticScope());
RawScript cscript = CloneScript(cx, NullPtr(), targetFun, sourceScript);
if (!cscript)
@ -713,3 +735,23 @@ JSRuntime::cloneSelfHostedValue(JSContext *cx, Handle<PropertyName*> name, Mutab
vp.set(val);
return true;
}
bool
JSRuntime::maybeWrappedSelfHostedFunction(JSContext *cx, Handle<PropertyName*> name,
MutableHandleValue funVal)
{
RootedObject shg(cx, selfHostingGlobal_);
RootedId id(cx, NameToId(name));
if (!GetUnclonedValue(cx, shg, id, funVal))
return false;
JS_ASSERT(funVal.isObject());
JS_ASSERT(funVal.toObject().isCallable());
if (!funVal.toObject().toFunction()->isWrappable()) {
funVal.setUndefined();
return true;
}
return cx->compartment->wrap(cx, funVal);
}