Bug 1348407 - Initialize %ThrowTypeError% lazily, simplify CreateFunctionPrototype. r=jwalden

--HG--
extra : rebase_source : 6ec777eabc14b501672184aa0ffc096b741e9ec8
This commit is contained in:
Jan de Mooij 2018-01-08 10:26:00 +01:00
Родитель 04e91897cf
Коммит 9fc2afbd44
6 изменённых файлов: 69 добавлений и 67 удалений

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

@ -0,0 +1,6 @@
if (!('oomTest' in this))
quit();
x = evalcx("lazy");
oomTest(function () {
x.eval("1");
});

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

@ -116,8 +116,8 @@ AdvanceToActiveCallLinear(JSContext* cx, NonBuiltinScriptFrameIter& iter, Handle
return false;
}
static void
ThrowTypeErrorBehavior(JSContext* cx)
void
js::ThrowTypeErrorBehavior(JSContext* cx)
{
JS_ReportErrorFlagsAndNumberASCII(cx, JSREPORT_ERROR, GetErrorMessage, nullptr,
JSMSG_THROW_TYPE_ERROR);
@ -814,13 +814,6 @@ fun_trace(JSTracer* trc, JSObject* obj)
obj->as<JSFunction>().trace(trc);
}
static bool
ThrowTypeError(JSContext* cx, unsigned argc, Value* vp)
{
ThrowTypeErrorBehavior(cx);
return false;
}
static JSObject*
CreateFunctionConstructor(JSContext* cx, JSProtoKey key)
{
@ -906,51 +899,6 @@ CreateFunctionPrototype(JSContext* cx, JSProtoKey key)
if (!JSObject::setNewGroupUnknown(cx, &JSFunction::class_, functionProto))
return nullptr;
// Set the prototype before we call NewFunctionWithProto below. This
// ensures EmptyShape::getInitialShape can share function shapes.
self->setPrototype(key, ObjectValue(*functionProto));
// Construct the unique [[%ThrowTypeError%]] function object, used only for
// "callee" and "caller" accessors on strict mode arguments objects. (The
// spec also uses this for "arguments" and "caller" on various functions,
// but we're experimenting with implementing them using accessors on
// |Function.prototype| right now.)
//
// Note that we can't use NewFunction here, even though we want the normal
// Function.prototype for our proto, because we're still in the middle of
// creating that as far as the world is concerned, so things will get all
// confused.
RootedFunction throwTypeError(cx,
NewFunctionWithProto(cx, ThrowTypeError, 0, JSFunction::NATIVE_FUN,
nullptr, nullptr, functionProto, AllocKind::FUNCTION,
SingletonObject));
if (!throwTypeError || !PreventExtensions(cx, throwTypeError))
return nullptr;
// The "length" property of %ThrowTypeError% is non-configurable, adjust
// the default property attributes accordingly.
Rooted<PropertyDescriptor> nonConfigurableDesc(cx);
nonConfigurableDesc.setAttributes(JSPROP_PERMANENT | JSPROP_IGNORE_READONLY |
JSPROP_IGNORE_ENUMERATE | JSPROP_IGNORE_VALUE);
RootedId lengthId(cx, NameToId(cx->names().length));
ObjectOpResult lengthResult;
if (!NativeDefineProperty(cx, throwTypeError, lengthId, nonConfigurableDesc, lengthResult))
return nullptr;
MOZ_ASSERT(lengthResult);
// Non-standard: Also change "name" to non-configurable. ECMAScript defines
// %ThrowTypeError% as an anonymous function, i.e. it shouldn't actually
// get an own "name" property. To be consistent with other built-in,
// anonymous functions, we don't delete %ThrowTypeError%'s "name" property.
RootedId nameId(cx, NameToId(cx->names().name));
ObjectOpResult nameResult;
if (!NativeDefineProperty(cx, throwTypeError, nameId, nonConfigurableDesc, nameResult))
return nullptr;
MOZ_ASSERT(nameResult);
self->setThrowTypeError(throwTypeError);
return functionProto;
}

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

@ -796,6 +796,9 @@ FunctionHasDefaultHasInstance(JSFunction* fun, const WellKnownSymbols& symbols);
extern bool
fun_symbolHasInstance(JSContext* cx, unsigned argc, Value* vp);
extern void
ThrowTypeErrorBehavior(JSContext* cx);
/*
* Function extended with reserved slots for use by various kinds of functions.
* Most functions do not have these extensions, but enough do that efficient

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

@ -793,9 +793,13 @@ UnmappedArgumentsObject::obj_resolve(JSContext* cx, HandleObject obj, HandleId i
if (!JSID_IS_ATOM(id, cx->names().callee))
return true;
JSObject* throwTypeError = GlobalObject::getOrCreateThrowTypeError(cx, cx->global());
if (!throwTypeError)
return false;
attrs = JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER;
getter = CastAsGetterOp(argsobj->global().getThrowTypeError());
setter = CastAsSetterOp(argsobj->global().getThrowTypeError());
getter = CastAsGetterOp(throwTypeError);
setter = CastAsSetterOp(throwTypeError);
}
attrs |= JSPROP_RESOLVING;

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

@ -304,6 +304,57 @@ GlobalObject::initBuiltinConstructor(JSContext* cx, Handle<GlobalObject*> global
return true;
}
static bool
ThrowTypeError(JSContext* cx, unsigned argc, Value* vp)
{
ThrowTypeErrorBehavior(cx);
return false;
}
/* static */ JSObject*
GlobalObject::getOrCreateThrowTypeError(JSContext* cx, Handle<GlobalObject*> global)
{
Value v = global->getReservedSlot(THROWTYPEERROR);
if (v.isObject())
return &v.toObject();
MOZ_ASSERT(v.isUndefined());
// Construct the unique [[%ThrowTypeError%]] function object, used only for
// "callee" and "caller" accessors on strict mode arguments objects. (The
// spec also uses this for "arguments" and "caller" on various functions,
// but we're experimenting with implementing them using accessors on
// |Function.prototype| right now.)
RootedFunction throwTypeError(cx, NewNativeFunction(cx, ThrowTypeError, 0, nullptr));
if (!throwTypeError || !PreventExtensions(cx, throwTypeError))
return nullptr;
// The "length" property of %ThrowTypeError% is non-configurable, adjust
// the default property attributes accordingly.
Rooted<PropertyDescriptor> nonConfigurableDesc(cx);
nonConfigurableDesc.setAttributes(JSPROP_PERMANENT | JSPROP_IGNORE_READONLY |
JSPROP_IGNORE_ENUMERATE | JSPROP_IGNORE_VALUE);
RootedId lengthId(cx, NameToId(cx->names().length));
ObjectOpResult lengthResult;
if (!NativeDefineProperty(cx, throwTypeError, lengthId, nonConfigurableDesc, lengthResult))
return nullptr;
MOZ_ASSERT(lengthResult);
// Non-standard: Also change "name" to non-configurable. ECMAScript defines
// %ThrowTypeError% as an anonymous function, i.e. it shouldn't actually
// get an own "name" property. To be consistent with other built-in,
// anonymous functions, we don't delete %ThrowTypeError%'s "name" property.
RootedId nameId(cx, NameToId(cx->names().name));
ObjectOpResult nameResult;
if (!NativeDefineProperty(cx, throwTypeError, nameId, nonConfigurableDesc, nameResult))
return nullptr;
MOZ_ASSERT(nameResult);
global->setReservedSlot(THROWTYPEERROR, ObjectValue(*throwTypeError));
return throwTypeError;
}
GlobalObject*
GlobalObject::createInternal(JSContext* cx, const Class* clasp)
{

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

@ -124,11 +124,6 @@ class GlobalObject : public NativeObject
LexicalEnvironmentObject& lexicalEnvironment() const;
GlobalScope& emptyGlobalScope() const;
void setThrowTypeError(JSFunction* fun) {
MOZ_ASSERT(getSlotRef(THROWTYPEERROR).isUndefined());
setSlot(THROWTYPEERROR, ObjectValue(*fun));
}
void setOriginalEval(JSObject* evalobj) {
MOZ_ASSERT(getSlotRef(EVAL).isUndefined());
setSlot(EVAL, ObjectValue(*evalobj));
@ -743,12 +738,7 @@ class GlobalObject : public NativeObject
Handle<GlobalObject*> global);
RegExpStatics* getAlreadyCreatedRegExpStatics() const;
JSObject* getThrowTypeError() const {
const Value v = getReservedSlot(THROWTYPEERROR);
MOZ_ASSERT(v.isObject(),
"attempting to access [[ThrowTypeError]] too early");
return &v.toObject();
}
static JSObject* getOrCreateThrowTypeError(JSContext* cx, Handle<GlobalObject*> global);
static bool isRuntimeCodeGenEnabled(JSContext* cx, Handle<GlobalObject*> global);