summaryrefslogtreecommitdiffstats
path: root/js/src/vm/GlobalObject.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/vm/GlobalObject.cpp')
-rw-r--r--js/src/vm/GlobalObject.cpp32
1 files changed, 32 insertions, 0 deletions
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;