Bug 999790: Make asm.js modules and functions constructible; r=luke

--HG--
extra : rebase_source : b4d64db2b3faeb5aaac0d3f104de60b1c47f1fc2
This commit is contained in:
Benjamin Bouvier 2014-04-30 21:31:28 +02:00
Родитель f3f4985fe0
Коммит 35e35895f4
4 изменённых файлов: 88 добавлений и 7 удалений

Просмотреть файл

@ -0,0 +1,69 @@
function CanBeConstructed(f) {
var caught = false;
try {
new f;
} catch (e) {
caught = true;
}
return !caught;
}
function IsConstructedFunction(f) {
return f.hasOwnProperty('length')
&& f.hasOwnProperty('name')
&& f.hasOwnProperty('arguments')
&& f.hasOwnProperty('caller')
&& f.hasOwnProperty('prototype')
&& f.prototype.hasOwnProperty('constructor')
&& f.prototype.constructor === f;
}
function IsntConstructedFunction(f) {
return !f.hasOwnProperty('length')
&& !f.hasOwnProperty('name')
&& !f.hasOwnProperty('arguments')
&& !f.hasOwnProperty('caller')
&& !f.hasOwnProperty('prototype')
}
var m = function() {
"use asm"
function g(){}
return g;
};
assertEq(CanBeConstructed(m), true, "asm.js modules can't be constructed");
var objM = new m;
assertEq(IsConstructedFunction(objM), true);
var g = m();
assertEq(CanBeConstructed(g), true, "asm.js functions can't be constructed");
// g is a ctor returning an primitive value, thus an empty object
assertEq(Object.getOwnPropertyNames(new g).length, 0);
var n = function() {
"use asm"
function g(){return 42.0}
function h(){return 42}
return {
g: g,
h: h
};
};
assertEq(CanBeConstructed(n), true, "asm.js modules can't be constructed");
var objN = new n;
// objN is an object with attributes g and h
assertEq(IsntConstructedFunction(objN), true);
assertEq(objN.hasOwnProperty('g'), true);
assertEq(objN.hasOwnProperty('h'), true);
assertEq(IsConstructedFunction(objN.g), true);
assertEq(IsConstructedFunction(objN.h), true);
var h = n().h;
assertEq(CanBeConstructed(h), true, "asm.js functions can't be constructed");
// h is a ctor returning an primitive value, thus an empty object
assertEq(Object.getOwnPropertyNames(new h).length, 0);
assertEq(typeof(function() {"use asm"; return {}}.prototype) !== 'undefined', true);

Просмотреть файл

@ -515,6 +515,16 @@ CallAsmJS(JSContext *cx, unsigned argc, Value *vp)
return false;
}
if (callArgs.isConstructing()) {
// By spec, when a function is called as a constructor and this function
// returns a primary type, which is the case for all asm.js exported
// functions, the returned value is discarded and an empty object is
// returned instead.
JSObject *obj = NewBuiltinClassInstance(cx, &JSObject::class_);
callArgs.rval().set(ObjectValue(*obj));
return true;
}
switch (func.returnType()) {
case AsmJSModule::Return_Void:
callArgs.rval().set(UndefinedValue());
@ -536,7 +546,7 @@ NewExportedFunction(JSContext *cx, const AsmJSModule::ExportedFunction &func,
{
RootedPropertyName name(cx, func.name());
JSFunction *fun = NewFunction(cx, NullPtr(), CallAsmJS, func.numArgs(),
JSFunction::NATIVE_FUN, cx->global(), name,
JSFunction::ASMJS_CTOR, cx->global(), name,
JSFunction::ExtendedFinalizeKind);
if (!fun)
return nullptr;
@ -798,8 +808,8 @@ js::NewAsmJSModuleFunction(ExclusiveContext *cx, JSFunction *origFun, HandleObje
{
RootedPropertyName name(cx, origFun->name());
JSFunction::Flags flags = origFun->isLambda() ? JSFunction::NATIVE_LAMBDA_FUN
: JSFunction::NATIVE_FUN;
JSFunction::Flags flags = origFun->isLambda() ? JSFunction::ASMJS_LAMBDA_CTOR
: JSFunction::ASMJS_CTOR;
JSFunction *moduleFun = NewFunction(cx, NullPtr(), LinkAsmJS, origFun->nargs(),
flags, NullPtr(), name,
JSFunction::ExtendedFinalizeKind, TenuredObject);

Просмотреть файл

@ -193,7 +193,7 @@ ResolveInterpretedFunctionPrototype(JSContext *cx, HandleObject obj)
{
#ifdef DEBUG
JSFunction *fun = &obj->as<JSFunction>();
JS_ASSERT(fun->isInterpreted());
JS_ASSERT(fun->isInterpreted() || fun->isAsmJSNative());
JS_ASSERT(!fun->isFunctionPrototype());
#endif

Просмотреть файл

@ -46,13 +46,14 @@ class JSFunction : public JSObject
SELF_HOSTED_CTOR = 0x0200, /* function is self-hosted builtin constructor and
must be constructible but not decompilable. */
HAS_REST = 0x0400, /* function has a rest (...) parameter */
// 0x0800 is available
ASMJS = 0x0800, /* function is an asm.js module or exported function */
INTERPRETED_LAZY = 0x1000, /* function is interpreted but doesn't have a script yet */
ARROW = 0x2000, /* ES6 '(args) => body' syntax */
/* Derived Flags values for convenience: */
NATIVE_FUN = 0,
NATIVE_LAMBDA_FUN = NATIVE_FUN | LAMBDA,
ASMJS_CTOR = ASMJS | NATIVE_CTOR,
ASMJS_LAMBDA_CTOR = ASMJS | NATIVE_CTOR | LAMBDA,
INTERPRETED_LAMBDA = INTERPRETED | LAMBDA,
INTERPRETED_LAMBDA_ARROW = INTERPRETED | LAMBDA | ARROW
};
@ -118,6 +119,7 @@ class JSFunction : public JSObject
/* Possible attributes of a native function: */
bool isNativeConstructor() const { return flags() & NATIVE_CTOR; }
bool isAsmJSNative() const { return flags() & ASMJS; }
/* Possible attributes of an interpreted function: */
bool isFunctionPrototype() const { return flags() & IS_FUN_PROTO; }
@ -147,7 +149,7 @@ class JSFunction : public JSObject
/* Compound attributes: */
bool isBuiltin() const {
return isNative() || isSelfHostedBuiltin();
return (isNative() && !isAsmJSNative()) || isSelfHostedBuiltin();
}
bool isInterpretedConstructor() const {
// Note: the JITs inline this check, so be careful when making changes