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);