Bug 1083648 - Part 2: Add JSAPI for compiling a function with a given scope chain (represented as a vector of JSObjects). r=shu, a=lsblakk
authorBoris Zbarsky <bzbarsky@mit.edu>
Sat, 25 Oct 2014 00:50:28 -0400
changeset 233505 860511ae5a45b5865fb6e02fb8ff2bf911b6aa1f
parent 233504 2cb21f30fa3d345a3c0074309a417eb8c702b3ca
child 233506 8aa88cc51b8646463201879028f068561a028481
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersshu, lsblakk
bugs1083648
milestone35.0a2
Bug 1083648 - Part 2: Add JSAPI for compiling a function with a given scope chain (represented as a vector of JSObjects). r=shu, a=lsblakk
js/src/jsapi.cpp
js/src/jsapi.h
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -71,16 +71,17 @@
 #include "vm/Debugger.h"
 #include "vm/ErrorObject.h"
 #include "vm/HelperThreads.h"
 #include "vm/Interpreter.h"
 #include "vm/NumericConversions.h"
 #include "vm/RegExpStatics.h"
 #include "vm/Runtime.h"
 #include "vm/SavedStacks.h"
+#include "vm/ScopeObject.h"
 #include "vm/Shape.h"
 #include "vm/StopIterationObject.h"
 #include "vm/StringBuffer.h"
 #include "vm/Symbol.h"
 #include "vm/TypedArrayCommon.h"
 #include "vm/WeakMapObject.h"
 #include "vm/WrapperObject.h"
 #include "vm/Xdr.h"
@@ -3910,16 +3911,53 @@ JS::GetSelfHostedFunction(JSContext *cx,
     if (!shName)
         return nullptr;
     RootedValue funVal(cx);
     if (!cx->global()->getSelfHostedFunction(cx, shName, name, nargs, &funVal))
         return nullptr;
     return &funVal.toObject().as<JSFunction>();
 }
 
+static bool
+CreateScopeObjectsForScopeChain(JSContext *cx, AutoObjectVector &scopeChain,
+                                MutableHandleObject dynamicScopeObj,
+                                MutableHandleObject staticScopeObj)
+{
+#ifdef DEBUG
+    for (size_t i = 0; i < scopeChain.length(); ++i) {
+        assertSameCompartment(cx, scopeChain[i]);
+        MOZ_ASSERT(!scopeChain[i]->is<GlobalObject>());
+    }
+#endif
+
+    // Construct With object wrappers for the things on this scope
+    // chain and use the result as the thing to scope the function to.
+    Rooted<StaticWithObject*> staticWith(cx);
+    RootedObject staticEnclosingScope(cx);
+    Rooted<DynamicWithObject*> dynamicWith(cx);
+    RootedObject dynamicEnclosingScope(cx, cx->global());
+    for (size_t i = scopeChain.length(); i > 0; ) {
+        staticWith = StaticWithObject::create(cx);
+        if (!staticWith)
+            return false;
+        staticWith->initEnclosingNestedScope(staticEnclosingScope);
+        staticEnclosingScope = staticWith;
+
+        dynamicWith = DynamicWithObject::create(cx, scopeChain[--i],
+                                                dynamicEnclosingScope, staticWith);
+        if (!dynamicWith)
+            return false;
+        dynamicEnclosingScope = dynamicWith;
+    }
+
+    dynamicScopeObj.set(dynamicEnclosingScope);
+    staticScopeObj.set(staticEnclosingScope);
+    return true;
+}
+
 JS_PUBLIC_API(JSObject *)
 JS_CloneFunctionObject(JSContext *cx, HandleObject funobj, HandleObject parentArg)
 {
     RootedObject parent(cx, parentArg);
 
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, parent);
@@ -4691,16 +4729,31 @@ JS::CompileFunction(JSContext *cx, Handl
         chars.reset(InflateString(cx, bytes, &length));
     if (!chars)
         return false;
 
     return CompileFunction(cx, obj, options, name, nargs, argnames, chars.get(), length, fun);
 }
 
 JS_PUBLIC_API(bool)
+JS::CompileFunction(JSContext *cx, AutoObjectVector &scopeChain,
+                    const ReadOnlyCompileOptions &options,
+                    const char *name, unsigned nargs, const char *const *argnames,
+                    const char16_t *chars, size_t length, MutableHandleFunction fun)
+{
+    RootedObject dynamicScopeObj(cx);
+    RootedObject staticScopeObj(cx);
+    if (!CreateScopeObjectsForScopeChain(cx, scopeChain, &dynamicScopeObj, &staticScopeObj))
+        return false;
+
+    return JS::CompileFunction(cx, dynamicScopeObj, options, name, nargs,
+                               argnames, chars, length, fun, staticScopeObj);
+}
+
+JS_PUBLIC_API(bool)
 JS_CompileUCFunction(JSContext *cx, JS::HandleObject obj, const char *name,
                      unsigned nargs, const char *const *argnames,
                      const char16_t *chars, size_t length,
                      const CompileOptions &options, MutableHandleFunction fun)
 {
     return CompileFunction(cx, obj, options, name, nargs, argnames, chars, length, fun);
 }
 
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -3890,16 +3890,29 @@ CompileFunction(JSContext *cx, JS::Handl
                 const char *bytes, size_t length, JS::MutableHandleFunction fun);
 
 extern JS_PUBLIC_API(bool)
 CompileFunction(JSContext *cx, JS::HandleObject obj, const ReadOnlyCompileOptions &options,
                 const char *name, unsigned nargs, const char *const *argnames,
                 const char16_t *chars, size_t length, JS::MutableHandleFunction fun,
                 HandleObject enclosingStaticScope = NullPtr());
 
+/**
+ * Compile a function with scopeChain plus the global as its scope chain.
+ * scopeChain must contain objects in the current compartment of cx.  The actual
+ * scope chain used for the function will consist of With wrappers for those
+ * objects, followed by the current global of the compartment cx is in.  This
+ * global must not be explicitly included in the scope chain.
+ */
+extern JS_PUBLIC_API(bool)
+CompileFunction(JSContext *cx, AutoObjectVector &scopeChain,
+                const ReadOnlyCompileOptions &options,
+                const char *name, unsigned nargs, const char *const *argnames,
+                const char16_t *chars, size_t length, JS::MutableHandleFunction fun);
+
 } /* namespace JS */
 
 extern JS_PUBLIC_API(JSString *)
 JS_DecompileScript(JSContext *cx, JS::Handle<JSScript*> script, const char *name, unsigned indent);
 
 /*
  * API extension: OR this into indent to avoid pretty-printing the decompiled
  * source resulting from JS_DecompileFunction{,Body}.