From 389ff7a57d641c82315ce6235d9881a9cd5adeb5 Mon Sep 17 00:00:00 2001 From: Cameron Kaiser Date: Sat, 15 Sep 2018 16:52:51 -0700 Subject: [PATCH] #521: M1226762 --- js/src/builtin/Utilities.js | 13 +++++++ .../self-hosting/getbuiltinconstructor.js | 13 +++++++ js/src/vm/SelfHosting.cpp | 36 +++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 js/src/jit-test/tests/self-hosting/getbuiltinconstructor.js diff --git a/js/src/builtin/Utilities.js b/js/src/builtin/Utilities.js index 4a0329c2d..8e232e8a0 100644 --- a/js/src/builtin/Utilities.js +++ b/js/src/builtin/Utilities.js @@ -152,6 +152,19 @@ function GetIterator(obj, method) { return iterator; } +var _builtinCtorsCache = {__proto__: null}; + +function GetBuiltinConstructor(builtinName) { + var ctor = _builtinCtorsCache[builtinName] || + (_builtinCtorsCache[builtinName] = GetBuiltinConstructorImpl(builtinName)); + assert(ctor, `No builtin with name "${builtinName}" found`); + return ctor; +} + +function GetBuiltinPrototype(builtinName) { + return (_builtinCtorsCache[builtinName] || GetBuiltinConstructor(builtinName)).prototype; +} + // ES6 draft 20150317 7.3.20. function SpeciesConstructor(obj, defaultConstructor) { // Step 1. diff --git a/js/src/jit-test/tests/self-hosting/getbuiltinconstructor.js b/js/src/jit-test/tests/self-hosting/getbuiltinconstructor.js new file mode 100644 index 000000000..57134875a --- /dev/null +++ b/js/src/jit-test/tests/self-hosting/getbuiltinconstructor.js @@ -0,0 +1,13 @@ +let getCtor = getSelfHostedValue('GetBuiltinConstructor'); + +assertEq(getCtor('Array'), Array); + +let origArray = Array; +Array = function(){}; +assertEq(getCtor('Array') == Array, false); +assertEq(getCtor('Array'), origArray); + +let origMap = Map; +Map = function(){}; +assertEq(getCtor('Map') == Map, false); +assertEq(getCtor('Map'), origMap); diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index bac95301c..683ed29d9 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -148,6 +148,41 @@ intrinsic_IsInstanceOfBuiltin(JSContext* cx, unsigned argc, Value* vp) return true; } +/** + * Self-hosting intrinsic returning the original constructor for a builtin + * the name of which is the first and only argument. + * + * The return value is guaranteed to be the original constructor even if + * content code changed the named binding on the global object. + * + * This intrinsic shouldn't be called directly. Instead, the + * `GetBuiltinConstructor` and `GetBuiltinPrototype` helper functions in + * Utilities.js should be used, as they cache results, improving performance. + */ +static bool +intrinsic_GetBuiltinConstructor(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + MOZ_ASSERT(args.length() == 1); + RootedString str(cx, args[0].toString()); + JSAtom* atom; + if (str->isAtom()) { + atom = &str->asAtom(); + } else { + atom = AtomizeString(cx, str); + if (!atom) + return false; + } + RootedId id(cx, AtomToId(atom)); + JSProtoKey key = JS_IdToProtoKey(cx, id); + MOZ_ASSERT(key != JSProto_Null); + RootedObject ctor(cx); + if (!GetBuiltinConstructor(cx, key, &ctor)) + return false; + args.rval().setObject(*ctor); + return true; +} + static bool intrinsic_SubstringKernel(JSContext* cx, unsigned argc, Value* vp) { @@ -1467,6 +1502,7 @@ static const JSFunctionSpec intrinsic_functions[] = { JS_FN("ToPropertyKey", intrinsic_ToPropertyKey, 1,0), JS_INLINABLE_FN("IsCallable", intrinsic_IsCallable, 1,0, IntrinsicIsCallable), JS_FN("IsConstructor", intrinsic_IsConstructor, 1,0), + JS_FN("GetBuiltinConstructorImpl", intrinsic_GetBuiltinConstructor, 1,0), JS_FN("OwnPropertyKeys", intrinsic_OwnPropertyKeys, 1,0), JS_FN("ThrowRangeError", intrinsic_ThrowRangeError, 4,0), JS_FN("ThrowTypeError", intrinsic_ThrowTypeError, 4,0),