Title: [233844] trunk
Revision
233844
Author
[email protected]
Date
2018-07-16 04:58:11 -0700 (Mon, 16 Jul 2018)

Log Message

[GLIB] Add API to evaluate code using a given object to store global symbols
https://bugs.webkit.org/show_bug.cgi?id=187639

Reviewed by Michael Catanzaro.

Source/_javascript_Core:

Add jsc_context_evaluate_in_object(). It returns a new object as an out parameter. Global symbols in the
evaluated script are added as properties to the new object instead of to the context global object. This is
similar to JS::Evaluate in spider monkey when a scopeChain parameter is passed, but JSC doesn't support using a
scope for assignments, so we have to create a new context and get its global object. This patch also updates
jsc_context_evaluate_with_source_uri() to receive the starting line number for consistency with the new
jsc_context_evaluate_in_object().

* API/glib/JSCContext.cpp:
(jsc_context_evaluate): Pass 0 as line number to jsc_context_evaluate_with_source_uri().
(evaluateScriptInContext): Helper function to evaluate a script in a JSGlobalContextRef.
(jsc_context_evaluate_with_source_uri): Use evaluateScriptInContext().
(jsc_context_evaluate_in_object): Create a new context and set the main context global object as extension
scope of it. Evaluate the script in the new context and get its global object to be returned as parameter.
* API/glib/JSCContext.h:
* API/glib/docs/jsc-glib-4.0-sections.txt:

Tools:

Add a new test case.

* TestWebKitAPI/Tests/_javascript_Core/glib/TestJSC.cpp:
(testJSCEvaluateInObject):
(testJSCExceptions):
(main):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/API/glib/JSCContext.cpp (233843 => 233844)


--- trunk/Source/_javascript_Core/API/glib/JSCContext.cpp	2018-07-16 06:43:45 UTC (rev 233843)
+++ trunk/Source/_javascript_Core/API/glib/JSCContext.cpp	2018-07-16 11:58:11 UTC (rev 233844)
@@ -28,6 +28,7 @@
 #include "JSCVirtualMachinePrivate.h"
 #include "JSCWrapperMap.h"
 #include "JSRetainPtr.h"
+#include "JSWithScope.h"
 #include "OpaqueJSString.h"
 #include <wtf/glib/GUniquePtr.h>
 #include <wtf/glib/WTFGType.h>
@@ -751,9 +752,16 @@
  */
 JSCValue* jsc_context_evaluate(JSCContext* context, const char* code, gssize length)
 {
-    return jsc_context_evaluate_with_source_uri(context, code, length, nullptr);
+    return jsc_context_evaluate_with_source_uri(context, code, length, nullptr, 0);
 }
 
+static JSValueRef evaluateScriptInContext(JSGlobalContextRef jsContext, String&& script, const char* uri, unsigned lineNumber, JSValueRef* exception)
+{
+    JSRetainPtr<JSStringRef> scriptJS(Adopt, OpaqueJSString::create(WTFMove(script)).leakRef());
+    JSRetainPtr<JSStringRef> sourceURI = uri ? adopt(JSStringCreateWithUTF8CString(uri)) : nullptr;
+    return JSEvaluateScript(jsContext, scriptJS.get(), nullptr, sourceURI.get(), lineNumber, exception);
+}
+
 /**
  * jsc_context_evaluate_with_source_uri:
  * @context: a #JSCContext
@@ -760,25 +768,21 @@
  * @code: a _javascript_ script to evaluate
  * @length: length of @code, or -1 if @code is a nul-terminated string
  * @uri: the source URI
+ * @line_number: the starting line number
  *
- * Evaluate @code in @context using @uri as the source URI. This is exactly the same as
- * jsc_context_evaluate() but @uri will be shown in exceptions. The source @uri doesn't
- * affect the behavior of the script.
+ * Evaluate @code in @context using @uri as the source URI. The @line_number is the starting line number
+ * in @uri; the value is one-based so the first line is 1. @uri and @line_number will be shown in exceptions and
+ * they don't affect the behavior of the script.
  *
  * Returns: (transfer full): a #JSCValue representing the last value generated by the script.
  */
-JSCValue* jsc_context_evaluate_with_source_uri(JSCContext* context, const char* code, gssize length, const char* uri)
+JSCValue* jsc_context_evaluate_with_source_uri(JSCContext* context, const char* code, gssize length, const char* uri, unsigned lineNumber)
 {
     g_return_val_if_fail(JSC_IS_CONTEXT(context), nullptr);
     g_return_val_if_fail(code, nullptr);
 
-    if (length < 0)
-        length = strlen(code);
-    auto script = String::fromUTF8(code, length);
-    JSRetainPtr<JSStringRef> scriptJS(Adopt, OpaqueJSString::create(WTFMove(script)).leakRef());
-    JSRetainPtr<JSStringRef> sourceURI = uri ? adopt(JSStringCreateWithUTF8CString(uri)) : nullptr;
     JSValueRef exception = nullptr;
-    JSValueRef result = JSEvaluateScript(context->priv->jsContext.get(), scriptJS.get(), nullptr, sourceURI.get(), 1, &exception);
+    JSValueRef result = evaluateScriptInContext(context->priv->jsContext.get(), String::fromUTF8(code, length < 0 ? strlen(code) : length), uri, lineNumber, &exception);
     if (jscContextHandleExceptionIfNeeded(context, exception))
         return jsc_value_new_undefined(context);
 
@@ -786,6 +790,44 @@
 }
 
 /**
+ * jsc_context_evaluate_in_object:
+ * @context: a #JSCContext
+ * @code: a _javascript_ script to evaluate
+ * @length: length of @code, or -1 if @code is a nul-terminated string
+ * @object_class: (nullable): a #JSCClass or %NULL to use the default
+ * @uri: the source URI
+ * @line_number: the starting line number
+ * @object: (out) (transfer full): return location for a #JSCValue.
+ *
+ * Evaluate @code and create an new object where symbols defined in @code will be added as properties,
+ * instead of being added to @context global object. The new object is returned as @object parameter.
+ * The @line_number is the starting line number in @uri; the value is one-based so the first line is 1.
+ * @uri and @line_number will be shown in exceptions and they don't affect the behavior of the script.
+ *
+ * Returns: (transfer full): a #JSCValue representing the last value generated by the script.
+ */
+JSCValue* jsc_context_evaluate_in_object(JSCContext* context, const char* code, gssize length, JSCClass* objectClass, const char* uri, unsigned lineNumber, JSCValue** object)
+{
+    g_return_val_if_fail(JSC_IS_CONTEXT(context), nullptr);
+    g_return_val_if_fail(code, nullptr);
+    g_return_val_if_fail(!objectClass || JSC_IS_CLASS(objectClass), nullptr);
+    g_return_val_if_fail(object && !*object, nullptr);
+
+    JSRetainPtr<JSGlobalContextRef> objectContext(Adopt, JSGlobalContextCreateInGroup(jscVirtualMachineGetContextGroup(context->priv->vm.get()), objectClass ? jscClassGetJSClass(objectClass) : nullptr));
+    JSC::ExecState* exec = toJS(objectContext.get());
+    auto* jsObject = exec->vmEntryGlobalObject();
+    jsObject->setGlobalScopeExtension(JSC::JSWithScope::create(exec->vm(), jsObject, jsObject->globalScope(), toJS(JSContextGetGlobalObject(context->priv->jsContext.get()))));
+    JSValueRef exception = nullptr;
+    JSValueRef result = evaluateScriptInContext(objectContext.get(), String::fromUTF8(code, length < 0 ? strlen(code) : length), uri, lineNumber, &exception);
+    if (jscContextHandleExceptionIfNeeded(context, exception))
+        return jsc_value_new_undefined(context);
+
+    *object = jscContextGetOrCreateValue(context, JSContextGetGlobalObject(objectContext.get())).leakRef();
+
+    return jscContextGetOrCreateValue(context, result).leakRef();
+}
+
+/**
  * jsc_context_get_global_object:
  * @context: a #JSCContext
  *

Modified: trunk/Source/_javascript_Core/API/glib/JSCContext.h (233843 => 233844)


--- trunk/Source/_javascript_Core/API/glib/JSCContext.h	2018-07-16 06:43:45 UTC (rev 233843)
+++ trunk/Source/_javascript_Core/API/glib/JSCContext.h	2018-07-16 11:58:11 UTC (rev 233844)
@@ -111,9 +111,19 @@
 jsc_context_evaluate_with_source_uri (JSCContext         *context,
                                       const char         *code,
                                       gssize              length,
-                                      const char         *uri);
+                                      const char         *uri,
+                                      guint               line_number);
 
 JSC_API JSCValue *
+jsc_context_evaluate_in_object       (JSCContext         *context,
+                                      const char         *code,
+                                      gssize              length,
+                                      JSCClass           *object_class,
+                                      const char         *uri,
+                                      guint               line_number,
+                                      JSCValue          **object);
+
+JSC_API JSCValue *
 jsc_context_get_global_object        (JSCContext         *context);
 
 JSC_API void

Modified: trunk/Source/_javascript_Core/API/glib/docs/jsc-glib-4.0-sections.txt (233843 => 233844)


--- trunk/Source/_javascript_Core/API/glib/docs/jsc-glib-4.0-sections.txt	2018-07-16 06:43:45 UTC (rev 233843)
+++ trunk/Source/_javascript_Core/API/glib/docs/jsc-glib-4.0-sections.txt	2018-07-16 11:58:11 UTC (rev 233844)
@@ -38,6 +38,7 @@
 jsc_context_get_current
 jsc_context_evaluate
 jsc_context_evaluate_with_source_uri
+jsc_context_evaluate_in_object
 jsc_context_get_global_object
 jsc_context_set_value
 jsc_context_get_value

Modified: trunk/Source/_javascript_Core/ChangeLog (233843 => 233844)


--- trunk/Source/_javascript_Core/ChangeLog	2018-07-16 06:43:45 UTC (rev 233843)
+++ trunk/Source/_javascript_Core/ChangeLog	2018-07-16 11:58:11 UTC (rev 233844)
@@ -1,3 +1,26 @@
+2018-07-15  Carlos Garcia Campos  <[email protected]>
+
+        [GLIB] Add API to evaluate code using a given object to store global symbols
+        https://bugs.webkit.org/show_bug.cgi?id=187639
+
+        Reviewed by Michael Catanzaro.
+
+        Add jsc_context_evaluate_in_object(). It returns a new object as an out parameter. Global symbols in the
+        evaluated script are added as properties to the new object instead of to the context global object. This is
+        similar to JS::Evaluate in spider monkey when a scopeChain parameter is passed, but JSC doesn't support using a
+        scope for assignments, so we have to create a new context and get its global object. This patch also updates
+        jsc_context_evaluate_with_source_uri() to receive the starting line number for consistency with the new
+        jsc_context_evaluate_in_object().
+
+        * API/glib/JSCContext.cpp:
+        (jsc_context_evaluate): Pass 0 as line number to jsc_context_evaluate_with_source_uri().
+        (evaluateScriptInContext): Helper function to evaluate a script in a JSGlobalContextRef.
+        (jsc_context_evaluate_with_source_uri): Use evaluateScriptInContext().
+        (jsc_context_evaluate_in_object): Create a new context and set the main context global object as extension
+        scope of it. Evaluate the script in the new context and get its global object to be returned as parameter.
+        * API/glib/JSCContext.h:
+        * API/glib/docs/jsc-glib-4.0-sections.txt:
+
 2018-07-13  Yusuke Suzuki  <[email protected]>
 
         [32bit JSC tests]  stress/cow-convert-double-to-contiguous.js and stress/cow-convert-int32-to-contiguous.js are failing

Modified: trunk/Tools/ChangeLog (233843 => 233844)


--- trunk/Tools/ChangeLog	2018-07-16 06:43:45 UTC (rev 233843)
+++ trunk/Tools/ChangeLog	2018-07-16 11:58:11 UTC (rev 233844)
@@ -1,3 +1,17 @@
+2018-07-15  Carlos Garcia Campos  <[email protected]>
+
+        [GLIB] Add API to evaluate code using a given object to store global symbols
+        https://bugs.webkit.org/show_bug.cgi?id=187639
+
+        Reviewed by Michael Catanzaro.
+
+        Add a new test case.
+
+        * TestWebKitAPI/Tests/_javascript_Core/glib/TestJSC.cpp:
+        (testJSCEvaluateInObject):
+        (testJSCExceptions):
+        (main):
+
 2018-07-15  Zan Dobersek  <[email protected]>
 
         [webkitpy] run-web-platform-tests should allow specifying custom WPT metadata directories

Modified: trunk/Tools/TestWebKitAPI/Tests/_javascript_Core/glib/TestJSC.cpp (233843 => 233844)


--- trunk/Tools/TestWebKitAPI/Tests/_javascript_Core/glib/TestJSC.cpp	2018-07-16 06:43:45 UTC (rev 233843)
+++ trunk/Tools/TestWebKitAPI/Tests/_javascript_Core/glib/TestJSC.cpp	2018-07-16 11:58:11 UTC (rev 233844)
@@ -607,6 +607,118 @@
     g_assert_true(window2.get() == globalObject.get());
 }
 
+static void testJSCEvaluateInObject()
+{
+    LeakChecker checker;
+    GRefPtr<JSCContext> context = adoptGRef(jsc_context_new());
+    checker.watch(context.get());
+    ExceptionHandler exceptionHandler(context.get());
+
+    GRefPtr<JSCValue> result = adoptGRef(jsc_context_evaluate(context.get(), "g = 54; function foo() { return 42; }", -1));
+    checker.watch(result.get());
+
+    GRefPtr<JSCValue> globalObject = adoptGRef(jsc_context_get_global_object(context.get()));
+    checker.watch(globalObject.get());
+
+    GRefPtr<JSCValue> rootFoo = adoptGRef(jsc_value_object_get_property(globalObject.get(), "foo"));
+    checker.watch(rootFoo.get());
+    g_assert(jsc_value_is_function(rootFoo.get()));
+    result = adoptGRef(jsc_value_function_call(rootFoo.get(), G_TYPE_NONE));
+    checker.watch(result.get());
+    g_assert_true(jsc_value_is_number(result.get()));
+    g_assert_cmpint(jsc_value_to_int32(result.get()), ==, 42);
+    GRefPtr<JSCValue> value = adoptGRef(jsc_context_evaluate(context.get(), "foo()", -1));
+    checker.watch(value.get());
+    g_assert_true(value.get() == result.get());
+
+    GRefPtr<JSCValue> module;
+    result = adoptGRef(jsc_context_evaluate_in_object(context.get(), "function bar() { return g; }", -1, nullptr, nullptr, 1, &module.outPtr()));
+    checker.watch(result.get());
+    checker.watch(module.get());
+    g_assert_true(JSC_IS_VALUE(module.get()));
+    g_assert_true(jsc_value_is_object(module.get()));
+    GUniquePtr<char> valueString(jsc_value_to_string(module.get()));
+    g_assert_cmpstr(valueString.get(), ==, "[object GlobalObject]");
+    jsc_context_set_value(context.get(), "module", module.get());
+
+    GRefPtr<JSCValue> bar = adoptGRef(jsc_value_object_get_property(module.get(), "bar"));
+    checker.watch(bar.get());
+    g_assert_true(jsc_value_is_function(bar.get()));
+    result = adoptGRef(jsc_value_function_call(bar.get(), G_TYPE_NONE));
+    checker.watch(result.get());
+    g_assert_true(jsc_value_is_number(result.get()));
+    g_assert_cmpint(jsc_value_to_int32(result.get()), ==, 54);
+    value = adoptGRef(jsc_context_evaluate(context.get(), "module.bar()", -1));
+    checker.watch(value.get());
+    g_assert_true(value.get() == result.get());
+
+    bar = adoptGRef(jsc_context_get_value(context.get(), "bar"));
+    checker.watch(bar.get());
+    g_assert_true(jsc_value_is_undefined(bar.get()));
+
+    JSCClass* jscClass = jsc_context_register_class(context.get(), "Module", nullptr, nullptr, nullptr);
+    checker.watch(jscClass);
+    GRefPtr<JSCValue> moduleWithClass;
+    result = adoptGRef(jsc_context_evaluate_in_object(context.get(), "function baz() { return foo(); }", -1, jscClass, nullptr, 1, &moduleWithClass.outPtr()));
+    checker.watch(result.get());
+    checker.watch(moduleWithClass.get());
+    g_assert_true(JSC_IS_VALUE(moduleWithClass.get()));
+    g_assert_true(jsc_value_is_object(moduleWithClass.get()));
+    valueString.reset(jsc_value_to_string(moduleWithClass.get()));
+    g_assert_cmpstr(valueString.get(), ==, "[object Module]");
+    jsc_context_set_value(context.get(), "moduleWithClass", moduleWithClass.get());
+
+    GRefPtr<JSCValue> baz = adoptGRef(jsc_value_object_get_property(moduleWithClass.get(), "baz"));
+    checker.watch(baz.get());
+    g_assert_true(jsc_value_is_function(baz.get()));
+    result = adoptGRef(jsc_value_function_call(baz.get(), G_TYPE_NONE));
+    checker.watch(result.get());
+    g_assert_true(jsc_value_is_number(result.get()));
+    g_assert_cmpint(jsc_value_to_int32(result.get()), ==, 42);
+    value = adoptGRef(jsc_context_evaluate(context.get(), "moduleWithClass.baz()", -1));
+    checker.watch(value.get());
+    g_assert_true(value.get() == result.get());
+
+    bar = adoptGRef(jsc_value_object_get_property(moduleWithClass.get(), "bar"));
+    checker.watch(bar.get());
+    g_assert_true(jsc_value_is_undefined(bar.get()));
+
+    baz = adoptGRef(jsc_value_object_get_property(module.get(), "baz"));
+    checker.watch(baz.get());
+    g_assert_true(jsc_value_is_undefined(baz.get()));
+
+    baz = adoptGRef(jsc_context_get_value(context.get(), "baz"));
+    checker.watch(baz.get());
+    g_assert_true(jsc_value_is_undefined(baz.get()));
+
+    GRefPtr<JSCValue> jsNamespace = adoptGRef(jsc_value_new_object(context.get(), nullptr, nullptr));
+    checker.watch(jsNamespace.get());
+    jsc_context_set_value(context.get(), "wk", jsNamespace.get());
+
+    GRefPtr<JSCValue> moduleInWk;
+    result = adoptGRef(jsc_context_evaluate_in_object(context.get(), "function bar() { return g; }", -1, nullptr, nullptr, 1, &moduleInWk.outPtr()));
+    checker.watch(result.get());
+    checker.watch(moduleInWk.get());
+    g_assert_true(JSC_IS_VALUE(moduleInWk.get()));
+    g_assert_true(jsc_value_is_object(moduleInWk.get()));
+    jsc_value_object_set_property(jsNamespace.get(), "moduleInWk", moduleInWk.get());
+
+    bar = adoptGRef(jsc_value_object_get_property(moduleInWk.get(), "bar"));
+    checker.watch(bar.get());
+    g_assert_true(jsc_value_is_function(bar.get()));
+    result = adoptGRef(jsc_value_function_call(bar.get(), G_TYPE_NONE));
+    checker.watch(result.get());
+    g_assert_true(jsc_value_is_number(result.get()));
+    g_assert_cmpint(jsc_value_to_int32(result.get()), ==, 54);
+    value = adoptGRef(jsc_context_evaluate(context.get(), "wk.moduleInWk.bar()", -1));
+    checker.watch(value.get());
+    g_assert_true(value.get() == result.get());
+
+    moduleInWk = adoptGRef(jsc_context_get_value(context.get(), "moduleInWk"));
+    checker.watch(moduleInWk.get());
+    g_assert_true(jsc_value_is_undefined(moduleInWk.get()));
+}
+
 static int foo(int n)
 {
     return n * 2;
@@ -2334,7 +2446,7 @@
         checker.watch(context.get());
         g_assert_false(jsc_context_get_exception(context.get()));
 
-        GRefPtr<JSCValue> result = adoptGRef(jsc_context_evaluate_with_source_uri(context.get(), "foo", -1, "file:///foo/script.js"));
+        GRefPtr<JSCValue> result = adoptGRef(jsc_context_evaluate_with_source_uri(context.get(), "foo", -1, "file:///foo/script.js", 3));
         checker.watch(result.get());
 
         g_assert_true(jsc_value_is_undefined(result.get()));
@@ -2342,6 +2454,7 @@
         g_assert_true(JSC_IS_EXCEPTION(exception));
         checker.watch(exception);
         g_assert_cmpstr(jsc_exception_get_source_uri(exception), ==, "file:///foo/script.js");
+        g_assert_cmpuint(jsc_exception_get_line_number(exception), ==, 3);
 
         jsc_context_clear_exception(context.get());
         g_assert_null(jsc_context_get_exception(context.get()));
@@ -2884,6 +2997,7 @@
     g_test_add_func("/jsc/basic", testJSCBasic);
     g_test_add_func("/jsc/types", testJSCTypes);
     g_test_add_func("/jsc/global-object", testJSCGlobalObject);
+    g_test_add_func("/jsc/evaluate-in-object", testJSCEvaluateInObject);
     g_test_add_func("/jsc/function", testJSCFunction);
     g_test_add_func("/jsc/object", testJSCObject);
     g_test_add_func("/jsc/class", testJSCClass);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to