Bug 784400 - Give self-hosted code access to standard builtins. r=luke
authorTill Schneidereit <tschneidereit@gmail.com>
Tue, 28 Aug 2012 04:58:00 +0200
changeset 110282 c9e4a0971222b391c811e36816333b9155ccc989
parent 110281 dc34d5773895741ec71f1970fbb4b1236b162917
child 110283 a821bac3baa965771fd631e2a0f4d0315cb357e5
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersluke
bugs784400
milestone19.0a1
Bug 784400 - Give self-hosted code access to standard builtins. r=luke
js/src/jsapi.cpp
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jsfun.cpp
js/src/vm/GlobalObject.cpp
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -4996,16 +4996,26 @@ JS_DefineFunctions(JSContext *cx, JSObje
 
             /*
              * As jsapi.h notes, fs must point to storage that lives as long
              * as fun->object lives.
              */
             fun->setExtendedSlot(0, PrivateValue(fs));
         }
 
+        /*
+         * During creation of the self-hosting global, we ignore all
+         * self-hosted functions, as that means we're currently setting up
+         * the global object that that the self-hosted code is then compiled
+         * in. Self-hosted functions can access each other via their names,
+         * but not via the builtin classes they get installed into.
+         */
+        if (fs->selfHostedName && cx->runtime->isSelfHostedGlobal(cx->global()))
+            return JS_TRUE;
+
         fun = js_DefineFunction(cx, obj, id, fs->call.op, fs->nargs, flags, fs->selfHostedName);
         if (!fun)
             return JS_FALSE;
         if (fs->call.info)
             fun->setJitInfo(fs->call.info);
     }
     return JS_TRUE;
 }
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -237,43 +237,45 @@ JSRuntime::createJaegerRuntime(JSContext
 }
 #endif
 
 static void
 selfHosting_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
 {
     PrintError(cx, stderr, message, report, true);
 }
+
 static JSClass self_hosting_global_class = {
     "self-hosting-global", JSCLASS_GLOBAL_FLAGS,
     JS_PropertyStub,  JS_PropertyStub,
     JS_PropertyStub,  JS_StrictPropertyStub,
     JS_EnumerateStub, JS_ResolveStub,
     JS_ConvertStub,   NULL
 };
+
 bool
 JSRuntime::initSelfHosting(JSContext *cx)
 {
     JS_ASSERT(!selfHostedGlobal_);
     RootedObject savedGlobal(cx, JS_GetGlobalObject(cx));
     if (!(selfHostedGlobal_ = JS_NewGlobalObject(cx, &self_hosting_global_class, NULL)))
         return false;
     JS_SetGlobalObject(cx, selfHostedGlobal_);
-    RootedObject shg(cx, selfHostedGlobal_);
 
     CompileOptions options(cx);
     options.setFileAndLine("self-hosted", 1);
     options.setSelfHostingMode(true);
 
     /*
      * Set a temporary error reporter printing to stderr because it is too
      * early in the startup process for any other reporter to be registered
      * and we don't want errors in self-hosted code to be silently swallowed.
      */
     JSErrorReporter oldReporter = JS_SetErrorReporter(cx, selfHosting_ErrorReporter);
+    RootedObject shg(cx, selfHostedGlobal_);
     Value rv;
     bool ok;
 
     char *filename = getenv("MOZ_SELFHOSTEDJS");
     if (filename) {
         RootedScript script(cx, Compile(cx, shg, options, filename));
         if (script)
             ok = Execute(cx, script, *shg.get(), &rv);
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -466,16 +466,19 @@ struct JSRuntime : js::RuntimeFriendFiel
     js::mjit::JaegerRuntime &jaegerRuntime() {
         JS_ASSERT(hasJaegerRuntime());
         return *jaegerRuntime_;
     }
 #endif
 
     bool initSelfHosting(JSContext *cx);
     void markSelfHostedGlobal(JSTracer *trc);
+    bool isSelfHostedGlobal(js::HandleObject global) {
+        return global == selfHostedGlobal_;
+    }
     JSFunction *getSelfHostedFunction(JSContext *cx, const char *name);
     bool cloneSelfHostedValueById(JSContext *cx, js::HandleId id, js::HandleObject holder,
                                   js::MutableHandleValue vp);
 
     /* Base address of the native stack for the current thread. */
     uintptr_t           nativeStackBase;
 
     /* The native stack size limit that runtime should not exceed. */
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -1563,16 +1563,17 @@ js_DefineFunction(JSContext *cx, HandleO
     if (native) {
         JS_ASSERT(!selfHostedName);
         RootedAtom atom(cx, JSID_IS_ATOM(id) ? JSID_TO_ATOM(id) : NULL);
         fun = js_NewFunction(cx, NullPtr(), native, nargs,
                              attrs & (JSFUN_FLAGS_MASK),
                              obj, atom, kind);
     } else {
         JS_ASSERT(attrs & JSFUN_INTERPRETED);
+        JS_ASSERT(!cx->runtime->isSelfHostedGlobal(cx->global()));
         fun = cx->runtime->getSelfHostedFunction(cx, selfHostedName);
         fun->initAtom(JSID_TO_ATOM(id));
     }
     if (!fun)
         return NULL;
 
     RootedValue funVal(cx, ObjectValue(*fun));
     if (!JSObject::defineGeneric(cx, obj, id, funVal, gop, sop, attrs & ~JSFUN_FLAGS_MASK))
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -451,16 +451,24 @@ GlobalObject::initFunctionAndObjectClass
     self->setThrowTypeError(throwTypeError);
 
     RootedObject intrinsicsHolder(cx, JS_NewObject(cx, NULL, NULL, self));
     if (!intrinsicsHolder)
         return NULL;
     self->setIntrinsicsHolder(intrinsicsHolder);
     if (!JS_DefineFunctions(cx, intrinsicsHolder, intrinsic_functions))
         return NULL;
+    /* Define a property 'global' with the current global as its value. */
+    RootedValue global(cx, OBJECT_TO_JSVAL(self));
+    if (!JSObject::defineProperty(cx, intrinsicsHolder, cx->names().global,
+                                  global, JS_PropertyStub, JS_StrictPropertyStub,
+                                  JSPROP_PERMANENT | JSPROP_READONLY))
+    {
+        return NULL;
+    }
 
     /*
      * The global object should have |Object.prototype| as its [[Prototype]].
      * Eventually we'd like to have standard classes be there from the start,
      * and thus we would know we were always setting what had previously been a
      * null [[Prototype]], but right now some code assumes it can set the
      * [[Prototype]] before standard classes have been initialized.  For now,
      * only set the [[Prototype]] if it hasn't already been set.