summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--js/public/Class.h2
-rw-r--r--js/src/jsapi.cpp9
-rw-r--r--js/src/vm/CommonPropertyNames.h1
-rw-r--r--js/src/vm/GlobalObject.cpp32
-rw-r--r--js/src/vm/GlobalObject.h3
5 files changed, 44 insertions, 3 deletions
diff --git a/js/public/Class.h b/js/public/Class.h
index f4fa9ccaf..3d73bce44 100644
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -779,7 +779,7 @@ struct JSClass {
// application.
#define JSCLASS_GLOBAL_APPLICATION_SLOTS 5
#define JSCLASS_GLOBAL_SLOT_COUNT \
- (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 45)
+ (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 46)
#define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \
(JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
#define JSCLASS_GLOBAL_FLAGS \
diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
index cb3945152..d75a3c33a 100644
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1029,13 +1029,17 @@ JS_ResolveStandardClass(JSContext* cx, HandleObject obj, HandleId id, bool* reso
/* Check whether we're resolving 'undefined', and define it if so. */
JSAtom* idAtom = JSID_TO_ATOM(id);
- JSAtom* undefinedAtom = cx->names().undefined;
- if (idAtom == undefinedAtom) {
+ if (idAtom == cx->names().undefined) {
*resolved = true;
return DefineProperty(cx, global, id, UndefinedHandleValue, nullptr, nullptr,
JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_RESOLVING);
}
+ // Resolve a "globalThis" self-referential property if necessary.
+ if (idAtom == cx->names().globalThis) {
+ return GlobalObject::maybeResolveGlobalThis(cx, global, resolved);
+ }
+
/* Try for class constructors/prototypes named by well-known atoms. */
stdnm = LookupStdName(cx->names(), idAtom, standard_class_names);
@@ -1088,6 +1092,7 @@ JS_MayResolveStandardClass(const JSAtomState& names, jsid id, JSObject* maybeObj
// better, we need a JSContext here; it's fine as it is.)
return atom == names.undefined ||
+ atom == names.globalThis ||
LookupStdName(names, atom, standard_class_names) ||
LookupStdName(names, atom, builtin_property_names);
}
diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h
index 420ee7535..b4a2de6f3 100644
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -160,6 +160,7 @@
macro(getPropertyDescriptor, getPropertyDescriptor, "getPropertyDescriptor") \
macro(getPrototypeOf, getPrototypeOf, "getPrototypeOf") \
macro(global, global, "global") \
+ macro(globalThis, globalThis, "globalThis") \
macro(Handle, Handle, "Handle") \
macro(has, has, "has") \
macro(hasOwn, hasOwn, "hasOwn") \
diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp
index a8d401af4..f6a53eef4 100644
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -296,6 +296,32 @@ GlobalObject::initBuiltinConstructor(JSContext* cx, Handle<GlobalObject*> global
return true;
}
+// Resolve a "globalThis" self-referential property if necessary,
+// per a stage-3 proposal. https://github.com/tc39/ecma262/pull/702
+//
+// We could also do this in |FinishObjectClassInit| to trim the global
+// resolve hook. Unfortunately, |ToWindowProxyIfWindow| doesn't work then:
+// the browser's |nsGlobalWindow::SetNewDocument| invokes Object init
+// *before* it sets the global's WindowProxy using |js::SetWindowProxy|.
+//
+// Refactoring global object creation code to support this approach is a
+// challenge for another day.
+/* static */ bool
+GlobalObject::maybeResolveGlobalThis(JSContext* cx, Handle<GlobalObject*> global, bool* resolved)
+{
+ if (global->getSlot(GLOBAL_THIS_RESOLVED).isUndefined()) {
+ RootedValue v(cx, ObjectValue(*ToWindowProxyIfWindow(global)));
+ if (!DefineProperty(cx, global, cx->names().globalThis, v, nullptr, nullptr, JSPROP_RESOLVING)) {
+ return false;
+ }
+
+ *resolved = true;
+ global->setSlot(GLOBAL_THIS_RESOLVED, BooleanValue(true));
+ }
+
+ return true;
+}
+
GlobalObject*
GlobalObject::createInternal(JSContext* cx, const Class* clasp)
{
@@ -419,6 +445,12 @@ GlobalObject::initStandardClasses(JSContext* cx, Handle<GlobalObject*> global)
return false;
}
+ // Resolve a "globalThis" self-referential property if necessary.
+ bool resolved;
+ if (!GlobalObject::maybeResolveGlobalThis(cx, global, &resolved)) {
+ return false;
+ }
+
for (size_t k = 0; k < JSProto_LIMIT; ++k) {
if (!ensureConstructor(cx, global, static_cast<JSProtoKey>(k)))
return false;
diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h
index 3fd2762f8..720f63e69 100644
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -121,6 +121,7 @@ class GlobalObject : public NativeObject
FOR_OF_PIC_CHAIN,
MODULE_RESOLVE_HOOK,
WINDOW_PROXY,
+ GLOBAL_THIS_RESOLVED,
/* Total reserved-slot count for global objects. */
RESERVED_SLOTS
@@ -171,6 +172,8 @@ class GlobalObject : public NativeObject
static bool initBuiltinConstructor(JSContext* cx, Handle<GlobalObject*> global,
JSProtoKey key, HandleObject ctor, HandleObject proto);
+ static bool maybeResolveGlobalThis(JSContext* cx, Handle<GlobalObject*> global, bool* resolved);
+
void setConstructor(JSProtoKey key, const Value& v) {
MOZ_ASSERT(key <= JSProto_LIMIT);
setSlot(APPLICATION_SLOTS + key, v);