diff --git a/docs/faq/development/where_are_es6_api_in_v8_mode.html b/docs/faq/development/where_are_es6_api_in_v8_mode.html
index 9c914e414..6f600decf 100644
--- a/docs/faq/development/where_are_es6_api_in_v8_mode.html
+++ b/docs/faq/development/where_are_es6_api_in_v8_mode.html
@@ -6,7 +6,7 @@
- Where are ES6 API in V8 Mode? - Javet 3.0.4 documentation
+ Where are ES6 API in V8 Mode? - Javet 3.1.0 documentation
@@ -125,7 +125,7 @@
implementation("com.caoccao.javet:javet:3.0.4")// Linux and Windows (x86_64)
-implementation("com.caoccao.javet:javet-linux-arm64:3.0.4")// Linux (arm64)
-implementation("com.caoccao.javet:javet-macos:3.0.4")// Mac OS (x86_64 and arm64)
-implementation("com.caoccao.javet:javet-android:3.0.4")// Android (arm, arm64, x86 and x86_64)
+
implementation("com.caoccao.javet:javet:3.1.0")// Linux and Windows (x86_64)
+implementation("com.caoccao.javet:javet-linux-arm64:3.1.0")// Linux (arm64)
+implementation("com.caoccao.javet:javet-macos:3.1.0")// Mac OS (x86_64 and arm64)
+implementation("com.caoccao.javet:javet-android-node:3.1.0")// Android Node (arm, arm64, x86 and x86_64)
+implementation("com.caoccao.javet:javet-android-v8:3.1.0")// Android V8 (arm, arm64, x86 and x86_64)
implementation'com.caoccao.javet:javet:3.0.4'// Linux and Windows (x86_64)
-implementation'com.caoccao.javet:javet-linux-arm64:3.0.4'// Linux (arm64)
-implementation'com.caoccao.javet:javet-macos:3.0.4'// Mac OS (x86_64 and arm64)
-implementation'com.caoccao.javet:javet-android:3.0.4'// Android (arm, arm64, x86 and x86_64)
+
implementation'com.caoccao.javet:javet:3.1.0'// Linux and Windows (x86_64)
+implementation'com.caoccao.javet:javet-linux-arm64:3.1.0'// Linux (arm64)
+implementation'com.caoccao.javet:javet-macos:3.1.0'// Mac OS (x86_64 and arm64)
+implementation'com.caoccao.javet:javet-android-node:3.1.0'// Android Node (arm, arm64, x86 and x86_64)
+implementation'com.caoccao.javet:javet-android-v8:3.1.0'// Android V8 (arm, arm64, x86 and x86_64)
implementation("com.caoccao.javet:javet:3.0.4")// Linux and Windows (x86_64)
-implementation("com.caoccao.javet:javet-linux-arm64:3.0.4")// Linux (arm64)
-implementation("com.caoccao.javet:javet-macos:3.0.4")// Mac OS (x86_64 and arm64)
-implementation("com.caoccao.javet:javet-android:3.0.4")// Android (arm, arm64, x86 and x86_64)
+
implementation("com.caoccao.javet:javet:3.1.0")// Linux and Windows (x86_64)
+implementation("com.caoccao.javet:javet-linux-arm64:3.1.0")// Linux (arm64)
+implementation("com.caoccao.javet:javet-macos:3.1.0")// Mac OS (x86_64 and arm64)
+implementation("com.caoccao.javet:javet-android-node:3.1.0")// Android Node (arm, arm64, x86 and x86_64)
+implementation("com.caoccao.javet:javet-android-v8:3.1.0")// Android V8 (arm, arm64, x86 and x86_64)
implementation'com.caoccao.javet:javet:3.0.4'// Linux and Windows (x86_64)
-implementation'com.caoccao.javet:javet-linux-arm64:3.0.4'// Linux (arm64)
-implementation'com.caoccao.javet:javet-macos:3.0.4'// Mac OS (x86_64 and arm64)
-implementation'com.caoccao.javet:javet-android:3.0.4'// Android (arm, arm64, x86 and x86_64)
+
implementation'com.caoccao.javet:javet:3.1.0'// Linux and Windows (x86_64)
+implementation'com.caoccao.javet:javet-linux-arm64:3.1.0'// Linux (arm64)
+implementation'com.caoccao.javet:javet-macos:3.1.0'// Mac OS (x86_64 and arm64)
+implementation'com.caoccao.javet:javet-android-node:3.1.0'// Android Node (arm, arm64, x86 and x86_64)
+implementation'com.caoccao.javet:javet-android-v8:3.1.0'// Android V8 (arm, arm64, x86 and x86_64)
Only V8 mode is supported for Android. Supporting Node.js mode implies huge amount of work, but is not mission impossible. Please contact the maintainer for details.
-
If you need Node.js features on Android, please refer to project Javenode.
-
+
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 15de90249..a59520664 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/scripts/node/javet-rebuild/rebuild.cmd b/scripts/node/javet-rebuild/rebuild.cmd
index 1b6eac1fd..f78c65f5a 100644
--- a/scripts/node/javet-rebuild/rebuild.cmd
+++ b/scripts/node/javet-rebuild/rebuild.cmd
@@ -1,5 +1,5 @@
@echo off
-SET NODE_LIB_FILE="..\..\..\..\..\..\build\libs\libjavet-node-windows-x86_64.v.3.0.4.lib"
+SET NODE_LIB_FILE="..\..\..\..\..\..\build\libs\libjavet-node-windows-x86_64.v.3.1.0.lib"
cd %NODE_MODULE_ROOT%
call node-gyp clean
call node-gyp configure --module_name=%NODE_MODULE_NAME% --module_path=%NODE_MODULE_PATH% --node_lib_file=%NODE_LIB_FILE%
diff --git a/scripts/node/javet-rebuild/rebuild.sh b/scripts/node/javet-rebuild/rebuild.sh
index 973371a4f..d9e14ce3a 100755
--- a/scripts/node/javet-rebuild/rebuild.sh
+++ b/scripts/node/javet-rebuild/rebuild.sh
@@ -1 +1 @@
-patchelf --add-needed libjavet-node-linux-x86_64.v.3.0.4.so ${NODE_MODULE_FILE}
+patchelf --add-needed libjavet-node-linux-x86_64.v.3.1.0.so ${NODE_MODULE_FILE}
diff --git a/scripts/patches/android/node/android_configure.py.patch b/scripts/patches/android/node/android_configure.py.patch
new file mode 100644
index 000000000..c8fb82c99
--- /dev/null
+++ b/scripts/patches/android/node/android_configure.py.patch
@@ -0,0 +1,23 @@
+diff --git a/android_configure.py b/android_configure.py
+index a82bb56bc5..94b3b7d51c 100644
+--- a/android_configure.py
++++ b/android_configure.py
+@@ -65,13 +65,16 @@ elif platform.system() == "Linux":
+ os.environ['PATH'] += os.pathsep + toolchain_path + "/bin"
+ os.environ['CC'] = toolchain_path + "/bin/" + TOOLCHAIN_PREFIX + android_sdk_version + "-" + "clang"
+ os.environ['CXX'] = toolchain_path + "/bin/" + TOOLCHAIN_PREFIX + android_sdk_version + "-" + "clang++"
++import shutil
++os.environ['CC_host'] = shutil.which("gcc")
++os.environ['CXX_host'] = shutil.which("g++")
+
+ GYP_DEFINES = "target_arch=" + arch
+-GYP_DEFINES += " v8_target_arch=" + arch
++GYP_DEFINES += " v8_target_arch=" + DEST_CPU
+ GYP_DEFINES += " android_target_arch=" + arch
+ GYP_DEFINES += " host_os=" + host_os + " OS=android"
+ GYP_DEFINES += " android_ndk_path=" + android_ndk_path
+ os.environ['GYP_DEFINES'] = GYP_DEFINES
+
+ if os.path.exists("./configure"):
+- os.system("./configure --dest-cpu=" + DEST_CPU + " --dest-os=android --openssl-no-asm --cross-compiling")
++ os.system("./configure --dest-cpu=" + DEST_CPU + " --dest-os=android --openssl-no-asm --cross-compiling --enable-static --with-intl=none")
diff --git a/scripts/patches/android/node/common.gypi.patch b/scripts/patches/android/node/common.gypi.patch
new file mode 100644
index 000000000..aae876e94
--- /dev/null
+++ b/scripts/patches/android/node/common.gypi.patch
@@ -0,0 +1,13 @@
+diff --git a/common.gypi b/common.gypi
+index db09a8a33d..2660cbaa5c 100644
+--- a/common.gypi
++++ b/common.gypi
+@@ -444,7 +444,7 @@
+ 'ldflags': [ '-rdynamic' ],
+ 'target_conditions': [
+ # The 1990s toolchain on SmartOS can't handle thin archives.
+- ['_type=="static_library" and OS=="solaris"', {
++ ['_type=="static_library"', {
+ 'standalone_static_library': 1,
+ }],
+ ['OS=="openbsd"', {
diff --git a/scripts/patches/android/node/configure.py.patch b/scripts/patches/android/node/configure.py.patch
new file mode 100644
index 000000000..54a1f1b10
--- /dev/null
+++ b/scripts/patches/android/node/configure.py.patch
@@ -0,0 +1,14 @@
+diff --git a/configure.py b/configure.py
+index 84b016cd85..48d645209a 100755
+--- a/configure.py
++++ b/configure.py
+@@ -1275,8 +1275,7 @@ def configure_node(o):
+
+ # Enable branch protection for arm64
+ if target_arch == 'arm64':
+- o['cflags']+=['-msign-return-address=all']
+- o['variables']['arm_fpu'] = options.arm_fpu or 'neon'
++ pass
+
+ if options.node_snapshot_main is not None:
+ if options.shared:
diff --git a/scripts/patches/android/node/constants-arm.h.patch b/scripts/patches/android/node/constants-arm.h.patch
new file mode 100644
index 000000000..fdcf4ee72
--- /dev/null
+++ b/scripts/patches/android/node/constants-arm.h.patch
@@ -0,0 +1,18 @@
+diff --git a/deps/v8/src/codegen/arm/constants-arm.h b/deps/v8/src/codegen/arm/constants-arm.h
+index 5b8636d3b9..ff6dea9a58 100644
+--- a/deps/v8/src/codegen/arm/constants-arm.h
++++ b/deps/v8/src/codegen/arm/constants-arm.h
+@@ -179,7 +179,13 @@ constexpr int U = 1 << 23; // Positive (or negative) offset/index.
+ constexpr int P =
+ 1 << 24; // Offset/pre-indexed addressing (or post-indexed addressing).
+ constexpr int I = 1 << 25; // Immediate shifter operand (or not).
++#ifdef B0
++#undef B0
++// ensure safe undef
++#define B0 undefined
++#else
+ constexpr int B0 = 1 << 0;
++#endif
+ constexpr int B4 = 1 << 4;
+ constexpr int B5 = 1 << 5;
+ constexpr int B6 = 1 << 6;
diff --git a/scripts/patches/android/node/push_registers_asm.cc.patch b/scripts/patches/android/node/push_registers_asm.cc.patch
new file mode 100644
index 000000000..1d6141c09
--- /dev/null
+++ b/scripts/patches/android/node/push_registers_asm.cc.patch
@@ -0,0 +1,52 @@
+diff --git a/deps/v8/src/heap/base/asm/x64/push_registers_asm.cc b/deps/v8/src/heap/base/asm/x64/push_registers_asm.cc
+index 1781a5816a..0a2889d04d 100644
+--- a/deps/v8/src/heap/base/asm/x64/push_registers_asm.cc
++++ b/deps/v8/src/heap/base/asm/x64/push_registers_asm.cc
+@@ -16,6 +16,7 @@
+ // GN toolchain (e.g. ChromeOS) and not provide them.
+ // _WIN64 Defined as 1 when the compilation target is 64-bit ARM or x64.
+ // Otherwise, undefined.
++#if defined(V8_TARGET_ARCH_ARM64) || defined(V8_TARGET_ARCH_X64)
+ #ifdef _WIN64
+
+ // We maintain 16-byte alignment at calls. There is an 8-byte return address
+@@ -104,3 +105,39 @@ asm(
+ " ret \n");
+
+ #endif // !_WIN64
++#else
++asm(
++#ifdef _WIN32
++ ".globl _PushAllRegistersAndIterateStack \n"
++ "_PushAllRegistersAndIterateStack: \n"
++#else // !_WIN32
++ ".globl PushAllRegistersAndIterateStack \n"
++ ".type PushAllRegistersAndIterateStack, %function \n"
++ ".hidden PushAllRegistersAndIterateStack \n"
++ "PushAllRegistersAndIterateStack: \n"
++#endif // !_WIN32
++ // [ IterateStackCallback ]
++ // [ StackVisitor* ]
++ // [ Stack* ]
++ // [ ret ]
++ // ebp is callee-saved. Maintain proper frame pointer for debugging.
++ " push %ebp \n"
++ " movl %esp, %ebp \n"
++ " push %ebx \n"
++ " push %esi \n"
++ " push %edi \n"
++ // Save 3rd parameter (IterateStackCallback).
++ " movl 28(%esp), %ecx \n"
++ // Pass 3rd parameter as esp (stack pointer).
++ " push %esp \n"
++ // Pass 2nd parameter (StackVisitor*).
++ " push 28(%esp) \n"
++ // Pass 1st parameter (Stack*).
++ " push 28(%esp) \n"
++ " call *%ecx \n"
++ // Pop the callee-saved registers.
++ " addl $24, %esp \n"
++ // Restore rbp as it was used as frame pointer.
++ " pop %ebp \n"
++ " ret \n");
++#endif
diff --git a/scripts/patches/android/node/test_crypto_clienthello.cc.patch b/scripts/patches/android/node/test_crypto_clienthello.cc.patch
new file mode 100644
index 000000000..ed7e9c7e7
--- /dev/null
+++ b/scripts/patches/android/node/test_crypto_clienthello.cc.patch
@@ -0,0 +1,96 @@
+diff --git a/test/cctest/test_crypto_clienthello.cc b/test/cctest/test_crypto_clienthello.cc
+index 870857cf90..1a5f7aaf15 100644
+--- a/test/cctest/test_crypto_clienthello.cc
++++ b/test/cctest/test_crypto_clienthello.cc
+@@ -43,91 +43,7 @@ size_t GetPageSize() {
+ }
+ #endif
+
+-template
+-class OverrunGuardedBuffer {
+- public:
+- OverrunGuardedBuffer() {
+-#if defined(USE_MPROTECT) || defined(USE_VIRTUALPROTECT)
+- size_t page = GetPageSize();
+- CHECK_GE(page, N);
+-#endif
+-#ifdef USE_MPROTECT
+- // Place the packet right before a guard page, which, when accessed, causes
+- // a segmentation fault.
+- alloc_base = static_cast(aligned_alloc(page, 2 * page));
+- CHECK_NOT_NULL(alloc_base);
+- uint8_t* second_page = alloc_base + page;
+- CHECK_EQ(mprotect(second_page, page, PROT_NONE), 0);
+- data_base = second_page - N;
+-#elif defined(USE_VIRTUALPROTECT)
+- // On Windows, it works almost the same way.
+- alloc_base = static_cast(
+- VirtualAlloc(nullptr, 2 * page, MEM_COMMIT, PAGE_READWRITE));
+- CHECK_NOT_NULL(alloc_base);
+- uint8_t* second_page = alloc_base + page;
+- DWORD old_prot;
+- CHECK_NE(VirtualProtect(second_page, page, PAGE_NOACCESS, &old_prot), 0);
+- CHECK_EQ(old_prot, PAGE_READWRITE);
+- data_base = second_page - N;
+-#else
+- // Place the packet in a regular allocated buffer. The bug causes undefined
+- // behavior, which might crash the process, and when it does not, address
+- // sanitizers and valgrind will catch it.
+- alloc_base = static_cast(malloc(N));
+- CHECK_NOT_NULL(alloc_base);
+- data_base = alloc_base;
+-#endif
+- }
+-
+- OverrunGuardedBuffer(const OverrunGuardedBuffer& other) = delete;
+- OverrunGuardedBuffer& operator=(const OverrunGuardedBuffer& other) = delete;
+-
+- ~OverrunGuardedBuffer() {
+-#if defined(USE_MPROTECT) || defined(USE_VIRTUALPROTECT)
+- size_t page = GetPageSize();
+-#endif
+-#ifdef USE_VIRTUALPROTECT
+- VirtualFree(alloc_base, 2 * page, MEM_RELEASE);
+-#else
+-#ifdef USE_MPROTECT
+- // Revert page protection such that the memory can be free()'d.
+- uint8_t* second_page = alloc_base + page;
+- CHECK_EQ(mprotect(second_page, page, PROT_READ | PROT_WRITE), 0);
+-#endif
+- free(alloc_base);
+-#endif
+- }
+-
+- uint8_t* data() {
+- return data_base;
+- }
+-
+- private:
+- uint8_t* alloc_base;
+- uint8_t* data_base;
+-};
+-
+ // Test that ClientHelloParser::ParseHeader() does not blindly trust the client
+ // to send a valid frame length and subsequently does not read out-of-bounds.
+ TEST(NodeCrypto, ClientHelloParserParseHeaderOutOfBoundsRead) {
+- using node::crypto::ClientHelloParser;
+-
+- // This is the simplest packet triggering the bug.
+- const uint8_t packet[] = {0x16, 0x03, 0x01, 0x00, 0x00};
+- OverrunGuardedBuffer buffer;
+- memcpy(buffer.data(), packet, sizeof(packet));
+-
+- // Let the ClientHelloParser parse the packet. This should not lead to a
+- // segmentation fault or to undefined behavior.
+- node::crypto::ClientHelloParser parser;
+- bool end_cb_called = false;
+- parser.Start([](void* arg, auto hello) { GTEST_FAIL(); },
+- [](void* arg) {
+- bool* end_cb_called = static_cast(arg);
+- EXPECT_FALSE(*end_cb_called);
+- *end_cb_called = true;
+- },
+- &end_cb_called);
+- parser.Parse(buffer.data(), sizeof(packet));
+- EXPECT_TRUE(end_cb_called);
+ }
diff --git a/scripts/patches/android/node/trap-handler.h.patch b/scripts/patches/android/node/trap-handler.h.patch
new file mode 100644
index 000000000..64ef38bfb
--- /dev/null
+++ b/scripts/patches/android/node/trap-handler.h.patch
@@ -0,0 +1,34 @@
+diff --git a/deps/v8/src/trap-handler/trap-handler.h b/deps/v8/src/trap-handler/trap-handler.h
+index 77b0b19aa3..c25b90f27f 100644
+--- a/deps/v8/src/trap-handler/trap-handler.h
++++ b/deps/v8/src/trap-handler/trap-handler.h
+@@ -17,29 +17,7 @@ namespace v8 {
+ namespace internal {
+ namespace trap_handler {
+
+-// X64 on Linux, Windows, MacOS, FreeBSD.
+-#if V8_HOST_ARCH_X64 && V8_TARGET_ARCH_X64 && \
+- ((V8_OS_LINUX && !V8_OS_ANDROID) || V8_OS_WIN || V8_OS_DARWIN || \
+- V8_OS_FREEBSD)
+-#define V8_TRAP_HANDLER_SUPPORTED true
+-// Arm64 (non-simulator) on Mac.
+-#elif V8_TARGET_ARCH_ARM64 && V8_HOST_ARCH_ARM64 && V8_OS_DARWIN
+-#define V8_TRAP_HANDLER_SUPPORTED true
+-// Arm64 simulator on x64 on Linux, Mac, or Windows.
+-//
+-// The simulator case uses some inline assembly code, which cannot be
+-// compiled with MSVC, so don't enable the trap handler in that case.
+-// (MSVC #defines _MSC_VER, but so does Clang when targeting Windows, hence
+-// the check for __clang__.)
+-#elif V8_TARGET_ARCH_ARM64 && V8_HOST_ARCH_X64 && \
+- (V8_OS_LINUX || V8_OS_DARWIN || V8_OS_WIN) && \
+- (!defined(_MSC_VER) || defined(__clang__))
+-#define V8_TRAP_HANDLER_VIA_SIMULATOR
+-#define V8_TRAP_HANDLER_SUPPORTED true
+-// Everything else is unsupported.
+-#else
+ #define V8_TRAP_HANDLER_SUPPORTED false
+-#endif
+
+ #if V8_OS_ANDROID && V8_TRAP_HANDLER_SUPPORTED
+ // It would require some careful security review before the trap handler
diff --git a/scripts/python/change_javet_version.py b/scripts/python/change_javet_version.py
index 75c92a2e3..6bec4d834 100644
--- a/scripts/python/change_javet_version.py
+++ b/scripts/python/change_javet_version.py
@@ -180,7 +180,7 @@ def _update(self, relative_file_path: str, line_separator: str, *patterns: list)
logging.info(' Updated.')
def main():
- change_javet_version = ChangeJavetVersion('3.0.4')
+ change_javet_version = ChangeJavetVersion('3.1.0')
change_javet_version.update()
return 0
diff --git a/scripts/python/change_node_v8_version.py b/scripts/python/change_node_v8_version.py
index 45beaf34c..cd0ae3c82 100644
--- a/scripts/python/change_node_v8_version.py
+++ b/scripts/python/change_node_v8_version.py
@@ -75,7 +75,7 @@ def update(self) -> None:
'README.rst', '\n',
re.compile(r'Node\.js ``v(?P\d+\.\d+\.\d+)``'))
self._update(
- '.github/workflows/android_build.yml', '\n',
+ '.github/workflows/android_node_build.yml', '\n',
re.compile(r'JAVET_NODE_VERSION: (?P\d+\.\d+\.\d+)$'))
self._update(
'.github/workflows/linux_x86_64_build.yml', '\n',
@@ -116,7 +116,7 @@ def update(self) -> None:
'README.rst', '\n',
re.compile(r'V8 ``v(?P\d+\.\d+\.\d+\.\d+)``'))
self._update(
- '.github/workflows/android_build.yml', '\n',
+ '.github/workflows/android_v8_build.yml', '\n',
re.compile(r'JAVET_V8_VERSION: (?P\d+\.\d+\.\d+\.\d+)$'))
self._update(
'.github/workflows/linux_x86_64_build.yml', '\n',
@@ -160,7 +160,7 @@ def update(self) -> None:
def main():
change_node_version = ChangeNodeVersion('20.11.1')
change_node_version.update()
- change_v8_version = ChangeV8Version('12.2.281.16')
+ change_v8_version = ChangeV8Version('12.3.219.10')
change_v8_version.update()
return 0
diff --git a/src/main/java/com/caoccao/javet/enums/JSRuntimeType.java b/src/main/java/com/caoccao/javet/enums/JSRuntimeType.java
index 40f1f877a..20071754c 100644
--- a/src/main/java/com/caoccao/javet/enums/JSRuntimeType.java
+++ b/src/main/java/com/caoccao/javet/enums/JSRuntimeType.java
@@ -47,7 +47,7 @@ public enum JSRuntimeType {
*/
V8(
"v8",
- "12.2.281.16",
+ "12.3.219.10",
V8RuntimeOptions::new,
o -> o instanceof V8RuntimeOptions);
diff --git a/src/main/java/com/caoccao/javet/exceptions/JavetScriptingError.java b/src/main/java/com/caoccao/javet/exceptions/JavetScriptingError.java
index 19e1a9a89..1300b367f 100644
--- a/src/main/java/com/caoccao/javet/exceptions/JavetScriptingError.java
+++ b/src/main/java/com/caoccao/javet/exceptions/JavetScriptingError.java
@@ -18,6 +18,7 @@
import com.caoccao.javet.interfaces.IJavetEntityError;
import com.caoccao.javet.interop.converters.JavetObjectConverter;
+import com.caoccao.javet.utils.StringUtils;
import com.caoccao.javet.values.V8Value;
import java.util.Map;
@@ -96,6 +97,27 @@ public final class JavetScriptingError {
this.startPosition = startPosition;
}
+ /**
+ * Instantiates a new Javet scripting error.
+ *
+ * @param message the message
+ * @param detailedMessage the detailed message
+ * @param stack the stack
+ * @since 3.1.0
+ */
+ public JavetScriptingError(String message, String detailedMessage, String stack) {
+ this.detailedMessage = detailedMessage;
+ this.endColumn = 0;
+ this.endPosition = 0;
+ this.lineNumber = 0;
+ this.message = message;
+ this.resourceName = StringUtils.EMPTY;
+ this.sourceLine = StringUtils.EMPTY;
+ this.stack = stack;
+ this.startColumn = 0;
+ this.startPosition = 0;
+ }
+
/**
* Gets context.
*
diff --git a/src/main/java/com/caoccao/javet/exceptions/V8ErrorTemplate.java b/src/main/java/com/caoccao/javet/exceptions/V8ErrorTemplate.java
index 020eefe54..31ff1a913 100644
--- a/src/main/java/com/caoccao/javet/exceptions/V8ErrorTemplate.java
+++ b/src/main/java/com/caoccao/javet/exceptions/V8ErrorTemplate.java
@@ -73,6 +73,17 @@ public static String typeErrorReduceOfEmptyArrayWithNoInitialValue() {
return "Reduce of empty array with no initial value";
}
+ /**
+ * TypeError: ${value} is not a function.
+ *
+ * @param functionName the function name
+ * @return the message
+ * @since 3.1.0
+ */
+ public static String typeErrorValueIsNotAFunction(String functionName) {
+ return Objects.requireNonNull(functionName) + " is not a function";
+ }
+
/**
* TypeError: ${value} is not a function.
*
@@ -81,6 +92,6 @@ public static String typeErrorReduceOfEmptyArrayWithNoInitialValue() {
* @since 3.0.4
*/
public static String typeErrorValueIsNotAFunction(V8Value v8Value) {
- return V8ValueUtils.asString(v8Value) + " is not a function";
+ return typeErrorValueIsNotAFunction(V8ValueUtils.asString(v8Value));
}
}
diff --git a/src/main/java/com/caoccao/javet/interop/IV8Native.java b/src/main/java/com/caoccao/javet/interop/IV8Native.java
index d344f6aed..334b0deaa 100644
--- a/src/main/java/com/caoccao/javet/interop/IV8Native.java
+++ b/src/main/java/com/caoccao/javet/interop/IV8Native.java
@@ -230,8 +230,12 @@ Object moduleExecute(
Object moduleGetException(long v8RuntimeHandle, long v8ValueHandle, int v8ValueType);
+ int moduleGetIdentityHash(long v8RuntimeHandle, long v8ValueHandle, int v8ValueType);
+
Object moduleGetNamespace(long v8RuntimeHandle, long v8ValueHandle, int v8ValueType);
+ String moduleGetResourceName(long v8RuntimeHandle, long v8ValueHandle, int v8ValueType);
+
int moduleGetScriptId(long v8RuntimeHandle, long v8ValueHandle, int v8ValueType);
int moduleGetStatus(long v8RuntimeHandle, long v8ValueHandle, int v8ValueType);
@@ -376,6 +380,8 @@ Object scriptExecute(
byte[] scriptGetCachedData(long v8RuntimeHandle, long v8ValueHandle, int v8ValueType);
+ String scriptGetResourceName(long v8RuntimeHandle, long v8ValueHandle, int v8ValueType);
+
Object scriptRun(long v8RuntimeHandle, long v8ValueHandle, int v8ValueType, boolean resultRequired);
void setAdd(long v8RuntimeHandle, long v8ValueHandle, int v8ValueType, Object value);
diff --git a/src/main/java/com/caoccao/javet/interop/JavetClassLoader.java b/src/main/java/com/caoccao/javet/interop/JavetClassLoader.java
index 38012816f..db3c6822a 100644
--- a/src/main/java/com/caoccao/javet/interop/JavetClassLoader.java
+++ b/src/main/java/com/caoccao/javet/interop/JavetClassLoader.java
@@ -30,27 +30,42 @@
import java.lang.reflect.Constructor;
import java.util.Objects;
-class JavetClassLoader extends ClassLoader {
- protected static final String ERROR_NODE_JS_IS_NOT_SUPPORTED_ON_ANDROID = "Node.js is not supported on Android.";
- protected static final String JAVET_LIB_LOADER_CLASS_NAME = JavetLibLoader.class.getName();
- protected static final String METHOD_LOAD = "load";
- protected static final String METHOD_SET_LIB_LOADING_LISTENER = "setLibLoadingListener";
- protected static final String NODE_NATIVE_CLASS_NAME = NodeNative.class.getName();
- protected static final String V8_NATIVE_CLASS_NAME = V8Native.class.getName();
- protected JSRuntimeType jsRuntimeType;
+/**
+ * The type Javet class loader.
+ *
+ * @since 0.8.0
+ */
+final class JavetClassLoader extends ClassLoader {
+ private static final String JAVET_LIB_LOADER_CLASS_NAME = JavetLibLoader.class.getName();
+ private static final String METHOD_LOAD = "load";
+ private static final String METHOD_SET_LIB_LOADING_LISTENER = "setLibLoadingListener";
+ private static final String NODE_NATIVE_CLASS_NAME = NodeNative.class.getName();
+ private static final String V8_NATIVE_CLASS_NAME = V8Native.class.getName();
+ private final JSRuntimeType jsRuntimeType;
+ /**
+ * Instantiates a new Javet class loader.
+ *
+ * @param parent the parent
+ * @param jsRuntimeType the js runtime type
+ * @since 0.8.0
+ */
JavetClassLoader(ClassLoader parent, JSRuntimeType jsRuntimeType) {
super(parent);
- Objects.requireNonNull(jsRuntimeType);
- this.jsRuntimeType = jsRuntimeType;
+ this.jsRuntimeType = Objects.requireNonNull(jsRuntimeType);
}
+ /**
+ * Gets the V8 native interface.
+ *
+ * @return the V8 native interface
+ * @throws JavetException the javet exception
+ * @since 0.8.0
+ */
IV8Native getNative() throws JavetException {
if (JavetOSUtils.IS_ANDROID) {
if (jsRuntimeType.isNode()) {
- throw new JavetException(
- JavetError.LibraryNotLoaded,
- SimpleMap.of(JavetError.PARAMETER_REASON, ERROR_NODE_JS_IS_NOT_SUPPORTED_ON_ANDROID));
+ return new NodeNative();
}
return new V8Native();
} else {
@@ -69,13 +84,14 @@ IV8Native getNative() throws JavetException {
}
}
+ /**
+ * Load the library.
+ *
+ * @throws JavetException the javet exception
+ * @since 0.8.0
+ */
void load() throws JavetException {
if (JavetOSUtils.IS_ANDROID) {
- if (jsRuntimeType.isNode()) {
- throw new JavetException(
- JavetError.LibraryNotLoaded,
- SimpleMap.of(JavetError.PARAMETER_REASON, ERROR_NODE_JS_IS_NOT_SUPPORTED_ON_ANDROID));
- }
JavetLibLoader javetLibLoader = new JavetLibLoader(jsRuntimeType);
javetLibLoader.load();
} else {
diff --git a/src/main/java/com/caoccao/javet/interop/V8Internal.java b/src/main/java/com/caoccao/javet/interop/V8Internal.java
index c4727afed..66c38d2bb 100644
--- a/src/main/java/com/caoccao/javet/interop/V8Internal.java
+++ b/src/main/java/com/caoccao/javet/interop/V8Internal.java
@@ -323,11 +323,19 @@ public V8ValueError moduleGetException(IV8Module iV8Module) throws JavetExceptio
return v8Runtime.moduleGetException(iV8Module);
}
+ public int moduleGetIdentityHash(IV8Module iV8Module) throws JavetException {
+ return v8Runtime.moduleGetIdentityHash(iV8Module);
+ }
+
@CheckReturnValue
- public V8ValueObject moduleGetNamespace(IV8Module iV8Module) throws JavetException {
+ public V8Value moduleGetNamespace(IV8Module iV8Module) throws JavetException {
return v8Runtime.moduleGetNamespace(iV8Module);
}
+ public String moduleGetResourceName(IV8Module iV8Module) throws JavetException {
+ return v8Runtime.moduleGetResourceName(iV8Module);
+ }
+
public int moduleGetScriptId(IV8Module iV8Module) throws JavetException {
return v8Runtime.moduleGetScriptId(iV8Module);
}
@@ -584,6 +592,10 @@ public byte[] scriptGetCachedData(IV8Script iV8Script) throws JavetException {
return v8Runtime.scriptGetCachedData(iV8Script);
}
+ public String scriptGetResourceName(IV8Script iV8Script) throws JavetException {
+ return v8Runtime.scriptGetResourceName(iV8Script);
+ }
+
public T scriptRun(
IV8Script iV8Script, boolean resultRequired) throws JavetException {
return v8Runtime.scriptRun(iV8Script, resultRequired);
diff --git a/src/main/java/com/caoccao/javet/interop/V8Native.java b/src/main/java/com/caoccao/javet/interop/V8Native.java
index 3899d2cfa..bb0d6488e 100644
--- a/src/main/java/com/caoccao/javet/interop/V8Native.java
+++ b/src/main/java/com/caoccao/javet/interop/V8Native.java
@@ -341,9 +341,15 @@ public native Object moduleExecute(
@Override
public native Object moduleGetException(long v8RuntimeHandle, long v8ValueHandle, int v8ValueType);
+ @Override
+ public native int moduleGetIdentityHash(long v8RuntimeHandle, long v8ValueHandle, int v8ValueType);
+
@Override
public native Object moduleGetNamespace(long v8RuntimeHandle, long v8ValueHandle, int v8ValueType);
+ @Override
+ public native String moduleGetResourceName(long v8RuntimeHandle, long v8ValueHandle, int v8ValueType);
+
@Override
public native int moduleGetScriptId(long v8RuntimeHandle, long v8ValueHandle, int v8ValueType);
@@ -570,6 +576,9 @@ public native Object scriptExecute(
@Override
public native byte[] scriptGetCachedData(long v8RuntimeHandle, long v8ValueHandle, int v8ValueType);
+ @Override
+ public native String scriptGetResourceName(long v8RuntimeHandle, long v8ValueHandle, int v8ValueType);
+
@Override
public native Object scriptRun(long v8RuntimeHandle, long v8ValueHandle, int v8ValueType, boolean resultRequired);
diff --git a/src/main/java/com/caoccao/javet/interop/V8Runtime.java b/src/main/java/com/caoccao/javet/interop/V8Runtime.java
index 45d270fba..acd57f469 100644
--- a/src/main/java/com/caoccao/javet/interop/V8Runtime.java
+++ b/src/main/java/com/caoccao/javet/interop/V8Runtime.java
@@ -18,8 +18,7 @@
import com.caoccao.javet.annotations.CheckReturnValue;
import com.caoccao.javet.enums.*;
-import com.caoccao.javet.exceptions.JavetError;
-import com.caoccao.javet.exceptions.JavetException;
+import com.caoccao.javet.exceptions.*;
import com.caoccao.javet.interfaces.IEnumBitset;
import com.caoccao.javet.interfaces.IJavetClosable;
import com.caoccao.javet.interfaces.IJavetLogger;
@@ -620,7 +619,6 @@ public V8Module compileV8Module(
V8Module v8Module = null;
if (resultRequired && result instanceof V8Module) {
v8Module = (V8Module) result;
- v8Module.setResourceName(v8ScriptOrigin.getResourceName());
addV8Module(v8Module);
}
return v8Module;
@@ -778,7 +776,6 @@ public V8Module createV8Module(String moduleName, IV8ValueObject iV8ValueObject)
V8Module v8Module = (V8Module) v8Native.moduleCreate(
handle, moduleName, iV8ValueObject.getHandle(), iV8ValueObject.getType().getId());
if (v8Module != null) {
- v8Module.setResourceName(moduleName);
addV8Module(v8Module);
}
return v8Module;
@@ -2178,6 +2175,18 @@ V8ValueError moduleGetException(IV8Module iV8Module) throws JavetException {
handle, iV8Module.getHandle(), iV8Module.getType().getId());
}
+ /**
+ * Gets an idendity hash from a module
+ *
+ * @param iV8Module the V8 module
+ * @return the identity hash
+ * @throws JavetException the javet exception
+ */
+ @SuppressWarnings("RedundantThrows")
+ int moduleGetIdentityHash(IV8Module iV8Module) throws JavetException {
+ return v8Native.moduleGetIdentityHash(handle, iV8Module.getHandle(), iV8Module.getType().getId());
+ }
+
/**
* Gets the namespace from a module.
*
@@ -2188,11 +2197,23 @@ V8ValueError moduleGetException(IV8Module iV8Module) throws JavetException {
*/
@SuppressWarnings("RedundantThrows")
@CheckReturnValue
- V8ValueObject moduleGetNamespace(IV8Module iV8Module) throws JavetException {
- return (V8ValueObject) v8Native.moduleGetNamespace(
+ V8Value moduleGetNamespace(IV8Module iV8Module) throws JavetException {
+ return (V8Value) v8Native.moduleGetNamespace(
handle, iV8Module.getHandle(), iV8Module.getType().getId());
}
+ /**
+ * Gets the resource name from a module.
+ *
+ * @param iV8Module the V8 module
+ * @return the resource name
+ * @throws JavetException the javet exception
+ * @since 3.1.0
+ */
+ String moduleGetResourceName(IV8Module iV8Module) throws JavetException {
+ return v8Native.moduleGetResourceName(handle, iV8Module.getHandle(), iV8Module.getType().getId());
+ }
+
/**
* Gets the script ID from a module.
*
@@ -2551,8 +2572,21 @@ boolean objectHasPrivateProperty(IV8ValueObject iV8ValueObject, String propertyN
T objectInvoke(
IV8ValueObject iV8ValueObject, String functionName, boolean returnResult, V8Value... v8Values)
throws JavetException {
- return (T) v8Native.objectInvoke(
- handle, iV8ValueObject.getHandle(), iV8ValueObject.getType().getId(), functionName, returnResult, v8Values);
+ Object result = v8Native.objectInvoke(
+ handle,
+ iV8ValueObject.getHandle(),
+ iV8ValueObject.getType().getId(),
+ functionName,
+ returnResult,
+ v8Values);
+ if (result == null) {
+ String message = MessageFormat.format(
+ "{0}: {1}",
+ V8ValueErrorType.TypeError.getName(),
+ V8ErrorTemplate.typeErrorValueIsNotAFunction(functionName));
+ throw new JavetExecutionException(new JavetScriptingError(message, message, null), null);
+ }
+ return (T) result;
}
/**
@@ -3339,6 +3373,19 @@ byte[] scriptGetCachedData(IV8Script iV8Script) throws JavetException {
return v8Native.scriptGetCachedData(handle, iV8Script.getHandle(), iV8Script.getType().getId());
}
+ /**
+ * Get resource name from a script.
+ *
+ * @param iV8Script the V8 script
+ * @return the resource name
+ * @throws JavetException the javet exception
+ * @since 3.1.0
+ */
+ @SuppressWarnings("RedundantThrows")
+ String scriptGetResourceName(IV8Script iV8Script) throws JavetException {
+ return v8Native.scriptGetResourceName(handle, iV8Script.getHandle(), iV8Script.getType().getId());
+ }
+
/**
* Run a script.
*
diff --git a/src/main/java/com/caoccao/javet/interop/callback/JavetBuiltInModuleResolver.java b/src/main/java/com/caoccao/javet/interop/callback/JavetBuiltInModuleResolver.java
index 42f4f6ff0..127c71daa 100644
--- a/src/main/java/com/caoccao/javet/interop/callback/JavetBuiltInModuleResolver.java
+++ b/src/main/java/com/caoccao/javet/interop/callback/JavetBuiltInModuleResolver.java
@@ -21,6 +21,7 @@
import com.caoccao.javet.interop.V8Runtime;
import com.caoccao.javet.node.modules.NodeModuleAny;
import com.caoccao.javet.values.reference.IV8Module;
+import com.caoccao.javet.values.reference.V8ValueObject;
/**
* The type Javet built in module resolver is for resolving the Node.js built-in modules.
@@ -35,6 +36,12 @@ public class JavetBuiltInModuleResolver implements IV8ModuleResolver {
* @since 3.0.1
*/
public static final String PREFIX_NODE = "node:";
+ /**
+ * The constant DEFAULT.
+ *
+ * @since 3.1.0
+ */
+ public static final String DEFAULT = "default";
@Override
public IV8Module resolve(V8Runtime v8Runtime, String resourceName, IV8Module v8ModuleReferrer)
@@ -45,7 +52,11 @@ public IV8Module resolve(V8Runtime v8Runtime, String resourceName, IV8Module v8M
String moduleName = resourceName.substring(PREFIX_NODE.length());
NodeRuntime nodeRuntime = (NodeRuntime) v8Runtime;
NodeModuleAny nodeModuleAny = nodeRuntime.getNodeModule(moduleName, NodeModuleAny.class);
- iV8Module = v8Runtime.createV8Module(resourceName, nodeModuleAny.getModuleObject());
+ V8ValueObject v8ValueObject = nodeModuleAny.getModuleObject();
+ if (!v8ValueObject.has(DEFAULT)) {
+ v8ValueObject.set(DEFAULT, v8ValueObject);
+ }
+ iV8Module = v8Runtime.createV8Module(resourceName, v8ValueObject);
}
return iV8Module;
}
diff --git a/src/main/java/com/caoccao/javet/interop/executors/IV8Executor.java b/src/main/java/com/caoccao/javet/interop/executors/IV8Executor.java
index 3bad1b70f..76a43d299 100644
--- a/src/main/java/com/caoccao/javet/interop/executors/IV8Executor.java
+++ b/src/main/java/com/caoccao/javet/interop/executors/IV8Executor.java
@@ -24,6 +24,7 @@
import com.caoccao.javet.interop.V8ScriptOrigin;
import com.caoccao.javet.node.modules.NodeModuleModule;
import com.caoccao.javet.node.modules.NodeModuleProcess;
+import com.caoccao.javet.utils.JavetOSUtils;
import com.caoccao.javet.values.V8Value;
import com.caoccao.javet.values.reference.V8Module;
import com.caoccao.javet.values.reference.V8Script;
@@ -220,13 +221,15 @@ default IV8Executor setResourceName(String resourceName) throws JavetException {
getV8ScriptOrigin().setResourceName(resourceName);
V8Runtime v8Runtime = getV8Runtime();
if (v8Runtime.getJSRuntimeType().isNode()) {
- NodeRuntime nodeRuntime = (NodeRuntime) v8Runtime;
- File resourceFile = new File(resourceName);
- File parentFile = resourceFile.getParentFile();
- nodeRuntime.getGlobalObject().set(NodeRuntime.PROPERTY_DIRNAME, parentFile.getAbsolutePath());
- nodeRuntime.getGlobalObject().set(NodeRuntime.PROPERTY_FILENAME, resourceFile.getAbsolutePath());
- nodeRuntime.getNodeModule(NodeModuleModule.class).setRequireRootDirectory(parentFile.getAbsoluteFile());
- nodeRuntime.getNodeModule(NodeModuleProcess.class).setWorkingDirectory(parentFile.getAbsolutePath());
+ if (!JavetOSUtils.IS_ANDROID) {
+ NodeRuntime nodeRuntime = (NodeRuntime) v8Runtime;
+ File resourceFile = new File(resourceName);
+ File parentFile = resourceFile.getParentFile();
+ nodeRuntime.getGlobalObject().set(NodeRuntime.PROPERTY_DIRNAME, parentFile.getAbsolutePath());
+ nodeRuntime.getGlobalObject().set(NodeRuntime.PROPERTY_FILENAME, resourceFile.getAbsolutePath());
+ nodeRuntime.getNodeModule(NodeModuleModule.class).setRequireRootDirectory(parentFile.getAbsoluteFile());
+ nodeRuntime.getNodeModule(NodeModuleProcess.class).setWorkingDirectory(parentFile.getAbsolutePath());
+ }
}
return this;
}
diff --git a/src/main/java/com/caoccao/javet/interop/loader/JavetLibLoader.java b/src/main/java/com/caoccao/javet/interop/loader/JavetLibLoader.java
index 42aa02fa1..c5aff5c4a 100644
--- a/src/main/java/com/caoccao/javet/interop/loader/JavetLibLoader.java
+++ b/src/main/java/com/caoccao/javet/interop/loader/JavetLibLoader.java
@@ -20,10 +20,7 @@
import com.caoccao.javet.exceptions.JavetError;
import com.caoccao.javet.exceptions.JavetException;
import com.caoccao.javet.interfaces.IJavetLogger;
-import com.caoccao.javet.utils.JavetDefaultLogger;
-import com.caoccao.javet.utils.JavetOSUtils;
-import com.caoccao.javet.utils.SimpleMap;
-import com.caoccao.javet.utils.StringUtils;
+import com.caoccao.javet.utils.*;
import java.io.File;
import java.io.FileOutputStream;
@@ -48,7 +45,7 @@ public final class JavetLibLoader {
*
* @since 0.8.0
*/
- public static final String LIB_VERSION = "3.0.4";
+ public static final String LIB_VERSION = "3.1.0";
private static final String ANDROID_ABI_ARM = "armeabi-v7a";
private static final String ANDROID_ABI_ARM64 = "arm64-v8a";
private static final String ANDROID_ABI_X86 = "x86";
@@ -346,8 +343,8 @@ public void load() throws JavetException {
}
purge(libPath);
File libFile = new File(rootLibPath, getLibFileName()).getAbsoluteFile();
- deployLibFile(resourceFileName, libFile);
libFilePath = libFile.getAbsolutePath();
+ deployLibFile(resourceFileName, libFile);
} else {
File libPath = libLoadingListener.getLibPath(jsRuntimeType);
Objects.requireNonNull(libPath, "Lib path cannot be null");
@@ -383,7 +380,7 @@ private void purge(File rootLibPath) {
if (rootLibPath.exists()) {
if (rootLibPath.isDirectory()) {
File[] files = rootLibPath.listFiles();
- if (files != null && files.length > 0) {
+ if (ArrayUtils.isNotEmpty(files)) {
for (File libFileOrPath : files) {
if (libFileOrPath.lastModified() + MIN_LAST_MODIFIED_GAP_IN_MILLIS > System.currentTimeMillis()) {
continue;
diff --git a/src/main/java/com/caoccao/javet/values/reference/IV8Module.java b/src/main/java/com/caoccao/javet/values/reference/IV8Module.java
index 4b1653cd9..6f9a3d047 100644
--- a/src/main/java/com/caoccao/javet/values/reference/IV8Module.java
+++ b/src/main/java/com/caoccao/javet/values/reference/IV8Module.java
@@ -116,30 +116,46 @@ default T execute(boolean resultRequired) throws JavetExcept
@CheckReturnValue
V8ValueError getException() throws JavetException;
+ /**
+ * Returns the identity hash for this object. The current implementation
+ * uses an inline property on the object to store the identity hash.
+ *
+ * The return value will never be 0. Also, it is not guaranteed to be
+ * unique.
+ *
+ * @return the identity hash
+ * @throws JavetException the javet exception
+ * @since 3.1.0
+ */
+ int getIdentityHash() throws JavetException;
+
/**
* Gets namespace.
*
- * The module's status must be at least kInstantiated. Otherwise, core dump will take place.
+ * The module's status must be at least kInstantiated.
+ * Otherwise, undefined is returned.
*
* @return the namespace
* @throws JavetException the javet exception
* @since 0.8.0
*/
@CheckReturnValue
- V8ValueObject getNamespace() throws JavetException;
+ V8Value getNamespace() throws JavetException;
/**
* Gets resource name.
*
* @return the resource name
+ * @throws JavetException the javet exception
* @since 0.8.0
*/
- String getResourceName();
+ String getResourceName() throws JavetException;
/**
* Gets script id.
*
* The module must be a SourceTextModule and must not have a kErrored status.
+ * Otherwise, -1 is returned.
*
* @return the script id
* @throws JavetException the javet exception
@@ -183,14 +199,6 @@ default T execute(boolean resultRequired) throws JavetExcept
*/
boolean isSyntheticModule() throws JavetException;
- /**
- * Sets resource name.
- *
- * @param resourceName the resource name
- * @since 0.8.0
- */
- void setResourceName(String resourceName);
-
@Override
default T toObject(V v8Value) throws JavetException {
return getV8Runtime().toObject(v8Value);
diff --git a/src/main/java/com/caoccao/javet/values/reference/IV8Script.java b/src/main/java/com/caoccao/javet/values/reference/IV8Script.java
index 88e516c5d..e6d613b0d 100644
--- a/src/main/java/com/caoccao/javet/values/reference/IV8Script.java
+++ b/src/main/java/com/caoccao/javet/values/reference/IV8Script.java
@@ -33,17 +33,10 @@ public interface IV8Script
* Gets resource name.
*
* @return the resource name
+ * @throws JavetException the javet exception
* @since 0.8.0
*/
- String getResourceName();
-
- /**
- * Sets resource name.
- *
- * @param resourceName the resource name
- * @since 0.8.0
- */
- void setResourceName(String resourceName);
+ String getResourceName() throws JavetException;
@Override
default T toObject(V v8Value) throws JavetException {
diff --git a/src/main/java/com/caoccao/javet/values/reference/V8Module.java b/src/main/java/com/caoccao/javet/values/reference/V8Module.java
index 09d30c876..c8ec45236 100644
--- a/src/main/java/com/caoccao/javet/values/reference/V8Module.java
+++ b/src/main/java/com/caoccao/javet/values/reference/V8Module.java
@@ -22,9 +22,6 @@
import com.caoccao.javet.interop.V8Runtime;
import com.caoccao.javet.values.V8Value;
-import java.util.Objects;
-import java.util.Optional;
-
/**
* The type V8 module.
*
@@ -34,23 +31,23 @@
public class V8Module extends V8ValueReference implements IV8Module {
/**
- * The Optional source text module is an internal cache storing whether the module is source text or not.
+ * The Resource name.
*
- * @since 3.0.1
+ * @since 0.8.0
*/
- protected Optional optionalSourceTextModule;
+ protected String resourceName;
/**
- * The Optional synthetic module is an internal cache storing whether the module is synthetic or not.
+ * The source text module is an internal cache storing whether the module is source text or not.
*
* @since 3.0.1
*/
- protected Optional optionalSyntheticModule;
+ protected Boolean sourceTextModule;
/**
- * The Resource name.
+ * The synthetic module is an internal cache storing whether the module is synthetic or not.
*
- * @since 0.8.0
+ * @since 3.0.1
*/
- protected String resourceName;
+ protected Boolean syntheticModule;
/**
* Instantiates a new V8 module.
@@ -62,8 +59,8 @@ public class V8Module extends V8ValueReference implements IV8Module {
*/
V8Module(V8Runtime v8Runtime, long handle) throws JavetException {
super(v8Runtime, handle);
- optionalSourceTextModule = Optional.empty();
- optionalSyntheticModule = Optional.empty();
+ sourceTextModule = null;
+ syntheticModule = null;
resourceName = null;
}
@@ -84,14 +81,22 @@ public V8ValueError getException() throws JavetException {
return checkV8Runtime().getV8Internal().moduleGetException(this);
}
+ @Override
+ public int getIdentityHash() throws JavetException {
+ return checkV8Runtime().getV8Internal().moduleGetIdentityHash(this);
+ }
+
@Override
@CheckReturnValue
- public V8ValueObject getNamespace() throws JavetException {
+ public V8Value getNamespace() throws JavetException {
return checkV8Runtime().getV8Internal().moduleGetNamespace(this);
}
@Override
- public String getResourceName() {
+ public String getResourceName() throws JavetException {
+ if (resourceName == null) {
+ resourceName = checkV8Runtime().getV8Internal().moduleGetResourceName(this);
+ }
return resourceName;
}
@@ -117,25 +122,18 @@ public boolean instantiate() throws JavetException {
@Override
public boolean isSourceTextModule() throws JavetException {
- if (!optionalSourceTextModule.isPresent()) {
- optionalSourceTextModule =
- Optional.of(checkV8Runtime().getV8Internal().moduleIsSourceTextModule(this));
+ if (sourceTextModule == null) {
+ sourceTextModule = checkV8Runtime().getV8Internal().moduleIsSourceTextModule(this);
}
- return optionalSourceTextModule.get();
+ return sourceTextModule;
}
@Override
public boolean isSyntheticModule() throws JavetException {
- if (!optionalSyntheticModule.isPresent()) {
- optionalSyntheticModule =
- Optional.of(checkV8Runtime().getV8Internal().moduleIsSyntheticModule(this));
+ if (syntheticModule == null) {
+ syntheticModule = checkV8Runtime().getV8Internal().moduleIsSyntheticModule(this);
}
- return optionalSyntheticModule.get();
- }
-
- @Override
- public void setResourceName(String resourceName) {
- this.resourceName = Objects.requireNonNull(resourceName);
+ return syntheticModule;
}
@Override
diff --git a/src/main/java/com/caoccao/javet/values/reference/V8Script.java b/src/main/java/com/caoccao/javet/values/reference/V8Script.java
index 98f35bc34..4ee2ed43a 100644
--- a/src/main/java/com/caoccao/javet/values/reference/V8Script.java
+++ b/src/main/java/com/caoccao/javet/values/reference/V8Script.java
@@ -22,8 +22,6 @@
import com.caoccao.javet.interop.V8Runtime;
import com.caoccao.javet.values.V8Value;
-import java.util.Objects;
-
/**
* The type V8 script.
*
@@ -63,7 +61,10 @@ public byte[] getCachedData() throws JavetException {
}
@Override
- public String getResourceName() {
+ public String getResourceName() throws JavetException {
+ if (resourceName == null) {
+ return checkV8Runtime().getV8Internal().scriptGetResourceName(this);
+ }
return resourceName;
}
@@ -72,12 +73,6 @@ public V8ValueReferenceType getType() {
return V8ValueReferenceType.Script;
}
- @Override
- public void setResourceName(String resourceName) {
- Objects.requireNonNull(resourceName);
- this.resourceName = resourceName;
- }
-
@Override
public V8Script toClone(boolean referenceCopy) throws JavetException {
return this;
diff --git a/src/main/resources/META-INF/MANIFEST.MF b/src/main/resources/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..b2e7a1a2d
--- /dev/null
+++ b/src/main/resources/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Automatic-Module-Name: com.caoccao.javet
+
diff --git a/src/test/java/com/caoccao/javet/mock/MockModuleResolver.java b/src/test/java/com/caoccao/javet/mock/MockModuleResolver.java
index 64427a404..31d750244 100644
--- a/src/test/java/com/caoccao/javet/mock/MockModuleResolver.java
+++ b/src/test/java/com/caoccao/javet/mock/MockModuleResolver.java
@@ -17,8 +17,8 @@
package com.caoccao.javet.mock;
import com.caoccao.javet.exceptions.JavetException;
-import com.caoccao.javet.interop.callback.IV8ModuleResolver;
import com.caoccao.javet.interop.V8Runtime;
+import com.caoccao.javet.interop.callback.IV8ModuleResolver;
import com.caoccao.javet.values.reference.IV8Module;
import java.util.Objects;
diff --git a/src/test/java/com/caoccao/javet/values/reference/TestV8Module.java b/src/test/java/com/caoccao/javet/values/reference/TestV8Module.java
index 59abe9bca..a5aa445cf 100644
--- a/src/test/java/com/caoccao/javet/values/reference/TestV8Module.java
+++ b/src/test/java/com/caoccao/javet/values/reference/TestV8Module.java
@@ -69,18 +69,19 @@ public void testCachedData() throws JavetException {
@Test
public void testExecute() throws JavetException {
- IV8Executor iV8Executor = v8Runtime.getExecutor(
- "Object.a = 1").setResourceName("./test.js");
+ final String moduleName = "./test.js";
+ IV8Executor iV8Executor = v8Runtime.getExecutor("Object.a = 1").setResourceName(moduleName);
try (V8Module v8Module = iV8Executor.compileV8Module()) {
assertTrue(v8Module.isSourceTextModule());
assertFalse(v8Module.isSyntheticModule());
assertEquals(V8Module.Uninstantiated, v8Module.getStatus());
- assertTrue(v8Runtime.containsV8Module(v8Module.getResourceName()));
+ assertEquals(moduleName, v8Module.getResourceName());
+ assertTrue(v8Runtime.containsV8Module(moduleName));
+ assertTrue(v8Module.getIdentityHash() != 0);
assertEquals(1, v8Runtime.getV8ModuleCount());
if (v8Runtime.getJSRuntimeType().isV8()) {
assertTrue(3 <= v8Module.getScriptId() && v8Module.getScriptId() <= 4);
}
- assertEquals("./test.js", v8Module.getResourceName());
try (V8ValuePromise v8ValuePromise = v8Module.execute()) {
assertTrue(v8ValuePromise.isFulfilled());
assertTrue(v8ValuePromise.getResult().isUndefined());
@@ -88,8 +89,9 @@ public void testExecute() throws JavetException {
assertEquals(V8Module.Evaluated, v8Module.getStatus());
assertNull(v8Module.getException());
assertEquals(1, v8Runtime.getExecutor("Object.a").executeInteger());
- try (V8ValueObject v8ValueObject = v8Module.getNamespace()) {
- assertNotNull(v8ValueObject);
+ try (V8Value v8Value = v8Module.getNamespace()) {
+ assertNotNull(v8Value);
+ assertFalse(v8Value.isUndefined());
}
}
}
@@ -215,9 +217,9 @@ public void testImportValidModuleInModule() throws JavetException {
assertTrue(v8ValuePromise.isFulfilled());
assertTrue(v8ValuePromise.getResult().isUndefined());
}
- try (V8ValueObject v8ValueObject = v8Module1.getNamespace()) {
- assertNotNull(v8ValueObject);
- try (V8ValueFunction v8ValueFunction = v8ValueObject.get("test1")) {
+ try (V8Value v8Value = v8Module1.getNamespace()) {
+ assertNotNull(v8Value);
+ try (V8ValueFunction v8ValueFunction = ((V8ValueObject) v8Value).get("test1")) {
assertEquals(codeString1.substring(7), v8ValueFunction.toString());
}
}
@@ -233,9 +235,9 @@ public void testImportValidModuleInModule() throws JavetException {
assertTrue(v8ValuePromise.isFulfilled());
assertTrue(v8ValuePromise.getResult().isUndefined());
}
- try (V8ValueObject v8ValueObject = v8Module2.getNamespace()) {
- assertNotNull(v8ValueObject);
- try (V8ValueFunction v8ValueFunction = v8ValueObject.get("test2")) {
+ try (V8Value v8Value = v8Module2.getNamespace()) {
+ assertNotNull(v8Value);
+ try (V8ValueFunction v8ValueFunction = ((V8ValueObject) v8Value).get("test2")) {
assertEquals(codeString1.substring(7), v8ValueFunction.toString());
}
}
@@ -275,7 +277,19 @@ public void testInvalidModuleResolver() throws JavetException {
}
@Test
- public void testJavetBuiltInModuleResolver() throws JavetException {
+ public void testJavetBuiltInModuleResolverWithDefault() throws JavetException {
+ if (v8Runtime.getJSRuntimeType().isNode()) {
+ v8Runtime.setV8ModuleResolver(new JavetBuiltInModuleResolver());
+ v8Runtime.getExecutor(
+ "import fs from 'node:fs';\n" +
+ "globalThis.a = fs.existsSync('/path-not-found');")
+ .setModule(true).executeVoid();
+ assertFalse(v8Runtime.getGlobalObject().getBoolean("a"));
+ }
+ }
+
+ @Test
+ public void testJavetBuiltInModuleResolverWithoutDefault() throws JavetException {
if (v8Runtime.getJSRuntimeType().isNode()) {
v8Runtime.setV8ModuleResolver(new JavetBuiltInModuleResolver());
v8Runtime.getExecutor(
@@ -313,6 +327,7 @@ public void testStatusConversion() throws JavetException {
@Test
public void testSyntheticModule() throws JavetException {
+ final String moduleName = "test.js";
if (v8Runtime.getJSRuntimeType().isNode()) {
v8Runtime.getExecutor("process.on('unhandledRejection', (reason, promise) => {\n" +
" globalThis.reason = reason.toString();\n" +
@@ -328,7 +343,7 @@ public void testSyntheticModule() throws JavetException {
});
}
v8Runtime.setV8ModuleResolver((v8Runtime, resourceName, v8ModuleReferrer) -> {
- if ("test.js".equals(resourceName)) {
+ if (moduleName.equals(resourceName)) {
try (V8ValueObject v8ValueObject = v8Runtime.createV8ValueObject();
V8ValueArray v8ValueArray = v8Runtime.createV8ValueArray()) {
v8ValueObject.set("a", 1);
@@ -340,9 +355,11 @@ public void testSyntheticModule() throws JavetException {
v8ValueBuiltInObject.freeze(v8ValueObject);
}
v8ValueArray.push(1);
- V8Module v8Module = v8Runtime.createV8Module("test.js", v8ValueObject);
+ V8Module v8Module = v8Runtime.createV8Module(moduleName, v8ValueObject);
assertFalse(v8Module.isSourceTextModule());
assertTrue(v8Module.isSyntheticModule());
+ assertEquals(moduleName, v8Module.getResourceName());
+ assertTrue(v8Module.getIdentityHash() != 0);
return v8Module;
}
}
diff --git a/src/test/java/com/caoccao/javet/values/reference/TestV8Script.java b/src/test/java/com/caoccao/javet/values/reference/TestV8Script.java
index dcbe56400..b3fed3899 100644
--- a/src/test/java/com/caoccao/javet/values/reference/TestV8Script.java
+++ b/src/test/java/com/caoccao/javet/values/reference/TestV8Script.java
@@ -28,19 +28,22 @@ public class TestV8Script extends BaseTestJavetRuntime {
@Test
public void testCachedData() throws JavetException {
String codeString = "1 + 1";
+ String resourceName = "./test.js";
byte[] cachedData;
- IV8Executor iV8Executor = v8Runtime.getExecutor(codeString).setResourceName("./test.js");
+ IV8Executor iV8Executor = v8Runtime.getExecutor(codeString).setResourceName(resourceName);
try (V8Script v8Script = iV8Executor.compileV8Script()) {
assertNotNull(v8Script);
+ assertEquals(resourceName, v8Script.getResourceName());
byte[] initializedCachedData = v8Script.getCachedData();
assertTrue(initializedCachedData != null && initializedCachedData.length > 0);
assertEquals(2, v8Script.executeInteger());
cachedData = initializedCachedData;
}
// Cached is only accepted if the source code matches.
- iV8Executor = v8Runtime.getExecutor(codeString, cachedData).setResourceName("./test.js");
+ iV8Executor = v8Runtime.getExecutor(codeString, cachedData).setResourceName(resourceName);
try (V8Script v8Script = iV8Executor.compileV8Script()) {
assertNotNull(v8Script);
+ assertEquals(resourceName, v8Script.getResourceName());
byte[] uninitializedCachedData = v8Script.getCachedData();
assertTrue(uninitializedCachedData != null && uninitializedCachedData.length > 0);
assertEquals(2, v8Script.executeInteger());
@@ -50,10 +53,12 @@ public void testCachedData() throws JavetException {
@Test
public void testExecute() throws JavetException {
+ String resourceName = "./test.js";
IV8Executor iV8Executor = v8Runtime.getExecutor(
- "const a = 1; a;").setResourceName("./test.js");
+ "const a = 1; a;").setResourceName(resourceName);
try (V8Script v8Script = iV8Executor.compileV8Script()) {
assertNotNull(v8Script);
+ assertEquals(resourceName, v8Script.getResourceName());
assertEquals(1, v8Script.executeInteger());
}
}
diff --git a/src/test/java/com/caoccao/javet/values/reference/TestV8ValueObject.java b/src/test/java/com/caoccao/javet/values/reference/TestV8ValueObject.java
index 0622ec7d2..d20427507 100644
--- a/src/test/java/com/caoccao/javet/values/reference/TestV8ValueObject.java
+++ b/src/test/java/com/caoccao/javet/values/reference/TestV8ValueObject.java
@@ -423,6 +423,11 @@ public void testInvokeObject() throws JavetException {
new Integer[]{1, 2, 3, 4, 5, 6},
result.toArray(new Integer[0]),
"invokeObject() should work transparently without resource leak");
+ assertEquals(
+ "TypeError: unknownFunction is not a function",
+ assertThrows(
+ JavetExecutionException.class,
+ () -> v8Runtime.getGlobalObject().invokeVoid("unknownFunction")).getMessage());
}
@Test
@@ -433,6 +438,11 @@ public void testInvokeVoid() throws JavetException {
assertEquals(4, v8ValueArray.getLength());
assertEquals(4, v8ValueArray.getInteger(3));
assertEquals("1,2,3,4", v8ValueArray.toString());
+ assertEquals(
+ "TypeError: unknownFunction is not a function",
+ assertThrows(
+ JavetExecutionException.class,
+ () -> v8ValueArray.invokeVoid("unknownFunction")).getMessage());
}
}