From 98133d220660b97724f52eded17239100dc10195 Mon Sep 17 00:00:00 2001 From: Seonghyun Kim Date: Wed, 18 Oct 2023 16:26:05 +0900 Subject: [PATCH] Update Java API * Check type on as{*} functions * Add Context as argument for every callback * Add Pending job option into evalScript function * Move few create functions into child class * Update build files Signed-off-by: Seonghyun Kim --- build/android/.idea/misc.xml | 3 +- .../lwe/escargot/shell/MainActivity.java | 18 +- build/android/escargot/build.gradle | 1 - build/android/escargot/consumer-rules.pro | 1 + build/android/escargot/proguard-rules.pro | 1 + .../samsung/lwe/escargot/EscargotTest.java | 236 +++++++++++++----- .../escargot/src/main/cpp/CMakeLists.txt | 2 +- .../escargot/src/main/cpp/escargot.cpp | 160 ++++++++---- .../java/com/samsung/lwe/escargot/Bridge.java | 3 +- .../com/samsung/lwe/escargot/Evaluator.java | 30 ++- .../escargot/JavaScriptFunctionObject.java | 1 + .../JavaScriptJavaCallbackFunctionObject.java | 3 +- .../lwe/escargot/JavaScriptString.java | 1 + .../lwe/escargot/JavaScriptSymbol.java | 2 + .../samsung/lwe/escargot/JavaScriptValue.java | 5 - build/target.cmake | 2 +- src/api/EscargotPublic.cpp | 5 + src/api/EscargotPublic.h | 3 + 18 files changed, 333 insertions(+), 144 deletions(-) diff --git a/build/android/.idea/misc.xml b/build/android/.idea/misc.xml index f1044879e..8978d23db 100644 --- a/build/android/.idea/misc.xml +++ b/build/android/.idea/misc.xml @@ -1,7 +1,6 @@ - - + diff --git a/build/android/app/src/main/java/com/samsung/lwe/escargot/shell/MainActivity.java b/build/android/app/src/main/java/com/samsung/lwe/escargot/shell/MainActivity.java index cac4cbd0c..3b4fc4c9c 100644 --- a/build/android/app/src/main/java/com/samsung/lwe/escargot/shell/MainActivity.java +++ b/build/android/app/src/main/java/com/samsung/lwe/escargot/shell/MainActivity.java @@ -82,9 +82,9 @@ private void run() { Context finalContext = context; - context.getGlobalObject().set(context, JavaScriptValue.create("print"), JavaScriptJavaCallbackFunctionObject.create(context, "print", 1, false, new JavaScriptJavaCallbackFunctionObject.Callback() { + context.getGlobalObject().set(context, JavaScriptString.create("print"), JavaScriptJavaCallbackFunctionObject.create(context, "print", 1, false, new JavaScriptJavaCallbackFunctionObject.Callback() { @Override - public Optional callback(JavaScriptValue javaScriptValue, JavaScriptValue[] javaScriptValues) { + public Optional callback(Context context, JavaScriptValue javaScriptValue, JavaScriptValue[] javaScriptValues) { StringBuffer sb = new StringBuffer(); sb.append(str); sb.append('\n'); @@ -118,9 +118,9 @@ public void run() { } })); - context.getGlobalObject().set(context, JavaScriptValue.create("load"), JavaScriptJavaCallbackFunctionObject.create(context, "run", 1, false, new JavaScriptJavaCallbackFunctionObject.Callback() { + context.getGlobalObject().set(context, JavaScriptString.create("load"), JavaScriptJavaCallbackFunctionObject.create(context, "run", 1, false, new JavaScriptJavaCallbackFunctionObject.Callback() { @Override - public Optional callback(JavaScriptValue javaScriptValue, JavaScriptValue[] javaScriptValues) { + public Optional callback(Context context, JavaScriptValue javaScriptValue, JavaScriptValue[] javaScriptValues) { Optional s = javaScriptValues[0].toString(finalContext); if (s.isPresent()) { try { @@ -137,9 +137,9 @@ public Optional callback(JavaScriptValue javaScriptValue, JavaS } })); - context.getGlobalObject().set(context, JavaScriptValue.create("run"), JavaScriptJavaCallbackFunctionObject.create(context, "run", 1, false, new JavaScriptJavaCallbackFunctionObject.Callback() { + context.getGlobalObject().set(context, JavaScriptString.create("run"), JavaScriptJavaCallbackFunctionObject.create(context, "run", 1, false, new JavaScriptJavaCallbackFunctionObject.Callback() { @Override - public Optional callback(JavaScriptValue javaScriptValue, JavaScriptValue[] javaScriptValues) { + public Optional callback(Context context, JavaScriptValue javaScriptValue, JavaScriptValue[] javaScriptValues) { long sm = System.currentTimeMillis(); Optional s = javaScriptValues[0].toString(finalContext); if (s.isPresent()) { @@ -149,16 +149,16 @@ public Optional callback(JavaScriptValue javaScriptValue, JavaS } })); - context.getGlobalObject().set(context, JavaScriptValue.create("read"), JavaScriptJavaCallbackFunctionObject.create(context, "read", 1, false, new JavaScriptJavaCallbackFunctionObject.Callback() { + context.getGlobalObject().set(context, JavaScriptString.create("read"), JavaScriptJavaCallbackFunctionObject.create(context, "read", 1, false, new JavaScriptJavaCallbackFunctionObject.Callback() { @Override - public Optional callback(JavaScriptValue javaScriptValue, JavaScriptValue[] javaScriptValues) { + public Optional callback(Context context, JavaScriptValue javaScriptValue, JavaScriptValue[] javaScriptValues) { Optional s = javaScriptValues[0].toString(finalContext); if (s.isPresent()) { FileReader in = null; try { byte[] chars = Files.readAllBytes(Paths.get(s.get().toJavaString())); String fileContent = new String(chars); - return Optional.of(JavaScriptValue.create(fileContent)); + return Optional.of(JavaScriptString.create(fileContent)); } catch (Exception ex) { return Optional.empty(); diff --git a/build/android/escargot/build.gradle b/build/android/escargot/build.gradle index e57d66daa..476a71420 100644 --- a/build/android/escargot/build.gradle +++ b/build/android/escargot/build.gradle @@ -178,7 +178,6 @@ task sourcesJar(type: Jar) { task javadoc(type: Javadoc) { source = android.sourceSets.main.java.sourceFiles - classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) android.libraryVariants.all { variant -> if (variant.name == 'release') { owner.classpath += variant.javaCompileProvider.get().classpath diff --git a/build/android/escargot/consumer-rules.pro b/build/android/escargot/consumer-rules.pro index 7a00f6ca9..43d6759e7 100644 --- a/build/android/escargot/consumer-rules.pro +++ b/build/android/escargot/consumer-rules.pro @@ -1 +1,2 @@ -keep class com.samsung.lwe.escargot.* { *; } +-keep enum com.samsung.lwe.escargot.* { *; } diff --git a/build/android/escargot/proguard-rules.pro b/build/android/escargot/proguard-rules.pro index 3a2103d2b..5dc7597b2 100644 --- a/build/android/escargot/proguard-rules.pro +++ b/build/android/escargot/proguard-rules.pro @@ -21,3 +21,4 @@ #-renamesourcefileattribute SourceFile -keep class com.samsung.lwe.escargot.* { *; } +-keep enum com.samsung.lwe.escargot.* { *; } diff --git a/build/android/escargot/src/androidTest/java/com/samsung/lwe/escargot/EscargotTest.java b/build/android/escargot/src/androidTest/java/com/samsung/lwe/escargot/EscargotTest.java index 8394adef7..743393888 100644 --- a/build/android/escargot/src/androidTest/java/com/samsung/lwe/escargot/EscargotTest.java +++ b/build/android/escargot/src/androidTest/java/com/samsung/lwe/escargot/EscargotTest.java @@ -11,6 +11,9 @@ import org.junit.runner.RunWith; import java.io.ByteArrayInputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; import java.util.Optional; @RunWith(AndroidJUnit4.class) @@ -52,7 +55,7 @@ public void initTest() { for (int i = 0; i < 30000; i++) { // alloc many trash objects for testing memory management - JavaScriptValue.create("asdf"); + JavaScriptString.create("asdf"); } context = null; @@ -126,8 +129,8 @@ public void simpleScriptRunTest() { Evaluator.evalScript(context, null, null, true); printNegativeTC("Evaluator.evalScript with null 2"); - JavaScriptValue vv = JavaScriptValue.create(System.getProperty("java.version")); - context.getGlobalObject().set(context, JavaScriptValue.create("ddd"), vv); + JavaScriptValue vv = JavaScriptString.create(System.getProperty("java.version")); + context.getGlobalObject().set(context, JavaScriptString.create("ddd"), vv); Evaluator.evalScript(context, "'java.version' + ddd", null, true); printPositiveTC("Evaluator.evalScript test 1"); @@ -177,13 +180,13 @@ public void simpleOneByOneThreadingTest() { assertEquals(JavaScriptValue.create(123).toString(context).get().toJavaString(), "123"); assertEquals(JavaScriptValue.create(123).toBoolean(context).get(), true); - JavaScriptValue vv = JavaScriptValue.create(System.getProperty("java.version")); - context.getGlobalObject().set(context, JavaScriptValue.create("ddd"), vv); + JavaScriptValue vv = JavaScriptString.create(System.getProperty("java.version")); + context.getGlobalObject().set(context, JavaScriptString.create("ddd"), vv); Evaluator.evalScript(context, "'java.version' + ddd", "invalid", true); for (int i = 0; i < 30000; i++) { // alloc many trash objects for testing memory management - JavaScriptValue.create("asdf"); + JavaScriptString.create("asdf"); } context = null; @@ -207,11 +210,11 @@ public void simpleOneByOneThreadingTest() { Context context = Context.create(vmInstance); String testString = "[1, 2, 3]"; - JavaScriptValue result = context.getGlobalObject().jsonParse(context, JavaScriptValue.create(testString)).get(); + JavaScriptValue result = context.getGlobalObject().jsonParse(context, JavaScriptString.create(testString)).get(); assertTrue(result.isArrayObject()); - JavaScriptValue vv = JavaScriptValue.create(System.getProperty("java.version")); - context.getGlobalObject().set(context, JavaScriptValue.create("ddd"), vv); + JavaScriptValue vv = JavaScriptString.create(System.getProperty("java.version")); + context.getGlobalObject().set(context, JavaScriptString.create("ddd"), vv); Evaluator.evalScript(context, "'java.version' + ddd", "invalid", true); context = null; @@ -245,13 +248,13 @@ public void simpleMultiThreadingTest() { assertEquals(JavaScriptValue.create(123).toString(context).get().toJavaString(), "123"); assertEquals(JavaScriptValue.create(123).toBoolean(context).get(), true); - JavaScriptValue vv = JavaScriptValue.create(System.getProperty("java.version")); - context.getGlobalObject().set(context, JavaScriptValue.create("ddd"), vv); + JavaScriptValue vv = JavaScriptString.create(System.getProperty("java.version")); + context.getGlobalObject().set(context, JavaScriptString.create("ddd"), vv); Evaluator.evalScript(context, "'java.version' + ddd", "invalid", true); for (int i = 0; i < 999999; i++) { // alloc many trash objects for testing memory management - JavaScriptValue.create("asdf"); + JavaScriptString.create("asdf"); } context = null; @@ -269,16 +272,16 @@ public void simpleMultiThreadingTest() { Context context = Context.create(vmInstance); String testString = "[1, 2, 3]"; - JavaScriptValue result = context.getGlobalObject().jsonParse(context, JavaScriptValue.create(testString)).get(); + JavaScriptValue result = context.getGlobalObject().jsonParse(context, JavaScriptString.create(testString)).get(); assertTrue(result.isArrayObject()); - JavaScriptValue vv = JavaScriptValue.create(System.getProperty("java.version")); - context.getGlobalObject().set(context, JavaScriptValue.create("ddd"), vv); + JavaScriptValue vv = JavaScriptString.create(System.getProperty("java.version")); + context.getGlobalObject().set(context, JavaScriptString.create("ddd"), vv); Evaluator.evalScript(context, "'java.version' + ddd", "invalid", true); for (int i = 0; i < 999999; i++) { // alloc many trash objects for testing memory management - JavaScriptValue.create("asdf"); + JavaScriptString.create("asdf"); } context = null; @@ -329,7 +332,7 @@ public void bridgeTest() { class EmptyBridge extends Bridge.Adapter { @Override - public Optional callback(Optional data) { + public Optional callback(Context context, Optional data) { return Optional.empty(); } } @@ -351,12 +354,13 @@ class TestBridge extends Bridge.Adapter { public boolean called = false; @Override - public Optional callback(Optional data) { + public Optional callback(Context context, Optional data) { + assertTrue(JavaScriptObject.create(context).isObject()); assertFalse(called); assertTrue(data.get().isString()); assertTrue(data.get().asScriptString().toJavaString().equals("dddd")); called = true; - return Optional.of(JavaScriptValue.create(data.get().asScriptString().toJavaString() + "ASdfasdfasdf")); + return Optional.of(JavaScriptString.create(data.get().asScriptString().toJavaString() + "ASdfasdfasdf")); } }; @@ -365,15 +369,15 @@ public Optional callback(Optional data) { printPositiveTC("register bridge 1"); Bridge.register(context, "Native", "returnString", new Bridge.Adapter() { @Override - public Optional callback(Optional data) { + public Optional callback(Context context, Optional data) { assertFalse(data.isPresent()); - return Optional.of(JavaScriptValue.create("string from java")); + return Optional.of(JavaScriptString.create("string from java")); } }); printPositiveTC("register bridge 2"); Bridge.register(context, "Native", "returnNothing", new Bridge.Adapter() { @Override - public Optional callback(Optional data) { + public Optional callback(Context context, Optional data) { return Optional.empty(); } }); @@ -389,7 +393,7 @@ public Optional callback(Optional data) { Bridge.register(context, "Native", "returnNull", new Bridge.Adapter() { @Override - public Optional callback(Optional data) { + public Optional callback(Context context, Optional data) { return null; } }); @@ -399,7 +403,7 @@ public Optional callback(Optional data) { Bridge.register(context, "Native", "runtimeException", new Bridge.Adapter() { @Override - public Optional callback(Optional data) { + public Optional callback(Context context, Optional data) { throw new RuntimeException("test"); } }); @@ -467,12 +471,12 @@ public void heapValueTest() { assertFalse(v.isInt32()); printPositiveTC("float value test"); - v = JavaScriptValue.create((String) null); + v = JavaScriptString.create((String) null); assertTrue(v.isString()); assertTrue(v.asScriptString().toJavaString().equals("")); printNegativeTC("string with null"); - v = JavaScriptValue.create("hello"); + v = JavaScriptString.create("hello"); assertTrue(v.isString()); assertTrue(v.asScriptString().toJavaString().equals("hello")); assertFalse(v.isNumber()); @@ -483,6 +487,84 @@ public void heapValueTest() { finalizeEngine(); } + @Test + public void valueConversionTest() throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { + Context context = initEngineAndCreateContext(); + + ArrayList methodList = new ArrayList<>(); + Method methods[] = JavaScriptValue.class.getMethods(); + for (int i = 0; i < methods.length; i ++) { + if (methods[i].getName().startsWith("as")) { + methodList.add(methods[i].getName()); + } + } + + class TestSet { + public JavaScriptValue value; + public String[] okMethodNames; + + public TestSet(JavaScriptValue value, String[] okMethodNames) + { + this.value = value; + this.okMethodNames = okMethodNames; + } + } + TestSet ts[] = new TestSet[] { + new TestSet(JavaScriptValue.createUndefined(), new String[]{}), + new TestSet(JavaScriptValue.createNull(), new String[]{}), + new TestSet(JavaScriptValue.create(true), new String[]{"asBoolean"}), + new TestSet(JavaScriptValue.create(123), new String[]{"asInt32", "asNumber"}), + new TestSet(JavaScriptValue.create(123.123), new String[]{"asNumber"}), + new TestSet(JavaScriptString.create("asdf"), new String[]{"asScriptString"}), + new TestSet(JavaScriptSymbol.create(Optional.empty()), new String[]{"asScriptSymbol"}), + new TestSet(JavaScriptBigInt.create(123123), new String[]{"asScriptBigInt"}), + new TestSet(JavaScriptObject.create(context), new String[]{"asScriptObject"}), + new TestSet(JavaScriptArrayObject.create(context), new String[]{"asScriptObject", "asScriptArrayObject"}), + new TestSet(JavaScriptPromiseObject.create(context), new String[]{"asScriptObject", "asScriptPromiseObject"}), + new TestSet(JavaScriptJavaCallbackFunctionObject.create(context, "", 0, false, new JavaScriptJavaCallbackFunctionObject.Callback() { + @Override + public Optional callback(Context context, JavaScriptValue receiverValue, JavaScriptValue[] arguments) { + return Optional.empty(); + } + }), new String[]{"asScriptObject", "asScriptFunctionObject"}) + }; + + for (int i = 0; i < ts.length; i ++) { + TestSet t = ts[i]; + for (int j = 0; j < methodList.size(); j ++) { + String name = methodList.get(j); + boolean okName = false; + for (int k = 0; k < t.okMethodNames.length; k ++) { + if (t.okMethodNames[k].equals(name)) { + okName = true; + break; + } + } + try { + Method method = JavaScriptValue.class.getMethod(name); + if (okName) { + // pass if there is no error + method.invoke(t.value); + printPositiveTC(name + " test"); + } else { + try { + method.invoke(t.value); + assertTrue(false); + } catch (InvocationTargetException e) { + assertTrue(e.getCause() instanceof ClassCastException); + } + printNegativeTC(name + " throwing exception test"); + } + } catch (Exception e) { + throw e; + } + } + } + + context = null; + finalizeEngine(); + } + @Test public void valueToStringTest() { Context context = initEngineAndCreateContext(); @@ -540,8 +622,8 @@ public void valueOperationTest() { assertEquals(JavaScriptValue.create(123.123).toInteger(context).get(), Double.valueOf(123.0)); assertEquals(JavaScriptValue.create(123.456).toInt32(context).get(), Integer.valueOf(123)); printPositiveTC("value test method test 3"); - assertEquals(JavaScriptValue.create("123").toNumber(context).get(), Double.valueOf(123)); - assertTrue(JavaScriptValue.create("123").toObject(context).get().isObject()); + assertEquals(JavaScriptString.create("123").toNumber(context).get(), Double.valueOf(123)); + assertTrue(JavaScriptString.create("123").toObject(context).get().isObject()); printPositiveTC("value test method test 4"); assertFalse(context.lastThrownException().isPresent()); assertFalse(JavaScriptValue.createUndefined().toObject(context).isPresent()); @@ -557,20 +639,20 @@ public void symbolValueTest() { VMInstance vmInstance = VMInstance.create(Optional.of("en-US"), Optional.of("Asia/Seoul")); Context context = Context.create(vmInstance); - JavaScriptSymbol symbol = JavaScriptValue.create(Optional.empty()); + JavaScriptSymbol symbol = JavaScriptSymbol.create(Optional.empty()); assertFalse(symbol.description().isPresent()); assertTrue(symbol.symbolDescriptiveString().toJavaString().equals("Symbol()")); printNegativeTC("symbol null test 1"); - symbol = JavaScriptValue.create((Optional) null); + symbol = JavaScriptSymbol.create((Optional) null); assertFalse(symbol.description().isPresent()); assertTrue(symbol.symbolDescriptiveString().toJavaString().equals("Symbol()")); printNegativeTC("symbol null test 2"); - symbol = JavaScriptValue.create(Optional.of(JavaScriptString.create("foobar"))); + symbol = JavaScriptSymbol.create(Optional.of(JavaScriptString.create("foobar"))); assertTrue(symbol.description().isPresent()); assertTrue(symbol.description().get().toJavaString().equals("foobar")); - assertFalse(symbol.equalsTo(context, JavaScriptValue.create(Optional.of(JavaScriptString.create("foobar")))).get().booleanValue()); + assertFalse(symbol.equalsTo(context, JavaScriptSymbol.create(Optional.of(JavaScriptString.create("foobar")))).get().booleanValue()); printNegativeTC("symbol null test 4"); Optional exception = context.lastThrownException(); @@ -614,7 +696,7 @@ public void objectCreateReadWriteTest() { { final Context finalContext = context; assertThrows(NullPointerException.class, () -> { - obj.get(null, JavaScriptValue.create("asdf")); + obj.get(null, JavaScriptString.create("asdf")); }); printNegativeTC("object null test 2"); assertThrows(NullPointerException.class, () -> { @@ -622,28 +704,28 @@ public void objectCreateReadWriteTest() { }); printNegativeTC("object null test 3"); assertThrows(NullPointerException.class, () -> { - obj.set(null, JavaScriptValue.create("asdf"), JavaScriptValue.create("asdf")); + obj.set(null, JavaScriptString.create("asdf"), JavaScriptString.create("asdf")); }); printNegativeTC("object null test 4"); assertThrows(NullPointerException.class, () -> { - obj.set(finalContext, null, JavaScriptValue.create("asdf")); + obj.set(finalContext, null, JavaScriptString.create("asdf")); }); printNegativeTC("object null test 5"); assertThrows(NullPointerException.class, () -> { - obj.set(finalContext, JavaScriptValue.create("asdf"), null); + obj.set(finalContext, JavaScriptString.create("asdf"), null); }); printNegativeTC("object null test 6"); } - assertTrue(obj.set(context, JavaScriptValue.create("asdf"), JavaScriptValue.create(123)).get().booleanValue()); + assertTrue(obj.set(context, JavaScriptString.create("asdf"), JavaScriptValue.create(123)).get().booleanValue()); printPositiveTC("object test 1"); - assertTrue(obj.get(context, JavaScriptValue.create("asdf")).get().toNumber(context).get().doubleValue() == 123); + assertTrue(obj.get(context, JavaScriptString.create("asdf")).get().toNumber(context).get().doubleValue() == 123); printPositiveTC("object test 2"); { final Context finalContext = context; assertThrows(NullPointerException.class, () -> { - obj.defineDataProperty(null, JavaScriptValue.create("qwer"), JavaScriptValue.create(123), false, false, false); + obj.defineDataProperty(null, JavaScriptString.create("qwer"), JavaScriptValue.create(123), false, false, false); }); printNegativeTC("object null test 6"); assertThrows(NullPointerException.class, () -> { @@ -656,15 +738,15 @@ public void objectCreateReadWriteTest() { printNegativeTC("object null test 8"); } - assertTrue(obj.defineDataProperty(context, JavaScriptValue.create("qwer"), JavaScriptValue.create(123), false, false, false).get().booleanValue()); + assertTrue(obj.defineDataProperty(context, JavaScriptString.create("qwer"), JavaScriptValue.create(123), false, false, false).get().booleanValue()); printPositiveTC("object test 3"); - assertFalse(obj.defineDataProperty(context, JavaScriptValue.create("qwer"), JavaScriptValue.create(456), false, true, true).get().booleanValue()); + assertFalse(obj.defineDataProperty(context, JavaScriptString.create("qwer"), JavaScriptValue.create(456), false, true, true).get().booleanValue()); printPositiveTC("object test 4"); { final Context finalContext = context; assertThrows(NullPointerException.class, () -> { - obj.getOwnProperty(null, JavaScriptValue.create("qwer")); + obj.getOwnProperty(null, JavaScriptString.create("qwer")); }); printNegativeTC("object null test 9"); assertThrows(NullPointerException.class, () -> { @@ -673,7 +755,7 @@ public void objectCreateReadWriteTest() { printNegativeTC("object null test 10"); } - assertTrue(obj.getOwnProperty(context, JavaScriptValue.create("qwer")).get().toNumber(context).get().doubleValue() == 123); + assertTrue(obj.getOwnProperty(context, JavaScriptString.create("qwer")).get().toNumber(context).get().doubleValue() == 123); printPositiveTC("object test 5"); context = null; @@ -692,7 +774,7 @@ public void arrayCreateReadWriteTest() { JavaScriptArrayObject arr = JavaScriptArrayObject.create(context); assertTrue(arr.set(context, JavaScriptValue.create(3), JavaScriptValue.create(123)).get().booleanValue()); assertTrue(arr.get(context, JavaScriptValue.create(3)).get().toNumber(context).get().doubleValue() == 123); - assertTrue(arr.get(context, JavaScriptValue.create("length")).get().toInt32(context).get().intValue() == 4); + assertTrue(arr.get(context, JavaScriptString.create("length")).get().toInt32(context).get().intValue() == 4); assertTrue(arr.length(context) == 4); printPositiveTC("array test 1"); @@ -715,7 +797,7 @@ public void jsonParseStringifyTest() { final Context finalContext = context; String finalTestString = testString; assertThrows(NullPointerException.class, () -> { - finalContext.getGlobalObject().jsonParse(null, JavaScriptValue.create(finalTestString)); + finalContext.getGlobalObject().jsonParse(null, JavaScriptString.create(finalTestString)); }); printNegativeTC("json null test 1"); assertThrows(NullPointerException.class, () -> { @@ -724,7 +806,7 @@ public void jsonParseStringifyTest() { printNegativeTC("json null test 2"); } - JavaScriptValue result = context.getGlobalObject().jsonParse(context, JavaScriptValue.create(testString)).get(); + JavaScriptValue result = context.getGlobalObject().jsonParse(context, JavaScriptString.create(testString)).get(); assertTrue(result.isArrayObject()); assertEquals(result.asScriptArrayObject().get(context, JavaScriptValue.create(0)).get().toNumber(context).get().intValue(), 1); assertEquals(result.asScriptArrayObject().get(context, JavaScriptValue.create(1)).get().toNumber(context).get().intValue(), 2); @@ -733,9 +815,9 @@ public void jsonParseStringifyTest() { printPositiveTC("json test 1"); testString = "{\"a\": \"asdf\"}"; - result = context.getGlobalObject().jsonParse(context, JavaScriptValue.create(testString)).get(); + result = context.getGlobalObject().jsonParse(context, JavaScriptString.create(testString)).get(); assertTrue(result.isObject()); - assertEquals(result.asScriptObject().get(context, JavaScriptValue.create("a")).get().asScriptString().toJavaString(), "asdf"); + assertEquals(result.asScriptObject().get(context, JavaScriptString.create("a")).get().asScriptString().toJavaString(), "asdf"); result.asScriptObject().set(context, JavaScriptValue.create(123), JavaScriptValue.create(456)); printPositiveTC("json test 2"); @@ -767,7 +849,7 @@ public void testCallableAndCall() { value = JavaScriptString.create("1123"); assertFalse(value.isCallable()); printPositiveTC("callable test 1"); - value = JavaScriptString.create(Optional.of(JavaScriptString.create("asdf"))); + value = JavaScriptSymbol.create(Optional.of(JavaScriptString.create("asdf"))); assertFalse(value.isCallable()); value = JavaScriptObject.create(context); assertFalse(value.isCallable()); @@ -778,15 +860,15 @@ public void testCallableAndCall() { { final Context finalContext = context; assertThrows(NullPointerException.class, () -> { - JavaScriptValue.create("asdf").call(null, JavaScriptValue.createUndefined(), new JavaScriptValue[]{}); + JavaScriptString.create("asdf").call(null, JavaScriptValue.createUndefined(), new JavaScriptValue[]{}); }); printNegativeTC("callable null test 1"); assertThrows(NullPointerException.class, () -> { - JavaScriptValue.create("asdf").call(finalContext, null, new JavaScriptValue[]{}); + JavaScriptString.create("asdf").call(finalContext, null, new JavaScriptValue[]{}); }); printNegativeTC("callable null test 2"); assertThrows(NullPointerException.class, () -> { - JavaScriptValue.create("asdf").call(finalContext, JavaScriptValue.createUndefined(), null); + JavaScriptString.create("asdf").call(finalContext, JavaScriptValue.createUndefined(), null); }); printNegativeTC("callable null test 3"); } @@ -796,7 +878,7 @@ public void testCallableAndCall() { assertTrue(context.lastThrownException().isPresent()); printPositiveTC("callable test 3"); - value = context.getGlobalObject().asScriptObject().get(context, JavaScriptValue.create("Array")).get(); + value = context.getGlobalObject().asScriptObject().get(context, JavaScriptString.create("Array")).get(); assertTrue(value.isCallable()); value = value.call(context, JavaScriptString.createUndefined(), new JavaScriptValue[]{ @@ -819,7 +901,7 @@ public void testCallableAndCall() { JavaScriptValue ret = newFunction.call(context, JavaScriptValue.createUndefined(), new JavaScriptValue[]{}).get(); assertTrue(ret.equalsTo(context, global).get().booleanValue()); - ret = newFunction.call(context, JavaScriptValue.create("asdf"), new JavaScriptValue[]{}).get(); + ret = newFunction.call(context, JavaScriptString.create("asdf"), new JavaScriptValue[]{}).get(); assertTrue(ret.isObject()); assertEquals(ret.toString(context).get().toJavaString(), "asdf"); printPositiveTC("callable test 5"); @@ -833,6 +915,7 @@ public void testBigInt() { Context context = initEngineAndCreateContext(); JavaScriptBigInt bigInt = JavaScriptBigInt.create(123123); + assertTrue(bigInt.asScriptBigInt().toNumber() == 123123); assertEquals(bigInt.toString(10).toJavaString(), "123123"); assertEquals(bigInt.toString(3).toJavaString(), "20020220010"); assertEquals(bigInt.toInt64(), 123123); @@ -877,11 +960,11 @@ public void testConstruct() { { final Context finalContext = context; assertThrows(NullPointerException.class, () -> { - JavaScriptValue.create("asdf").construct(null, new JavaScriptValue[]{}); + JavaScriptString.create("asdf").construct(null, new JavaScriptValue[]{}); }); printNegativeTC("construct value test 1"); assertThrows(NullPointerException.class, () -> { - JavaScriptValue.create("asdf").construct(finalContext, null); + JavaScriptString.create("asdf").construct(finalContext, null); }); printNegativeTC("construct value test 2"); } @@ -897,7 +980,7 @@ public void testConstruct() { printPositiveTC("construct test 1"); JavaScriptValue returnValue = newFunction.call(context, JavaScriptValue.createUndefined(), new JavaScriptValue[]{ - JavaScriptValue.create("test") + JavaScriptString.create("test") }).get(); assertEquals(returnValue.asScriptString().toJavaString(), "test"); @@ -920,7 +1003,7 @@ public void testJavaCallbackFunction() { false, new JavaScriptJavaCallbackFunctionObject.Callback() { @Override - public Optional callback(JavaScriptValue receiverValue, JavaScriptValue[] arguments) { + public Optional callback(Context context, JavaScriptValue receiverValue, JavaScriptValue[] arguments) { return Optional.empty(); } }); @@ -943,7 +1026,7 @@ public Optional callback(JavaScriptValue receiverValue, JavaScr false, new JavaScriptJavaCallbackFunctionObject.Callback() { @Override - public Optional callback(JavaScriptValue receiverValue, JavaScriptValue[] arguments) { + public Optional callback(Context context, JavaScriptValue receiverValue, JavaScriptValue[] arguments) { return Optional.of(JavaScriptValue.create(arguments.length)); } }); @@ -975,7 +1058,7 @@ public Optional callback(JavaScriptValue receiverValue, JavaScr false, new JavaScriptJavaCallbackFunctionObject.Callback() { @Override - public Optional callback(JavaScriptValue receiverValue, JavaScriptValue[] arguments) { + public Optional callback(Context context, JavaScriptValue receiverValue, JavaScriptValue[] arguments) { int sum = 0; for (int i = 0; i < arguments.length; i++) { sum += arguments[i].asInt32(); @@ -999,7 +1082,7 @@ public Optional callback(JavaScriptValue receiverValue, JavaScr false, new JavaScriptJavaCallbackFunctionObject.Callback() { @Override - public Optional callback(JavaScriptValue receiverValue, JavaScriptValue[] arguments) { + public Optional callback(Context context, JavaScriptValue receiverValue, JavaScriptValue[] arguments) { return null; } }); @@ -1016,7 +1099,7 @@ public Optional callback(JavaScriptValue receiverValue, JavaScr false, new JavaScriptJavaCallbackFunctionObject.Callback() { @Override - public Optional callback(JavaScriptValue receiverValue, JavaScriptValue[] arguments) { + public Optional callback(Context context, JavaScriptValue receiverValue, JavaScriptValue[] arguments) { throw new RuntimeException("test"); } }); @@ -1074,9 +1157,9 @@ public void promiseTest() "});\n" + "myPromise.then( () => { globalThis.thenCalled = true; } )", "test.js", true); - assertTrue(context.getGlobalObject().get(context, JavaScriptValue.create("thenCalled")).get().isUndefined()); + assertTrue(context.getGlobalObject().get(context, JavaScriptString.create("thenCalled")).get().isUndefined()); Evaluator.evalScript(context, "myResolve()", "test.js", true); - assertTrue(context.getGlobalObject().get(context, JavaScriptValue.create("thenCalled")).get().asBoolean()); + assertTrue(context.getGlobalObject().get(context, JavaScriptString.create("thenCalled")).get().asBoolean()); assertFalse(vmInstance.hasPendingJob()); printPositiveTC("promiseTest 1"); @@ -1086,10 +1169,10 @@ public void promiseTest() " myResolve = resolve;\n" + "});\n" + "myPromise.then( () => { globalThis.thenCalled = true; } )", "test.js", true); - context.getGlobalObject().get(context, JavaScriptValue.create("myResolve")).get().call(context, JavaScriptValue.createUndefined(), new JavaScriptValue[]{}); + context.getGlobalObject().get(context, JavaScriptString.create("myResolve")).get().call(context, JavaScriptValue.createUndefined(), new JavaScriptValue[]{}); assertTrue(vmInstance.hasPendingJob()); vmInstance.executeEveryPendingJobIfExists(); - assertTrue(context.getGlobalObject().get(context, JavaScriptValue.create("thenCalled")).get().asBoolean()); + assertTrue(context.getGlobalObject().get(context, JavaScriptString.create("thenCalled")).get().asBoolean()); assertFalse(vmInstance.hasPendingJob()); printPositiveTC("promiseTest 2"); @@ -1103,10 +1186,11 @@ public void promiseTest() class TestCallback extends JavaScriptJavaCallbackFunctionObject.Callback { public boolean called = false; @Override - public Optional callback(JavaScriptValue receiverValue, JavaScriptValue[] arguments) { + public Optional callback(Context context, JavaScriptValue receiverValue, JavaScriptValue[] arguments) { + JavaScriptObject.create(context); called = true; assertTrue(arguments[0].asInt32() == 123); - return Optional.of(JavaScriptValue.create("asdf")); + return Optional.of(JavaScriptString.create("asdf")); } } TestCallback cb = new TestCallback(); @@ -1221,6 +1305,22 @@ public Optional callback(JavaScriptValue receiverValue, JavaScr assertTrue(cb2.called); assertTrue(po.state() == JavaScriptPromiseObject.PromiseState.Rejected); + printPositiveTC("promiseTest 10"); + Optional asyncCallResult = Evaluator.evalScript(context, "async function asdf() { return 10; }; asdf().then(function() {});", + "test.js", false, false); + assertTrue(asyncCallResult.isPresent()); + assertTrue(vmInstance.hasPendingJob()); + assertTrue(asyncCallResult.get().asScriptPromiseObject().state() == JavaScriptPromiseObject.PromiseState.Pending); + vmInstance.executeEveryPendingJobIfExists(); + assertTrue(asyncCallResult.get().asScriptPromiseObject().state() == JavaScriptPromiseObject.PromiseState.FulFilled); + + printPositiveTC("promiseTest 11"); + asyncCallResult = Evaluator.evalScript(context, "async function asdf() { return 10; }; asdf().then(function() {});", + "test.js", false, true); + assertTrue(asyncCallResult.isPresent()); + assertFalse(vmInstance.hasPendingJob()); + assertTrue(asyncCallResult.get().asScriptPromiseObject().state() == JavaScriptPromiseObject.PromiseState.FulFilled); + context = null; vmInstance = null; finalizeEngine(); diff --git a/build/android/escargot/src/main/cpp/CMakeLists.txt b/build/android/escargot/src/main/cpp/CMakeLists.txt index a4cc8d8f4..9223cb446 100644 --- a/build/android/escargot/src/main/cpp/CMakeLists.txt +++ b/build/android/escargot/src/main/cpp/CMakeLists.txt @@ -5,7 +5,7 @@ project(escargot-jni) option(UNDER_NDK "Build under the Android NDK" ON) option(ENABLE_SHELL "Enable shell" OFF) -SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fexceptions") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fexceptions -Wno-conversion-null") if (NOT UNDER_NDK) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libstdc++ -g3") diff --git a/build/android/escargot/src/main/cpp/escargot.cpp b/build/android/escargot/src/main/cpp/escargot.cpp index 17f4603be..b30b5f2b3 100644 --- a/build/android/escargot/src/main/cpp/escargot.cpp +++ b/build/android/escargot/src/main/cpp/escargot.cpp @@ -66,6 +66,15 @@ using namespace Escargot; return; \ } +#define THROW_CAST_EXCEPTION_IF_NEEDS(param, value, typeName) \ + if (env->ExceptionCheck()) { \ + return NULL; \ + } \ + if (!value->is##typeName()) { \ + env->ThrowNew(env->FindClass("java/lang/ClassCastException"), "Can not cast to " #typeName); \ + return NULL; \ + } + static JavaVM* g_jvm; static size_t g_nonPointerValueLast = reinterpret_cast(ValueRef::createUndefined()); static jobject createJavaObjectFromValue(JNIEnv* env, ValueRef* value); @@ -86,6 +95,22 @@ static OptionalRef fetchJNIEnvFromCallback() return env; } +static jobject createJavaObject(JNIEnv* env, VMInstanceRef* value) +{ + PersistentRefHolder* pRef = new PersistentRefHolder(value); + jlong ptr = reinterpret_cast(pRef); + jclass clazz = env->FindClass("com/samsung/lwe/escargot/VMInstance"); + return env->NewObject(clazz, env->GetMethodID(clazz, "", "(J)V"), ptr); +} + +static jobject createJavaObject(JNIEnv* env, ContextRef* value) +{ + PersistentRefHolder* pRef = new PersistentRefHolder(value); + jlong ptr = reinterpret_cast(pRef); + jclass clazz = env->FindClass("com/samsung/lwe/escargot/Context"); + return env->NewObject(clazz, env->GetMethodID(clazz, "", "(J)V"), ptr); +} + extern "C" JNIEXPORT void JNICALL Java_com_samsung_lwe_escargot_Escargot_init(JNIEnv* env, jclass clazz) @@ -363,7 +388,7 @@ class ShellPlatform : public PlatformRef { } }; -static Evaluator::EvaluatorResult evalScript(ContextRef* context, StringRef* source, StringRef* srcName, bool shouldPrintScriptResult, bool isModule) +static Evaluator::EvaluatorResult evalScript(ContextRef* context, StringRef* source, StringRef* srcName, bool shouldPrintScriptResult, bool shouldExecutePendingJobsAtEnd, bool isModule) { if (stringEndsWith(srcName->toStdUTF8String(), "mjs")) { isModule = isModule || true; @@ -417,23 +442,24 @@ static Evaluator::EvaluatorResult evalScript(ContextRef* context, StringRef* sou LOGD("%s", evalResult.resultOrErrorToString(context)->toStdUTF8String().data()); } - bool result = true; - while (context->vmInstance()->hasPendingJob() || context->vmInstance()->hasPendingJobFromAnotherThread()) { - if (context->vmInstance()->waitEventFromAnotherThread(10)) { - context->vmInstance()->executePendingJobFromAnotherThread(); - } - if (context->vmInstance()->hasPendingJob()) { - auto jobResult = context->vmInstance()->executePendingJob(); - if (shouldPrintScriptResult || jobResult.error) { - if (jobResult.error) { - LOGD("Uncaught %s:(in promise job)\n", jobResult.resultOrErrorToString(context)->toStdUTF8String().data()); - result = false; - } else { - LOGD("%s(in promise job)\n", jobResult.resultOrErrorToString(context)->toStdUTF8String().data()); + if (shouldExecutePendingJobsAtEnd) { + while (context->vmInstance()->hasPendingJob() || context->vmInstance()->hasPendingJobFromAnotherThread()) { + if (context->vmInstance()->waitEventFromAnotherThread(10)) { + context->vmInstance()->executePendingJobFromAnotherThread(); + } + if (context->vmInstance()->hasPendingJob()) { + auto jobResult = context->vmInstance()->executePendingJob(); + if (shouldPrintScriptResult) { + if (jobResult.error) { + LOGD("Uncaught %s:(in promise job)\n", jobResult.resultOrErrorToString(context)->toStdUTF8String().data()); + } else { + LOGD("%s(in promise job)\n", jobResult.resultOrErrorToString(context)->toStdUTF8String().data()); + } } } } } + return evalResult; } @@ -621,8 +647,7 @@ Java_com_samsung_lwe_escargot_VMInstance_create(JNIEnv *env, jclass clazz, jobje auto vmRef = VMInstanceRef::create(localeString.length() ? localeString.data() : nullptr, timezoneString.length() ? timezoneString.data() : nullptr); - PersistentRefHolder* pRef = new PersistentRefHolder(std::move(vmRef)); - return env->NewObject(clazz, env->GetMethodID(clazz, "", "(J)V"), reinterpret_cast(pRef)); + return createJavaObject(env, vmRef.get()); } extern "C" @@ -654,8 +679,7 @@ Java_com_samsung_lwe_escargot_Context_create(JNIEnv* env, jclass clazz, jobject auto vmPtr = getPersistentPointerFromJava(env, env->GetObjectClass(vmInstance), vmInstance); auto contextRef = ContextRef::create(vmPtr->get()); - PersistentRefHolder* pRef = new PersistentRefHolder(std::move(contextRef)); - return env->NewObject(clazz, env->GetMethodID(clazz, "", "(J)V"), reinterpret_cast(pRef)); + return createJavaObject(env, contextRef.get()); } static StringRef* createJSStringFromJava(JNIEnv* env, jstring str) @@ -687,14 +711,15 @@ extern "C" JNIEXPORT jobject JNICALL Java_com_samsung_lwe_escargot_Evaluator_evalScript(JNIEnv* env, jclass clazz, jobject context, jstring source, jstring sourceFileName, - jboolean shouldPrintScriptResult) + jboolean shouldPrintScriptResult, + jboolean shouldExecutePendingJobsAtEnd) { THROW_NPE_RETURN_NULL(context, "Context"); auto ptr = getPersistentPointerFromJava(env, env->GetObjectClass(context), context); Evaluator::EvaluatorResult result = evalScript(ptr->get(), createJSStringFromJava(env, source), createJSStringFromJava(env, sourceFileName), shouldPrintScriptResult, - false); + shouldExecutePendingJobsAtEnd, false); if (env->ExceptionCheck()) { return nullptr; } @@ -797,7 +822,8 @@ Java_com_samsung_lwe_escargot_Bridge_register(JNIEnv* env, jclass clazz, jobject env->GetMethodID( env->GetObjectClass(jo), "callback", - "(Ljava/util/Optional;)Ljava/util/Optional;"), + "(Lcom/samsung/lwe/escargot/Context;Ljava/util/Optional;)Ljava/util/Optional;"), + createJavaObject(env.get(), callee->context()), callbackArg); if (env->ExceptionCheck()) { @@ -914,35 +940,6 @@ Java_com_samsung_lwe_escargot_JavaScriptValue_create__Z(JNIEnv* env, jclass claz return createJavaValueObject(env, clazz, ValueRef::create(static_cast(value))); } -extern "C" -JNIEXPORT jobject JNICALL -Java_com_samsung_lwe_escargot_JavaScriptValue_create__Ljava_util_Optional_2(JNIEnv* env, - jclass clazz, - jobject value) -{ - OptionalRef descString; - if (value) { - auto classOptionalJavaScriptString = env->GetObjectClass(value); - auto methodIsPresent = env->GetMethodID(classOptionalJavaScriptString, "isPresent", "()Z"); - if (env->CallBooleanMethod(value, methodIsPresent)) { - auto methodGet = env->GetMethodID(classOptionalJavaScriptString, "get", "()Ljava/lang/Object;"); - jboolean isSucceed; - jobject javaObjectValue = env->CallObjectMethod(value, methodGet); - descString = unwrapValueRefFromValue(env, env->GetObjectClass(javaObjectValue), javaObjectValue)->asString(); - } - } - - return createJavaValueObject(env, "com/samsung/lwe/escargot/JavaScriptSymbol", SymbolRef::create(descString)); -} - -extern "C" -JNIEXPORT jobject JNICALL -Java_com_samsung_lwe_escargot_JavaScriptValue_create__Ljava_lang_String_2(JNIEnv* env, jclass clazz, - jstring value) -{ - return createJavaValueObject(env, "com/samsung/lwe/escargot/JavaScriptString", createJSStringFromJava(env, value)); -} - static jobject createJavaObjectFromValue(JNIEnv* env, ValueRef* value) { if (!value->isStoredInHeap() || value->isNumber()) { @@ -1089,27 +1086,35 @@ extern "C" JNIEXPORT jboolean JNICALL Java_com_samsung_lwe_escargot_JavaScriptValue_asBoolean(JNIEnv* env, jobject thiz) { - return unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->asBoolean(); + ValueRef* ref = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz); + THROW_CAST_EXCEPTION_IF_NEEDS(env, ref, Boolean); + return ref->asBoolean(); } extern "C" JNIEXPORT jint JNICALL Java_com_samsung_lwe_escargot_JavaScriptValue_asInt32(JNIEnv* env, jobject thiz) { - return unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->asInt32(); + ValueRef* ref = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz); + THROW_CAST_EXCEPTION_IF_NEEDS(env, ref, Int32); + return ref->asInt32(); } extern "C" JNIEXPORT jdouble JNICALL Java_com_samsung_lwe_escargot_JavaScriptValue_asNumber(JNIEnv* env, jobject thiz) { - return unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->asNumber(); + ValueRef* ref = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz); + THROW_CAST_EXCEPTION_IF_NEEDS(env, ref, Number); + return ref->asNumber(); } extern "C" JNIEXPORT jobject JNICALL Java_com_samsung_lwe_escargot_JavaScriptValue_asScriptString(JNIEnv* env, jobject thiz) { + ValueRef* ref = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz); + THROW_CAST_EXCEPTION_IF_NEEDS(env, ref, String); return thiz; } @@ -1117,6 +1122,8 @@ extern "C" JNIEXPORT jobject JNICALL Java_com_samsung_lwe_escargot_JavaScriptValue_asScriptSymbol(JNIEnv* env, jobject thiz) { + ValueRef* ref = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz); + THROW_CAST_EXCEPTION_IF_NEEDS(env, ref, Symbol); return thiz; } @@ -1124,6 +1131,8 @@ extern "C" JNIEXPORT jobject JNICALL Java_com_samsung_lwe_escargot_JavaScriptValue_asScriptBigInt(JNIEnv* env, jobject thiz) { + ValueRef* ref = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz); + THROW_CAST_EXCEPTION_IF_NEEDS(env, ref, BigInt); return thiz; } @@ -1131,6 +1140,8 @@ extern "C" JNIEXPORT jobject JNICALL Java_com_samsung_lwe_escargot_JavaScriptValue_asScriptObject(JNIEnv* env, jobject thiz) { + ValueRef* ref = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz); + THROW_CAST_EXCEPTION_IF_NEEDS(env, ref, Object); return thiz; } @@ -1138,6 +1149,8 @@ extern "C" JNIEXPORT jobject JNICALL Java_com_samsung_lwe_escargot_JavaScriptValue_asScriptArrayObject(JNIEnv* env, jobject thiz) { + ValueRef* ref = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz); + THROW_CAST_EXCEPTION_IF_NEEDS(env, ref, ArrayObject); return thiz; } @@ -1145,6 +1158,8 @@ extern "C" JNIEXPORT jobject JNICALL Java_com_samsung_lwe_escargot_JavaScriptValue_asScriptFunctionObject(JNIEnv* env, jobject thiz) { + ValueRef* ref = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz); + THROW_CAST_EXCEPTION_IF_NEEDS(env, ref, FunctionObject); return thiz; } @@ -1152,9 +1167,18 @@ extern "C" JNIEXPORT jobject JNICALL Java_com_samsung_lwe_escargot_JavaScriptValue_asScriptPromiseObject(JNIEnv* env, jobject thiz) { + ValueRef* ref = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz); + THROW_CAST_EXCEPTION_IF_NEEDS(env, ref, PromiseObject); return thiz; } +extern "C" +JNIEXPORT jobject JNICALL +Java_com_samsung_lwe_escargot_JavaScriptString_create(JNIEnv* env, jclass clazz, jstring value) +{ + return createJavaValueObject(env, "com/samsung/lwe/escargot/JavaScriptString", createJSStringFromJava(env, value)); +} + extern "C" JNIEXPORT jstring JNICALL Java_com_samsung_lwe_escargot_JavaScriptString_toJavaString(JNIEnv* env, jobject thiz) @@ -1558,6 +1582,25 @@ Java_com_samsung_lwe_escargot_JavaScriptBigInt_toInt64(JNIEnv* env, jobject thiz return unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->asBigInt()->toInt64(); } +extern "C" +JNIEXPORT jobject JNICALL +Java_com_samsung_lwe_escargot_JavaScriptSymbol_create(JNIEnv* env, jclass clazz, jobject value) +{ + OptionalRef descString; + if (value) { + auto classOptionalJavaScriptString = env->GetObjectClass(value); + auto methodIsPresent = env->GetMethodID(classOptionalJavaScriptString, "isPresent", "()Z"); + if (env->CallBooleanMethod(value, methodIsPresent)) { + auto methodGet = env->GetMethodID(classOptionalJavaScriptString, "get", "()Ljava/lang/Object;"); + jboolean isSucceed; + jobject javaObjectValue = env->CallObjectMethod(value, methodGet); + descString = unwrapValueRefFromValue(env, env->GetObjectClass(javaObjectValue), javaObjectValue)->asString(); + } + } + + return createJavaValueObject(env, "com/samsung/lwe/escargot/JavaScriptSymbol", SymbolRef::create(descString)); +} + extern "C" JNIEXPORT jobject JNICALL Java_com_samsung_lwe_escargot_JavaScriptSymbol_fromGlobalSymbolRegistry(JNIEnv* env, jclass clazz, @@ -1865,6 +1908,14 @@ Java_com_samsung_lwe_escargot_JavaScriptPromiseObject_hasHandler(JNIEnv* env, jo return thisValueRef->hasResolveHandlers() || thisValueRef->hasRejectHandlers(); } +extern "C" +JNIEXPORT jobject JNICALL +Java_com_samsung_lwe_escargot_JavaScriptFunctionObject_context(JNIEnv* env, jobject thiz) +{ + FunctionObjectRef* thisValueRef = unwrapValueRefFromValue(env, env->GetObjectClass(thiz), thiz)->asFunctionObject(); + return createJavaObject(env, thisValueRef->context()); +} + extern "C" JNIEXPORT jobject JNICALL Java_com_samsung_lwe_escargot_Context_getGlobalObject(JNIEnv* env, jobject thiz) @@ -1945,7 +1996,7 @@ Java_com_samsung_lwe_escargot_JavaScriptJavaCallbackFunctionObject_create(JNIEnv env->PushLocalFrame(32); jobject callback = reinterpret_cast(state->resolveCallee()->extraData()); auto callbackMethodId = env->GetMethodID(env->GetObjectClass(callback), "callback", - "(Lcom/samsung/lwe/escargot/JavaScriptValue;[Lcom/samsung/lwe/escargot/JavaScriptValue;)Ljava/util/Optional;"); + "(Lcom/samsung/lwe/escargot/Context;Lcom/samsung/lwe/escargot/JavaScriptValue;[Lcom/samsung/lwe/escargot/JavaScriptValue;)Ljava/util/Optional;"); jobjectArray javaArgv = env->NewObjectArray(argc, env->FindClass("com/samsung/lwe/escargot/JavaScriptValue"), nullptr); @@ -1957,6 +2008,7 @@ Java_com_samsung_lwe_escargot_JavaScriptJavaCallbackFunctionObject_create(JNIEnv jobject returnValue = env->CallObjectMethod( callback, callbackMethodId, + createJavaObject(env.get(), state->resolveCallee()->context()), createJavaObjectFromValue(env.get(), thisValue), javaArgv ); diff --git a/build/android/escargot/src/main/java/com/samsung/lwe/escargot/Bridge.java b/build/android/escargot/src/main/java/com/samsung/lwe/escargot/Bridge.java index beada2c29..e3f27734b 100644 --- a/build/android/escargot/src/main/java/com/samsung/lwe/escargot/Bridge.java +++ b/build/android/escargot/src/main/java/com/samsung/lwe/escargot/Bridge.java @@ -9,10 +9,11 @@ private Bridge() { public abstract static class Adapter { /** + * @param context Context from callee * @param data the data parameter contains value when call this function from JavaScript * @return if want to return data to JavaScript callback, you can return value from this callback. */ - public abstract Optional callback(Optional data); + public abstract Optional callback(Context context, Optional data); } /** diff --git a/build/android/escargot/src/main/java/com/samsung/lwe/escargot/Evaluator.java b/build/android/escargot/src/main/java/com/samsung/lwe/escargot/Evaluator.java index 5341229cf..e498b2e0a 100644 --- a/build/android/escargot/src/main/java/com/samsung/lwe/escargot/Evaluator.java +++ b/build/android/escargot/src/main/java/com/samsung/lwe/escargot/Evaluator.java @@ -7,12 +7,40 @@ final public class Evaluator { private Evaluator() { } + /** + * + * @param context + * @param source + * @param sourceFileName + * @return return result if eval was successful + */ + static public Optional evalScript(Context context, String source, String sourceFileName) + { + return evalScript(context, source, sourceFileName, false); + } + + + /** + * @param context + * @param source + * @param sourceFileName + * @param shouldPrintScriptResult + * @return return result if eval was successful + */ + static public Optional evalScript(Context context, String source, String sourceFileName, + boolean shouldPrintScriptResult) + { + return evalScript(context, source, sourceFileName, shouldPrintScriptResult, true); + } + /** * @param context * @param source * @param sourceFileName * @param shouldPrintScriptResult + * @param shouldExecutePendingJobsAtEnd * @return return result if eval was successful */ - static native public Optional evalScript(Context context, String source, String sourceFileName, boolean shouldPrintScriptResult); + static native public Optional evalScript(Context context, String source, String sourceFileName, + boolean shouldPrintScriptResult, boolean shouldExecutePendingJobsAtEnd); } diff --git a/build/android/escargot/src/main/java/com/samsung/lwe/escargot/JavaScriptFunctionObject.java b/build/android/escargot/src/main/java/com/samsung/lwe/escargot/JavaScriptFunctionObject.java index 9428690c3..fe7a361e3 100644 --- a/build/android/escargot/src/main/java/com/samsung/lwe/escargot/JavaScriptFunctionObject.java +++ b/build/android/escargot/src/main/java/com/samsung/lwe/escargot/JavaScriptFunctionObject.java @@ -5,4 +5,5 @@ protected JavaScriptFunctionObject(long nativePointer) { super(nativePointer); } + public native Context context(); } diff --git a/build/android/escargot/src/main/java/com/samsung/lwe/escargot/JavaScriptJavaCallbackFunctionObject.java b/build/android/escargot/src/main/java/com/samsung/lwe/escargot/JavaScriptJavaCallbackFunctionObject.java index a5c66fee5..60884b33d 100644 --- a/build/android/escargot/src/main/java/com/samsung/lwe/escargot/JavaScriptJavaCallbackFunctionObject.java +++ b/build/android/escargot/src/main/java/com/samsung/lwe/escargot/JavaScriptJavaCallbackFunctionObject.java @@ -11,11 +11,12 @@ protected JavaScriptJavaCallbackFunctionObject(long nativePointer) public abstract static class Callback { /** * + * @param context * @param receiverValue * @param arguments * @return */ - public abstract Optional callback(JavaScriptValue receiverValue, JavaScriptValue arguments[]); + public abstract Optional callback(Context context, JavaScriptValue receiverValue, JavaScriptValue arguments[]); } /** diff --git a/build/android/escargot/src/main/java/com/samsung/lwe/escargot/JavaScriptString.java b/build/android/escargot/src/main/java/com/samsung/lwe/escargot/JavaScriptString.java index 86587e999..3c447cb77 100644 --- a/build/android/escargot/src/main/java/com/samsung/lwe/escargot/JavaScriptString.java +++ b/build/android/escargot/src/main/java/com/samsung/lwe/escargot/JavaScriptString.java @@ -5,5 +5,6 @@ protected JavaScriptString(long nativePointer) { super(nativePointer, true); } + native static public JavaScriptString create(String value); native public String toJavaString(); } diff --git a/build/android/escargot/src/main/java/com/samsung/lwe/escargot/JavaScriptSymbol.java b/build/android/escargot/src/main/java/com/samsung/lwe/escargot/JavaScriptSymbol.java index ee9596491..294eac338 100644 --- a/build/android/escargot/src/main/java/com/samsung/lwe/escargot/JavaScriptSymbol.java +++ b/build/android/escargot/src/main/java/com/samsung/lwe/escargot/JavaScriptSymbol.java @@ -7,6 +7,8 @@ protected JavaScriptSymbol(long nativePointer) { super(nativePointer, true); } + + native static public JavaScriptSymbol create(Optional value); native public Optional description(); native public JavaScriptString symbolDescriptiveString(); diff --git a/build/android/escargot/src/main/java/com/samsung/lwe/escargot/JavaScriptValue.java b/build/android/escargot/src/main/java/com/samsung/lwe/escargot/JavaScriptValue.java index 252bce07d..6dfa69a5a 100644 --- a/build/android/escargot/src/main/java/com/samsung/lwe/escargot/JavaScriptValue.java +++ b/build/android/escargot/src/main/java/com/samsung/lwe/escargot/JavaScriptValue.java @@ -18,8 +18,6 @@ protected JavaScriptValue(long nativePointer, boolean isHeapValue) native static public JavaScriptValue create(boolean value); native static public JavaScriptValue create(int value); native static public JavaScriptValue create(double value); - native static public JavaScriptString create(String value); - native static public JavaScriptSymbol create(Optional value); native public boolean isUndefined(); native public boolean isNull(); @@ -38,9 +36,6 @@ protected JavaScriptValue(long nativePointer, boolean isHeapValue) native public boolean isFunctionObject(); native public boolean isPromiseObject(); - // as{ .. } methods don't check type is correct - // if you want to use these as{ .. } methods - // you must check type before use! native public boolean asBoolean(); native public int asInt32(); native public double asNumber(); diff --git a/build/target.cmake b/build/target.cmake index 3064fcc57..737a223d3 100644 --- a/build/target.cmake +++ b/build/target.cmake @@ -22,7 +22,7 @@ ENDIF() # Default options per compiler IF (${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC" OR ${COMPILER_CLANG_CL}) - SET (ESCARGOT_CXXFLAGS /std:c++17 /fp:strict /Zc:__cplusplus /EHs /source-charset:utf-8 /D_CRT_SECURE_NO_WARNINGS /DGC_NOT_DLL /D_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING /wd4244 /wd4267 /wd4805 /wd4018 /wd4172) + SET (ESCARGOT_CXXFLAGS /std:c++17 /fp:strict /Zc:__cplusplus /EHs /source-charset:utf-8 /MP /D_CRT_SECURE_NO_WARNINGS /DGC_NOT_DLL /D_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING /wd4244 /wd4267 /wd4805 /wd4018 /wd4172) SET (ESCARGOT_CXXFLAGS_RELEASE /O2 /Oy-) SET (ESCARGOT_THIRDPARTY_CFLAGS /D_CRT_SECURE_NO_WARNINGS /DGC_NOT_DLL /Oy- /wd4146 /EHs) IF (${COMPILER_CLANG_CL}) diff --git a/src/api/EscargotPublic.cpp b/src/api/EscargotPublic.cpp index 795b2c291..ec2531fe1 100644 --- a/src/api/EscargotPublic.cpp +++ b/src/api/EscargotPublic.cpp @@ -2802,6 +2802,11 @@ FunctionObjectRef* FunctionObjectRef::create(ExecutionStateRef* stateRef, String return toRef(result); } +ContextRef* FunctionObjectRef::context() +{ + return toRef(toImpl(this)->codeBlock()->context()); +} + ValueRef* FunctionObjectRef::getFunctionPrototype(ExecutionStateRef* state) { FunctionObject* o = toImpl(this); diff --git a/src/api/EscargotPublic.h b/src/api/EscargotPublic.h index df114fbe5..ade4fa45c 100644 --- a/src/api/EscargotPublic.h +++ b/src/api/EscargotPublic.h @@ -1544,6 +1544,9 @@ class ESCARGOT_EXPORT FunctionObjectRef : public ObjectRef { static FunctionObjectRef* create(ExecutionStateRef* state, AtomicStringRef* functionName, size_t argumentCount, ValueRef** argumentNameArray, ValueRef* body); static FunctionObjectRef* create(ExecutionStateRef* state, StringRef* sourceName, AtomicStringRef* functionName, size_t argumentCount, ValueRef** argumentNameArray, ValueRef* body); + // returns associate context + ContextRef* context(); + // get prototype property of constructible function(not [[prototype]]) // this property is used for new object construction. see https://www.ecma-international.org/ecma-262/6.0/#sec-ordinarycreatefromconstructor ValueRef* getFunctionPrototype(ExecutionStateRef* state);