зеркало из https://github.com/mozilla/pjs.git
Bug 202019 - Built-in functions should not be constructors. r=jorendorff.
--HG-- extra : rebase_source : 2f845218384004c09a60c59ae03704729f1d91dc
This commit is contained in:
Родитель
edbfa19587
Коммит
646ecb971c
|
@ -767,7 +767,6 @@ nsDOMWorkerFunctions::CTypesLazyGetter(JSContext* aCx,
|
|||
JS_GetPropertyById(aCx, aObj, aId, aVp);
|
||||
}
|
||||
#endif
|
||||
|
||||
JSFunctionSpec gDOMWorkerFunctions[] = {
|
||||
{ "dump", nsDOMWorkerFunctions::Dump, 1, 0 },
|
||||
{ "setTimeout", nsDOMWorkerFunctions::SetTimeout, 1, 0 },
|
||||
|
@ -775,19 +774,16 @@ JSFunctionSpec gDOMWorkerFunctions[] = {
|
|||
{ "setInterval", nsDOMWorkerFunctions::SetInterval, 1, 0 },
|
||||
{ "clearInterval", nsDOMWorkerFunctions::KillTimeout, 1, 0 },
|
||||
{ "importScripts", nsDOMWorkerFunctions::LoadScripts, 1, 0 },
|
||||
{ "XMLHttpRequest", nsDOMWorkerFunctions::NewXMLHttpRequest, 0, 0 },
|
||||
{ "Worker", nsDOMWorkerFunctions::NewWorker, 1, 0 },
|
||||
{ "XMLHttpRequest", nsDOMWorkerFunctions::NewXMLHttpRequest, 0, JSFUN_CONSTRUCTOR },
|
||||
{ "Worker", nsDOMWorkerFunctions::NewWorker, 1, JSFUN_CONSTRUCTOR },
|
||||
{ "atob", nsDOMWorkerFunctions::AtoB, 1, 0 },
|
||||
{ "btoa", nsDOMWorkerFunctions::BtoA, 1, 0 },
|
||||
{ nsnull, nsnull, 0, 0 }
|
||||
};
|
||||
|
||||
JSFunctionSpec gDOMWorkerChromeFunctions[] = {
|
||||
{ "ChromeWorker", nsDOMWorkerFunctions::NewChromeWorker, 1, 0 },
|
||||
{ "ChromeWorker", nsDOMWorkerFunctions::NewChromeWorker, 1, JSFUN_CONSTRUCTOR },
|
||||
{ nsnull, nsnull, 0, 0 }
|
||||
};
|
||||
|
||||
|
||||
enum DOMWorkerStructuredDataType
|
||||
{
|
||||
// We have a special tag for XPCWrappedNatives that are being passed between
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
for (a = 0; a < 4; a++) {
|
||||
new Math.round(0).t
|
||||
try {
|
||||
for (a = 0; a < 4; a++) {
|
||||
new Math.round(0).t
|
||||
}
|
||||
}
|
||||
|
||||
catch (e) {}
|
||||
/* Don't assert. */
|
||||
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
Object.defineProperty(Function.prototype, "prototype", {set:function(){}});
|
||||
var x;
|
||||
for (var i = 0; i < HOTLOOP + 2; i++)
|
||||
x = new Function.prototype;
|
||||
assertEq(toString.call(x), "[object Object]");
|
||||
assertEq(Object.getPrototypeOf(x), Object.prototype);
|
|
@ -1,6 +0,0 @@
|
|||
Function.prototype.prototype = function () {};
|
||||
var x;
|
||||
for (var i = 0; i < HOTLOOP + 2; i++)
|
||||
x = new Function.prototype;
|
||||
assertEq(toString.call(x), "[object Object]");
|
||||
assertEq(Object.getPrototypeOf(x), Function.prototype.prototype);
|
|
@ -1,12 +0,0 @@
|
|||
var a = [];
|
||||
function next() {
|
||||
var x = {};
|
||||
a.push(x);
|
||||
return x;
|
||||
}
|
||||
Object.defineProperty(Function.prototype, 'prototype', {get: next});
|
||||
var b = [];
|
||||
for (var i = 0; i < HOTLOOP + 2; i++)
|
||||
b[i] = new Function.prototype;
|
||||
for (var i = 0; i < HOTLOOP + 2; i++)
|
||||
assertEq(Object.getPrototypeOf(b[i]), a[i]);
|
|
@ -1,10 +0,0 @@
|
|||
Object.defineProperty(Function.prototype, 'prototype',
|
||||
{get: function () { if (i == HOTLOOP + 1) throw "X"; }});
|
||||
var x;
|
||||
try {
|
||||
for (var i = 0; i < HOTLOOP + 2; i++)
|
||||
x = new Function.prototype;
|
||||
} catch (exc) {
|
||||
assertEq(i, HOTLOOP + 1);
|
||||
assertEq(exc, "X");
|
||||
}
|
|
@ -1,19 +1,18 @@
|
|||
var funProto = Function.prototype;
|
||||
assertEq(Object.getOwnPropertyDescriptor(funProto, "prototype"), undefined);
|
||||
|
||||
assertEq(parseInt.prototype, undefined);
|
||||
|
||||
var oldObj;
|
||||
for (var i = 0, sz = RUNLOOP; i < sz; oldObj = obj, i++)
|
||||
{
|
||||
var obj = new funProto;
|
||||
assertEq(obj === oldObj, false);
|
||||
assertEq(Object.prototype.toString.call(obj), "[object Object]");
|
||||
|
||||
try {
|
||||
var obj = new funProto;
|
||||
}
|
||||
catch (e) {}
|
||||
assertEq(Object.getOwnPropertyDescriptor(funProto, "prototype"), undefined);
|
||||
assertEq(Object.getOwnPropertyDescriptor(parseInt, "prototype"), undefined);
|
||||
assertEq(parseInt.prototype, undefined);
|
||||
}
|
||||
|
||||
checkStats({
|
||||
recorderStarted: 1,
|
||||
recorderAborted: 0,
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
var gen = (function () {yield})();
|
||||
var t = gen.throw;
|
||||
|
||||
try {
|
||||
new t;
|
||||
} catch (e) {
|
||||
actual = "" + e;
|
||||
}
|
||||
assertEq(actual, "TypeError: Generator.prototype.throw called on incompatible Object");
|
||||
|
||||
assertEq(actual, "TypeError: t is not a constructor");
|
||||
|
|
|
@ -2,15 +2,16 @@
|
|||
|
||||
// proxies can return primitives
|
||||
assertEq(new (Proxy.createFunction({}, function(){}, function(){})), undefined);
|
||||
|
||||
x = Proxy.createFunction((function () {}), Uint16Array, wrap)
|
||||
new(wrap(x))
|
||||
|
||||
// proxies can return the callee
|
||||
var x = Proxy.createFunction({}, function (q) { return q; });
|
||||
new x(x);
|
||||
|
||||
// not an error
|
||||
new (Proxy.createFunction({}, "".indexOf));
|
||||
|
||||
assertEq(new x(x), x);
|
||||
try {
|
||||
var x = (Proxy.createFunction({}, "".indexOf));
|
||||
new x;
|
||||
}
|
||||
catch (e) {
|
||||
assertEq(e.message, 'new x is not a constructor');
|
||||
}
|
||||
throw "ExitCleanly"
|
||||
|
|
|
@ -152,12 +152,10 @@ struct JSFunction : public JSObject_Slots2
|
|||
bool isConstructor() const { return flags & JSFUN_CONSTRUCTOR; }
|
||||
bool isHeavyweight() const { return JSFUN_HEAVYWEIGHT_TEST(flags); }
|
||||
bool isFlatClosure() const { return FUN_KIND(this) == JSFUN_FLAT_CLOSURE; }
|
||||
|
||||
bool isFunctionPrototype() const { return flags & JSFUN_PROTOTYPE; }
|
||||
|
||||
bool isInterpretedConstructor() const { return isInterpreted() && !isFunctionPrototype(); }
|
||||
/* Returns the strictness of this function, which must be interpreted. */
|
||||
inline bool inStrictMode() const;
|
||||
|
||||
void setArgCount(uint16 nargs) {
|
||||
JS_ASSERT(this->nargs == 0);
|
||||
this->nargs = nargs;
|
||||
|
|
|
@ -1251,56 +1251,37 @@ InvokeConstructor(JSContext *cx, const CallArgs &argsRef)
|
|||
JS_ASSERT(!js_FunctionClass.construct);
|
||||
CallArgs args = argsRef;
|
||||
|
||||
JSObject *callee;
|
||||
if (args.calleev().isPrimitive() || !(callee = &args.callee())->getParent()) {
|
||||
js_ReportIsNotFunction(cx, &args.calleev(), JSV2F_CONSTRUCT);
|
||||
return false;
|
||||
}
|
||||
if (args.calleev().isObject()) {
|
||||
JSObject *callee = &args.callee();
|
||||
if (callee->isFunction()) {
|
||||
JSFunction *fun = callee->getFunctionPrivate();
|
||||
|
||||
/* Handle the fast-constructors cases before falling into the general case . */
|
||||
Class *clasp = callee->getClass();
|
||||
JSFunction *fun = NULL;
|
||||
if (clasp == &js_FunctionClass) {
|
||||
fun = callee->getFunctionPrivate();
|
||||
if (fun->isConstructor()) {
|
||||
args.thisv().setMagicWithObjectOrNullPayload(NULL);
|
||||
return CallJSNativeConstructor(cx, fun->u.n.native, args.argc(), args.base());
|
||||
}
|
||||
} else if (clasp->construct) {
|
||||
args.thisv().setMagicWithObjectOrNullPayload(NULL);
|
||||
return CallJSNativeConstructor(cx, clasp->construct, args.argc(), args.base());
|
||||
}
|
||||
|
||||
/* Scripts create their own |this| in JSOP_BEGIN */
|
||||
if (!fun || !fun->isInterpreted()) {
|
||||
JSObject *obj = js_CreateThis(cx, callee);
|
||||
if (!obj)
|
||||
return false;
|
||||
args.thisv().setObject(*obj);
|
||||
}
|
||||
|
||||
if (!Invoke(cx, args, JSINVOKE_CONSTRUCT))
|
||||
return false;
|
||||
|
||||
if (args.rval().isPrimitive()) {
|
||||
if (clasp != &js_FunctionClass) {
|
||||
/* native [[Construct]] returning primitive is error */
|
||||
JSAutoByteString bytes;
|
||||
if (js_ValueToPrintable(cx, args.rval(), &bytes)) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_NEW_RESULT, bytes.ptr());
|
||||
return false;
|
||||
if (fun->isConstructor()) {
|
||||
args.thisv().setMagicWithObjectOrNullPayload(NULL);
|
||||
return CallJSNativeConstructor(cx, fun->u.n.native, args.argc(), args.base());
|
||||
}
|
||||
|
||||
if (!fun->isInterpretedConstructor())
|
||||
goto error;
|
||||
|
||||
if (!Invoke(cx, args, JSINVOKE_CONSTRUCT))
|
||||
return false;
|
||||
|
||||
JS_ASSERT(args.rval().isObject());
|
||||
JS_RUNTIME_METER(cx->runtime, constructs);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* The interpreter fixes rval for us. */
|
||||
JS_ASSERT(!fun->isInterpreted());
|
||||
|
||||
args.rval() = args.thisv();
|
||||
Class *clasp = callee->getClass();
|
||||
if (clasp->construct) {
|
||||
args.thisv().setMagicWithObjectOrNullPayload(NULL);
|
||||
return CallJSNativeConstructor(cx, clasp->construct, args.argc(), args.base());
|
||||
}
|
||||
}
|
||||
|
||||
JS_RUNTIME_METER(cx->runtime, constructs);
|
||||
return true;
|
||||
error:
|
||||
js_ReportIsNotFunction(cx, &args.calleev(), JSV2F_CONSTRUCT);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -4588,7 +4569,7 @@ BEGIN_CASE(JSOP_NEW)
|
|||
*/
|
||||
if (IsFunctionObject(vp[0], &callee)) {
|
||||
newfun = callee->getFunctionPrivate();
|
||||
if (newfun->isInterpreted()) {
|
||||
if (newfun->isInterpretedConstructor()) {
|
||||
if (newfun->u.i.script->isEmpty()) {
|
||||
JSObject *obj2 = js_CreateThisForFunction(cx, callee);
|
||||
if (!obj2)
|
||||
|
|
|
@ -409,12 +409,10 @@ void
|
|||
stubs::UncachedNewHelper(VMFrame &f, uint32 argc, UncachedCallResult *ucr)
|
||||
{
|
||||
ucr->init();
|
||||
|
||||
JSContext *cx = f.cx;
|
||||
Value *vp = f.regs.sp - (argc + 2);
|
||||
|
||||
/* Try to do a fast inline call before the general Invoke path. */
|
||||
if (IsFunctionObject(*vp, &ucr->fun) && ucr->fun->isInterpreted()) {
|
||||
if (IsFunctionObject(*vp, &ucr->fun) && ucr->fun->isInterpretedConstructor()) {
|
||||
ucr->callee = &vp->toObject();
|
||||
if (!UncachedInlineCall(f, JSFRAME_CONSTRUCTING, &ucr->codeAddr, &ucr->unjittable, argc))
|
||||
THROW();
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
function checkMethod(method) {
|
||||
try {
|
||||
new method();
|
||||
assertEq(0, 1, "not reached " + method);
|
||||
} catch (e) {
|
||||
assertEq(e.message, "method is not a constructor");
|
||||
}
|
||||
}
|
||||
|
||||
function checkMethods(proto) {
|
||||
var names = Object.getOwnPropertyNames(proto);
|
||||
for (var i = 0; i < names.length; i++) {
|
||||
var name = names[i];
|
||||
if (name == "constructor")
|
||||
continue;
|
||||
var prop = proto[name];
|
||||
if (typeof prop === "function")
|
||||
checkMethod(prop);
|
||||
}
|
||||
}
|
||||
|
||||
checkMethod(Function.prototype);
|
||||
checkMethods(JSON);
|
||||
checkMethods(Math);
|
||||
checkMethods(Proxy);
|
||||
|
||||
var builtin_ctors = [
|
||||
Object, Function, Array, String, Boolean, Number, Date, RegExp, Error,
|
||||
EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError,
|
||||
];
|
||||
|
||||
for (var i = 0; i < builtin_ctors.length; i++) {
|
||||
checkMethods(builtin_ctors[i]);
|
||||
checkMethods(builtin_ctors[i].prototype);
|
||||
}
|
||||
|
||||
var builtin_funcs = [
|
||||
eval, isFinite, isNaN, parseFloat, parseInt,
|
||||
decodeURI, decodeURIComponent, encodeURI, encodeURIComponent
|
||||
];
|
||||
|
||||
for (var i = 0; i < builtin_funcs.length; i++) {
|
||||
checkMethod(builtin_funcs[i]);
|
||||
}
|
||||
|
||||
if (typeof reportCompare == 'function')
|
||||
reportCompare(0, 0, "ok");
|
|
@ -10,3 +10,4 @@ script function-call.js
|
|||
script redefine-arguments-length.js
|
||||
script builtin-no-prototype.js
|
||||
script Function-arguments-gc.js
|
||||
script builtin-no-construct.js
|
||||
|
|
|
@ -9,4 +9,5 @@ skip-if(!xulRuntime.shell) script function-definition-evaluate.js # needs evalua
|
|||
script future-reserved-words.js
|
||||
script builtin-methods-reject-null-undefined-this.js
|
||||
script regress-bug632003.js
|
||||
script new-with-non-constructor.js
|
||||
script error-undefined-message.js
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
function checkConstruct(thing, buggy) {
|
||||
try {
|
||||
new thing();
|
||||
assertEq(0, 1, "not reached " + thing);
|
||||
} catch (e) {
|
||||
if (buggy)
|
||||
assertEq(e.message, "new thing is not a constructor");
|
||||
else
|
||||
assertEq(e.message, "thing is not a constructor");
|
||||
}
|
||||
}
|
||||
|
||||
var re = /aaa/
|
||||
checkConstruct(re, false);
|
||||
|
||||
var boundFunctionPrototype = Function.prototype.bind();
|
||||
checkConstruct(boundFunctionPrototype, true);
|
||||
|
||||
var boundBuiltin = Math.sin.bind();
|
||||
checkConstruct(boundBuiltin, true);
|
||||
|
||||
/* We set the proxies construct trap to undefined,
|
||||
* so the call trap is used as constructor.
|
||||
*/
|
||||
|
||||
var proxiedFunctionPrototype = Proxy.create({}, Function.prototype, undefined);
|
||||
checkConstruct(proxiedFunctionPrototype, false);
|
||||
|
||||
var proxiedBuiltin = Proxy.create({}, parseInt, undefined);
|
||||
checkConstruct(proxiedBuiltin, false);
|
||||
|
||||
|
||||
if (typeof reportCompare == 'function')
|
||||
reportCompare(0, 0, "ok");
|
|
@ -103,7 +103,6 @@ XrayWrapperConstructor(JSContext *cx, uintN argc, jsval *vp)
|
|||
*vp = OBJECT_TO_JSVAL(obj);
|
||||
return JS_WrapValue(cx, vp);
|
||||
}
|
||||
|
||||
// static
|
||||
PRBool
|
||||
AttachNewConstructorObject(XPCCallContext &ccx, JSObject *aGlobalObject)
|
||||
|
@ -111,15 +110,13 @@ AttachNewConstructorObject(XPCCallContext &ccx, JSObject *aGlobalObject)
|
|||
JSObject *xpcnativewrapper =
|
||||
JS_DefineFunction(ccx, aGlobalObject, "XPCNativeWrapper",
|
||||
XrayWrapperConstructor, 1,
|
||||
JSPROP_READONLY | JSPROP_PERMANENT | JSFUN_STUB_GSOPS);
|
||||
JSPROP_READONLY | JSPROP_PERMANENT | JSFUN_STUB_GSOPS | JSFUN_CONSTRUCTOR);
|
||||
if (!xpcnativewrapper) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
return JS_DefineFunction(ccx, xpcnativewrapper, "unwrap", UnwrapNW, 1,
|
||||
JSPROP_READONLY | JSPROP_PERMANENT) != nsnull;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace XPCWrapper {
|
||||
|
|
Загрузка…
Ссылка в новой задаче