diff --git a/README.rst b/README.rst
index e0829a5df..4ff53a24b 100644
--- a/README.rst
+++ b/README.rst
@@ -33,7 +33,7 @@ Maven
com.caoccao.javetjavet
- 0.7.1
+ 0.7.2
Gradle Kotlin DSL
@@ -41,14 +41,14 @@ Gradle Kotlin DSL
.. code-block:: kotlin
- implementation("com.caoccao.javet:javet:0.7.1")
+ implementation("com.caoccao.javet:javet:0.7.2")
Gradle Groovy DSL
^^^^^^^^^^^^^^^^^
.. code-block:: groovy
- implementation 'com.caoccao.javet:javet:0.7.1'
+ implementation 'com.caoccao.javet:javet:0.7.2'
Hello Javet
-----------
@@ -62,25 +62,15 @@ Hello Javet
Documents
=========
-* `Build `_
-* `Development `_
+* `Development `_
+ * `Build `_
+ * `Design `_
+ * `Performance `_
* `Tutorial `_
-* `Performance `_
* `Release Notes `_
* `FAQ `_
* `TODO List `_
-Motivation
-==========
-
-I used to take a try of J2V8 and find it's quite compelling. However, J2V8 is slowly dying, with serious memory leak issues, V8 version issue, etc.
-
-Sometimes starting from scratch implies lower cost than upgrading an existing solution. I think it might be true here in this project. I've learned quite a lot by manually fixing the Windows and Linux build system of J2V8.
-
-Also, I had got many ideas on how the API will look like. At the end of 2020, I thought I would be able to write a new one from scratch and leave J2V8 behind. Indeed, I made it few months later.
-
-Please refer to `History with J2V8 `_ for detail.
-
License
=======
diff --git a/build.gradle.kts b/build.gradle.kts
index a3cd87abb..502f0d83e 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -26,7 +26,7 @@ repositories {
}
group = "com.caoccao.javet"
-version = "0.7.1"
+version = "0.7.2"
repositories {
mavenCentral()
diff --git a/cpp/build.cmd b/cpp/build.cmd
index 57eb833bb..cb16ea9bc 100644
--- a/cpp/build.cmd
+++ b/cpp/build.cmd
@@ -1,6 +1,6 @@
@echo off
REM Usage sample: build -DV8_DIR=C:\v8
-SET JAVET_VERSION=0.7.1
+SET JAVET_VERSION=0.7.2
rd /s/q build
mkdir build
cd build
diff --git a/cpp/build.sh b/cpp/build.sh
index a5a38dbac..827e3913e 100755
--- a/cpp/build.sh
+++ b/cpp/build.sh
@@ -1,7 +1,7 @@
#!/bin/sh
# Usage sample: build -DV8_DIR=~/v8
-JAVET_VERSION=0.7.1
+JAVET_VERSION=0.7.2
rm -rf build
mkdir build
cd build
diff --git a/cpp/jni/com_caoccao_javet_interop_V8Native.cpp b/cpp/jni/com_caoccao_javet_interop_V8Native.cpp
index f7d22f1f6..21e8652ca 100644
--- a/cpp/jni/com_caoccao_javet_interop_V8Native.cpp
+++ b/cpp/jni/com_caoccao_javet_interop_V8Native.cpp
@@ -44,6 +44,7 @@
#define TO_JAVA_INTEGER(jniEnv, obj) jniEnv->CallIntMethod(obj, Javet::Main::jmethodIDV8ValueIntegerToPrimitive)
#define TO_JAVA_STRING(jniEnv, obj) (jstring)jniEnv->CallObjectMethod(obj, Javet::Main::jmethodIDV8ValueStringToPrimitive)
#define IS_V8_ARRAY(type) (type == Javet::Enums::V8ValueReferenceType::Array)
+#define IS_V8_ARRAY_BUFFER(type) (type == Javet::Enums::V8ValueReferenceType::ArrayBuffer)
#define IS_V8_ARGUMENTS(type) (type == Javet::Enums::V8ValueReferenceType::Arguments)
#define IS_V8_FUNCTION(type) (type == Javet::Enums::V8ValueReferenceType::Function)
#define IS_V8_MAP(type) (type == Javet::Enums::V8ValueReferenceType::Map)
@@ -69,7 +70,18 @@
v8::HandleScope v8HandleScope(v8Runtime->v8Isolate); \
auto v8Context = v8::Local::New(v8Runtime->v8Isolate, v8Runtime->v8Context); \
v8::Context::Scope v8ContextScope(v8Context); \
- auto v8LocalObject = v8PersistentObjectPointer->Get(v8Runtime->v8Isolate);
+ auto v8LocalObject = v8PersistentObjectPointer->Get(v8Context->GetIsolate());
+
+#define RUNTIME_AND_2_VALUES_HANDLES_TO_OBJECTS_WITH_SCOPE(v8RuntimeHandle, v8ValueHandle1, v8ValueHandle2) \
+ auto v8Runtime = reinterpret_cast(v8RuntimeHandle); \
+ auto v8PersistentObjectPointer1 = reinterpret_cast*>(v8ValueHandle1); \
+ auto v8PersistentObjectPointer2 = reinterpret_cast*>(v8ValueHandle2); \
+ v8::Isolate::Scope v8IsolateScope(v8Runtime->v8Isolate); \
+ v8::HandleScope v8HandleScope(v8Runtime->v8Isolate); \
+ auto v8Context = v8::Local::New(v8Runtime->v8Isolate, v8Runtime->v8Context); \
+ v8::Context::Scope v8ContextScope(v8Context); \
+ auto v8LocalObject1 = v8PersistentObjectPointer1->Get(v8Context->GetIsolate()); \
+ auto v8LocalObject2 = v8PersistentObjectPointer2->Get(v8Context->GetIsolate());
#define SAFE_CONVERT_AND_RETURN_JAVE_V8_VALUE(jniEnv, v8Context, v8Value) \
try { \
@@ -182,6 +194,30 @@ JNIEXPORT jobject JNICALL Java_com_caoccao_javet_interop_V8Native_call
return nullptr;
}
+JNIEXPORT jobject JNICALL Java_com_caoccao_javet_interop_V8Native_callAsConstructor
+(JNIEnv* jniEnv, jclass callerClass, jlong v8RuntimeHandle, jlong v8ValueHandle, jint v8ValueType, jobjectArray mValues) {
+ RUNTIME_AND_VALUE_HANDLES_TO_OBJECTS_WITH_SCOPE(v8RuntimeHandle, v8ValueHandle);
+ if (v8LocalObject->IsFunction()) {
+ v8::TryCatch v8TryCatch(v8Runtime->v8Isolate);
+ v8::MaybeLocal maybeLocalValueResult;
+ uint32_t valueCount = mValues == nullptr ? 0 : jniEnv->GetArrayLength(mValues);
+ if (valueCount > 0) {
+ auto umValuesPointer = Javet::Converter::ToV8Values(jniEnv, v8Context, mValues);
+ maybeLocalValueResult = v8LocalObject.As()->CallAsConstructor(v8Context, valueCount, umValuesPointer.get());
+ }
+ else {
+ maybeLocalValueResult = v8LocalObject.As()->CallAsConstructor(v8Context, 0, nullptr);
+ }
+ if (v8TryCatch.HasCaught()) {
+ Javet::Exceptions::ThrowJavetExecutionException(jniEnv, v8Context, v8TryCatch);
+ }
+ else {
+ SAFE_CONVERT_AND_RETURN_JAVE_V8_VALUE(jniEnv, v8Context, maybeLocalValueResult.ToLocalChecked());
+ }
+ }
+ return nullptr;
+}
+
JNIEXPORT void JNICALL Java_com_caoccao_javet_interop_V8Native_clearWeak
(JNIEnv* jniEnv, jclass callerClass, jlong v8RuntimeHandle, jlong v8ValueHandle, jint v8ValueType) {
RUNTIME_AND_VALUE_HANDLES_TO_OBJECTS_WITH_SCOPE(v8RuntimeHandle, v8ValueHandle);
@@ -259,6 +295,11 @@ JNIEXPORT jobject JNICALL Java_com_caoccao_javet_interop_V8Native_createV8Value
else if (IS_V8_ARRAY(v8ValueType)) {
v8ValueValue = v8::Array::New(v8Context->GetIsolate());
}
+ else if (IS_V8_ARRAY_BUFFER(v8ValueType)) {
+ if (IS_JAVA_INTEGER(jniEnv, mContext)) {
+ v8ValueValue = v8::ArrayBuffer::New(v8Context->GetIsolate(), TO_JAVA_INTEGER(jniEnv, mContext));
+ }
+ }
else if (IS_V8_FUNCTION(v8ValueType)) {
jobject umContext = jniEnv->NewGlobalRef(mContext);
Javet::Callback::JavetCallbackContextReference javetCallbackContextReference(jniEnv, umContext);
@@ -309,6 +350,12 @@ JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_delete
return false;
}
+JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_equals
+(JNIEnv* jniEnv, jclass callerClass, jlong v8RuntimeHandle, jlong v8ValueHandle1, jlong v8ValueHandle2) {
+ RUNTIME_AND_2_VALUES_HANDLES_TO_OBJECTS_WITH_SCOPE(v8RuntimeHandle, v8ValueHandle1, v8ValueHandle2);
+ return v8LocalObject1->Equals(v8Context, v8LocalObject2).FromMaybe(false);
+}
+
JNIEXPORT jobject JNICALL Java_com_caoccao_javet_interop_V8Native_execute
(JNIEnv* jniEnv, jclass callerClass, jlong v8RuntimeHandle, jstring mScript, jboolean mReturnResult,
jstring mResourceName, jint mResourceLineOffset, jint mResourceColumnOffset, jint mScriptId, jboolean mIsWASM, jboolean mIsModule) {
@@ -342,7 +389,7 @@ JNIEXPORT jobject JNICALL Java_com_caoccao_javet_interop_V8Native_get
RUNTIME_AND_VALUE_HANDLES_TO_OBJECTS_WITH_SCOPE(v8RuntimeHandle, v8ValueHandle);
auto v8ValueKey = Javet::Converter::ToV8Value(jniEnv, v8Context, key);
v8::Local v8ValueValue;
- if (IS_V8_ARRAY(v8ValueType) || IS_V8_ARGUMENTS(v8ValueType)) {
+ if (IS_V8_ARGUMENTS(v8ValueType) || IS_V8_ARRAY(v8ValueType) || v8LocalObject->IsTypedArray()) {
if (IS_JAVA_INTEGER(jniEnv, key)) {
jint integerKey = TO_JAVA_INTEGER(jniEnv, key);
if (integerKey >= 0) {
@@ -382,11 +429,20 @@ JNIEXPORT jobject JNICALL Java_com_caoccao_javet_interop_V8Native_getGlobalObjec
return Javet::Converter::ToExternalV8ValueGlobalObject(jniEnv, v8Runtime->v8GlobalObject);
}
+JNIEXPORT jint JNICALL Java_com_caoccao_javet_interop_V8Native_getIdentityHash
+(JNIEnv* jniEnv, jclass callerClass, jlong v8RuntimeHandle, jlong v8ValueHandle, jint v8ValueType) {
+ RUNTIME_AND_VALUE_HANDLES_TO_OBJECTS_WITH_SCOPE(v8RuntimeHandle, v8ValueHandle);
+ return v8LocalObject->GetIdentityHash();
+}
+
JNIEXPORT jint JNICALL Java_com_caoccao_javet_interop_V8Native_getLength
(JNIEnv* jniEnv, jclass callerClass, jlong v8RuntimeHandle, jlong v8ValueHandle, jint v8ValueType) {
RUNTIME_AND_VALUE_HANDLES_TO_OBJECTS_WITH_SCOPE(v8RuntimeHandle, v8ValueHandle);
if (IS_V8_ARRAY(v8ValueType)) {
- return v8LocalObject.As()->Length();
+ return (jint)v8LocalObject.As()->Length();
+ }
+ if (v8LocalObject->IsTypedArray()) {
+ return (jint)v8LocalObject.As()->Length();
}
return 0;
}
@@ -513,6 +569,18 @@ JNIEXPORT jobject JNICALL Java_com_caoccao_javet_interop_V8Native_invoke
return nullptr;
}
+JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_isDead
+(JNIEnv* jniEnv, jclass callerClass, jlong v8RuntimeHandle) {
+ auto v8Runtime = reinterpret_cast(v8RuntimeHandle);
+ return v8Runtime->v8Isolate->IsDead();
+}
+
+JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_isInUse
+(JNIEnv* jniEnv, jclass callerClass, jlong v8RuntimeHandle) {
+ auto v8Runtime = reinterpret_cast(v8RuntimeHandle);
+ return v8Runtime->v8Isolate->IsInUse();
+}
+
JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_isWeak
(JNIEnv* jniEnv, jclass callerClass, jlong v8RuntimeHandle, jlong v8ValueHandle, jint v8ValueType) {
RUNTIME_AND_VALUE_HANDLES_TO_OBJECTS_WITH_SCOPE(v8RuntimeHandle, v8ValueHandle);
@@ -670,6 +738,24 @@ JNIEXPORT void JNICALL Java_com_caoccao_javet_interop_V8Native_setWeak
}
}
+JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_sameValue
+(JNIEnv* jniEnv, jclass callerClass, jlong v8RuntimeHandle, jlong v8ValueHandle1, jlong v8ValueHandle2) {
+ RUNTIME_AND_2_VALUES_HANDLES_TO_OBJECTS_WITH_SCOPE(v8RuntimeHandle, v8ValueHandle1, v8ValueHandle2);
+ return v8LocalObject1->SameValue(v8LocalObject2);
+}
+
+JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_strictEquals
+(JNIEnv* jniEnv, jclass callerClass, jlong v8RuntimeHandle, jlong v8ValueHandle1, jlong v8ValueHandle2) {
+ RUNTIME_AND_2_VALUES_HANDLES_TO_OBJECTS_WITH_SCOPE(v8RuntimeHandle, v8ValueHandle1, v8ValueHandle2);
+ return v8LocalObject1->StrictEquals(v8LocalObject2);
+}
+
+JNIEXPORT void JNICALL Java_com_caoccao_javet_interop_V8Native_terminateExecution
+(JNIEnv* jniEnv, jclass callerClass, jlong v8RuntimeHandle) {
+ auto v8Runtime = reinterpret_cast(v8RuntimeHandle);
+ v8Runtime->v8Isolate->TerminateExecution();
+}
+
JNIEXPORT jstring JNICALL Java_com_caoccao_javet_interop_V8Native_toProtoString
(JNIEnv* jniEnv, jclass callerClass, jlong v8RuntimeHandle, jlong v8ValueHandle, jint v8ValueType) {
RUNTIME_AND_VALUE_HANDLES_TO_OBJECTS_WITH_SCOPE(v8RuntimeHandle, v8ValueHandle);
diff --git a/cpp/jni/com_caoccao_javet_interop_V8Native.h b/cpp/jni/com_caoccao_javet_interop_V8Native.h
index 8a79de8e4..9313d542f 100644
--- a/cpp/jni/com_caoccao_javet_interop_V8Native.h
+++ b/cpp/jni/com_caoccao_javet_interop_V8Native.h
@@ -23,6 +23,14 @@ JNIEXPORT void JNICALL Java_com_caoccao_javet_interop_V8Native_add
JNIEXPORT jobject JNICALL Java_com_caoccao_javet_interop_V8Native_call
(JNIEnv *, jclass, jlong, jlong, jint, jobject, jboolean, jobjectArray);
+/*
+ * Class: com_caoccao_javet_interop_V8Native
+ * Method: callAsConstructor
+ * Signature: (JJI[Ljava/lang/Object;)Ljava/lang/Object;
+ */
+JNIEXPORT jobject JNICALL Java_com_caoccao_javet_interop_V8Native_callAsConstructor
+ (JNIEnv *, jclass, jlong, jlong, jint, jobjectArray);
+
/*
* Class: com_caoccao_javet_interop_V8Native
* Method: clearWeak
@@ -79,6 +87,14 @@ JNIEXPORT jobject JNICALL Java_com_caoccao_javet_interop_V8Native_createV8Value
JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_delete
(JNIEnv *, jclass, jlong, jlong, jint, jobject);
+/*
+ * Class: com_caoccao_javet_interop_V8Native
+ * Method: equals
+ * Signature: (JJJ)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_equals
+ (JNIEnv *, jclass, jlong, jlong, jlong);
+
/*
* Class: com_caoccao_javet_interop_V8Native
* Method: execute
@@ -103,6 +119,14 @@ JNIEXPORT jobject JNICALL Java_com_caoccao_javet_interop_V8Native_get
JNIEXPORT jobject JNICALL Java_com_caoccao_javet_interop_V8Native_getGlobalObject
(JNIEnv *, jclass, jlong);
+/*
+ * Class: com_caoccao_javet_interop_V8Native
+ * Method: getIdentityHash
+ * Signature: (JJI)I
+ */
+JNIEXPORT jint JNICALL Java_com_caoccao_javet_interop_V8Native_getIdentityHash
+ (JNIEnv *, jclass, jlong, jlong, jint);
+
/*
* Class: com_caoccao_javet_interop_V8Native
* Method: getLength
@@ -175,6 +199,22 @@ JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_hasOwnPropert
JNIEXPORT jobject JNICALL Java_com_caoccao_javet_interop_V8Native_invoke
(JNIEnv *, jclass, jlong, jlong, jint, jstring, jboolean, jobjectArray);
+/*
+ * Class: com_caoccao_javet_interop_V8Native
+ * Method: isDead
+ * Signature: (J)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_isDead
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: com_caoccao_javet_interop_V8Native
+ * Method: isInUse
+ * Signature: (J)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_isInUse
+ (JNIEnv *, jclass, jlong);
+
/*
* Class: com_caoccao_javet_interop_V8Native
* Method: isWeak
@@ -263,6 +303,30 @@ JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_setProperty
JNIEXPORT void JNICALL Java_com_caoccao_javet_interop_V8Native_setWeak
(JNIEnv *, jclass, jlong, jlong, jint, jobject);
+/*
+ * Class: com_caoccao_javet_interop_V8Native
+ * Method: sameValue
+ * Signature: (JJJ)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_sameValue
+ (JNIEnv *, jclass, jlong, jlong, jlong);
+
+/*
+ * Class: com_caoccao_javet_interop_V8Native
+ * Method: strictEquals
+ * Signature: (JJJ)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_caoccao_javet_interop_V8Native_strictEquals
+ (JNIEnv *, jclass, jlong, jlong, jlong);
+
+/*
+ * Class: com_caoccao_javet_interop_V8Native
+ * Method: terminateExecution
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_com_caoccao_javet_interop_V8Native_terminateExecution
+ (JNIEnv *, jclass, jlong);
+
/*
* Class: com_caoccao_javet_interop_V8Native
* Method: toProtoString
diff --git a/cpp/jni/javet.rc b/cpp/jni/javet.rc
index 1f70f4d61..a2e96d2e6 100644
--- a/cpp/jni/javet.rc
+++ b/cpp/jni/javet.rc
@@ -61,8 +61,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 0,7,1,0
- PRODUCTVERSION 0,7,1,0
+ FILEVERSION 0,7,2,0
+ PRODUCTVERSION 0,7,2,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -79,12 +79,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "caoccao.com"
VALUE "FileDescription", "caoccao.com"
- VALUE "FileVersion", "0.7.1.0"
- VALUE "InternalName", "javet-windows-x86_64.v.0.7.1.dll"
+ VALUE "FileVersion", "0.7.2.0"
+ VALUE "InternalName", "javet-windows-x86_64.v.0.7.2.dll"
VALUE "LegalCopyright", "Copyright (C) 2021"
- VALUE "OriginalFilename", "javet-windows-x86_64.v.0.7.1.dll"
+ VALUE "OriginalFilename", "javet-windows-x86_64.v.0.7.2.dll"
VALUE "ProductName", "Javet Windows"
- VALUE "ProductVersion", "0.7.1.0"
+ VALUE "ProductVersion", "0.7.2.0"
END
END
BLOCK "VarFileInfo"
diff --git a/cpp/jni/javet_converter.cpp b/cpp/jni/javet_converter.cpp
index 0f2795551..e2b961f1f 100644
--- a/cpp/jni/javet_converter.cpp
+++ b/cpp/jni/javet_converter.cpp
@@ -16,6 +16,7 @@
*/
#include "javet_converter.h"
+#include "javet_enums.h"
// Primitive
#define IS_JAVA_BOOLEAN(jniEnv, obj) jniEnv->IsInstanceOf(obj, jclassV8ValueBoolean)
@@ -30,10 +31,13 @@
// Reference
#define IS_JAVA_ARGUMENTS(jniEnv, obj) jniEnv->IsInstanceOf(obj, jclassV8ValueArguments)
#define IS_JAVA_ARRAY(jniEnv, obj) jniEnv->IsInstanceOf(obj, jclassV8ValueArray)
+#define IS_JAVA_ARRAY_BUFFER(jniEnv, obj) jniEnv->IsInstanceOf(obj, jclassV8ValueArrayBuffer)
+#define IS_JAVA_DATA_VIEW(jniEnv, obj) jniEnv->IsInstanceOf(obj, jclassV8ValueDataView)
#define IS_JAVA_FUNCTION(jniEnv, obj) jniEnv->IsInstanceOf(obj, jclassV8ValueFunction)
#define IS_JAVA_ERROR(jniEnv, obj) jniEnv->IsInstanceOf(obj, jclassV8ValueError)
#define IS_JAVA_GLOBAL_OBJECT(jniEnv, obj) jniEnv->IsInstanceOf(obj, jclassV8ValueGlobalObject)
#define IS_JAVA_MAP(jniEnv, obj) jniEnv->IsInstanceOf(obj, jclassV8ValueMap)
+#define IS_JAVA_ITERATOR(jniEnv, obj) jniEnv->IsInstanceOf(obj, jclassV8ValueIterator)
#define IS_JAVA_OBJECT(jniEnv, obj) jniEnv->IsInstanceOf(obj, jclassV8ValueObject)
#define IS_JAVA_PROMISE(jniEnv, obj) jniEnv->IsInstanceOf(obj, jclassV8ValuePromise)
#define IS_JAVA_PROXY(jniEnv, obj) jniEnv->IsInstanceOf(obj, jclassV8ValueProxy)
@@ -96,6 +100,14 @@ namespace Javet {
jmethodIDV8ValueArrayConstructor = jniEnv->GetMethodID(jclassV8ValueArray, "", "(J)V");
jmethodIDV8ValueArrayGetHandle = jniEnv->GetMethodID(jclassV8ValueArray, "getHandle", "()J");
+ jclassV8ValueArrayBuffer = (jclass)jniEnv->NewGlobalRef(jniEnv->FindClass("com/caoccao/javet/values/reference/V8ValueArrayBuffer"));
+ jmethodIDV8ValueArrayBufferConstructor = jniEnv->GetMethodID(jclassV8ValueArrayBuffer, "", "(JLjava/nio/ByteBuffer;)V");
+ jmethodIDV8ValueArrayBufferGetHandle = jniEnv->GetMethodID(jclassV8ValueArrayBuffer, "getHandle", "()J");
+
+ jclassV8ValueDataView = (jclass)jniEnv->NewGlobalRef(jniEnv->FindClass("com/caoccao/javet/values/reference/V8ValueDataView"));
+ jmethodIDV8ValueDataViewConstructor = jniEnv->GetMethodID(jclassV8ValueDataView, "", "(J)V");
+ jmethodIDV8ValueDataViewGetHandle = jniEnv->GetMethodID(jclassV8ValueDataView, "getHandle", "()J");
+
jclassV8ValueFunction = (jclass)jniEnv->NewGlobalRef(jniEnv->FindClass("com/caoccao/javet/values/reference/V8ValueFunction"));
jmethodIDV8ValueFunctionConstructor = jniEnv->GetMethodID(jclassV8ValueFunction, "", "(J)V");
jmethodIDV8ValueFunctionGetHandle = jniEnv->GetMethodID(jclassV8ValueFunction, "getHandle", "()J");
@@ -112,6 +124,10 @@ namespace Javet {
jmethodIDV8ValueMapConstructor = jniEnv->GetMethodID(jclassV8ValueMap, "", "(J)V");
jmethodIDV8ValueMapGetHandle = jniEnv->GetMethodID(jclassV8ValueMap, "getHandle", "()J");
+ jclassV8ValueIterator = (jclass)jniEnv->NewGlobalRef(jniEnv->FindClass("com/caoccao/javet/values/reference/V8ValueIterator"));
+ jmethodIDV8ValueIteratorConstructor = jniEnv->GetMethodID(jclassV8ValueIterator, "", "(J)V");
+ jmethodIDV8ValueIteratorGetHandle = jniEnv->GetMethodID(jclassV8ValueIterator, "getHandle", "()J");
+
jclassV8ValueObject = (jclass)jniEnv->NewGlobalRef(jniEnv->FindClass("com/caoccao/javet/values/reference/V8ValueObject"));
jmethodIDV8ValueObjectConstructor = jniEnv->GetMethodID(jclassV8ValueObject, "", "(J)V");
jmethodIDV8ValueObjectGetHandle = jniEnv->GetMethodID(jclassV8ValueObject, "getHandle", "()J");
@@ -137,6 +153,10 @@ namespace Javet {
jclassV8ValueSymbol = (jclass)jniEnv->NewGlobalRef(jniEnv->FindClass("com/caoccao/javet/values/reference/V8ValueSymbol"));
jmethodIDV8ValueSymbolConstructor = jniEnv->GetMethodID(jclassV8ValueSymbol, "", "(J)V");
jmethodIDV8ValueSymbolGetHandle = jniEnv->GetMethodID(jclassV8ValueSymbol, "getHandle", "()J");
+
+ jclassV8ValueTypedArray = (jclass)jniEnv->NewGlobalRef(jniEnv->FindClass("com/caoccao/javet/values/reference/V8ValueTypedArray"));
+ jmethodIDV8ValueTypedArrayConstructor = jniEnv->GetMethodID(jclassV8ValueTypedArray, "", "(JI)V");
+ jmethodIDV8ValueTypedArrayGetHandle = jniEnv->GetMethodID(jclassV8ValueTypedArray, "getHandle", "()J");
}
jobject ToExternalV8ValueArray(JNIEnv* jniEnv, v8::Local& v8Context, const v8::FunctionCallbackInfo& args) {
@@ -165,47 +185,66 @@ namespace Javet {
return jniEnv->NewObject(jclassV8ValueArray, jmethodIDV8ValueArrayConstructor, ToV8PersistentObjectReference(v8Context, v8Value));
}
if (v8Value->IsTypedArray()) {
- // TODO
+ int type = Javet::Enums::V8ValueReferenceType::Invalid;
if (v8Value->IsBigInt64Array()) {
+ type = Javet::Enums::V8ValueReferenceType::BigInt64Array;
}
- if (v8Value->IsBigUint64Array()) {
+ else if (v8Value->IsBigUint64Array()) {
+ type = Javet::Enums::V8ValueReferenceType::BigUint64Array;
}
- if (v8Value->IsFloat32Array()) {
+ else if (v8Value->IsFloat32Array()) {
+ type = Javet::Enums::V8ValueReferenceType::Float32Array;
}
- if (v8Value->IsFloat64Array()) {
+ else if (v8Value->IsFloat64Array()) {
+ type = Javet::Enums::V8ValueReferenceType::Float64Array;
}
- if (v8Value->IsInt16Array()) {
+ else if (v8Value->IsInt16Array()) {
+ type = Javet::Enums::V8ValueReferenceType::Int16Array;
}
- if (v8Value->IsInt32Array()) {
+ else if (v8Value->IsInt32Array()) {
+ type = Javet::Enums::V8ValueReferenceType::Int32Array;
}
- if (v8Value->IsInt8Array()) {
+ else if (v8Value->IsInt8Array()) {
+ type = Javet::Enums::V8ValueReferenceType::Int8Array;
}
- if (v8Value->IsUint16Array()) {
+ else if (v8Value->IsUint16Array()) {
+ type = Javet::Enums::V8ValueReferenceType::Uint16Array;
}
- if (v8Value->IsUint32Array()) {
+ else if (v8Value->IsUint32Array()) {
+ type = Javet::Enums::V8ValueReferenceType::Uint32Array;
}
- if (v8Value->IsUint8Array()) {
+ else if (v8Value->IsUint8Array()) {
+ type = Javet::Enums::V8ValueReferenceType::Uint8Array;
}
- if (v8Value->IsUint8ClampedArray()) {
+ else if (v8Value->IsUint8ClampedArray()) {
+ type = Javet::Enums::V8ValueReferenceType::Uint8ClampedArray;
}
+ if (type != Javet::Enums::V8ValueReferenceType::Invalid) {
+ return jniEnv->NewObject(jclassV8ValueTypedArray, jmethodIDV8ValueTypedArrayConstructor, ToV8PersistentObjectReference(v8Context, v8Value), type);
+ }
+ }
+ if (v8Value->IsDataView()) {
+ return jniEnv->NewObject(jclassV8ValueDataView, jmethodIDV8ValueDataViewConstructor, ToV8PersistentObjectReference(v8Context, v8Value));
}
if (v8Value->IsArrayBuffer()) {
- // TODO
+ auto v8ArrayBuffer = v8Value.As();
+ return jniEnv->NewObject(jclassV8ValueArrayBuffer, jmethodIDV8ValueArrayBufferConstructor, ToV8PersistentObjectReference(v8Context, v8Value),
+ jniEnv->NewDirectByteBuffer(v8ArrayBuffer->GetBackingStore()->Data(), v8ArrayBuffer->ByteLength()));
}
if (v8Value->IsArrayBufferView()) {
- // TODO
+ /*
+ ArrayBufferView is a helper type representing any of typed array or DataView.
+ This block shouldn't be entered.
+ */
}
if (v8Value->IsMap()) {
return jniEnv->NewObject(jclassV8ValueMap, jmethodIDV8ValueMapConstructor, ToV8PersistentObjectReference(v8Context, v8Value));
}
- if (v8Value->IsMapIterator()) {
- // It defaults to V8ValueObject.
- }
if (v8Value->IsSet()) {
return jniEnv->NewObject(jclassV8ValueSet, jmethodIDV8ValueSetConstructor, ToV8PersistentObjectReference(v8Context, v8Value));
}
- if (v8Value->IsSetIterator()) {
- // It defaults to V8ValueObject.
+ if (v8Value->IsMapIterator() || v8Value->IsSetIterator()) {
+ return jniEnv->NewObject(jclassV8ValueIterator, jmethodIDV8ValueIteratorConstructor, ToV8PersistentObjectReference(v8Context, v8Value));
}
if (v8Value->IsWeakMap()) {
// TODO
@@ -252,18 +291,8 @@ namespace Javet {
return jniEnv->NewObject(jclassV8ValueInteger, jmethodIDV8ValueIntegerConstructor, v8Value->Int32Value(v8Context).FromMaybe(0));
}
if (v8Value->IsBigInt() || v8Value->IsBigIntObject()) {
-#ifdef JAVET_CONVERTER_BIGINT_STANDARD
- // This is the standard way of getting int64.
return jniEnv->NewObject(jclassV8ValueLong, jmethodIDV8ValueLongConstructorFromLong,
v8Value->ToBigInt(v8Context).ToLocalChecked()->Int64Value());
-#else
- // There is another way of getting int64. This branch is disabled by default.
- v8::String::Value stringValue(v8Context->GetIsolate(), v8Value);
- jstring mStringValue = jniEnv->NewString(*stringValue, stringValue.length());
- jobject mV8Value = jniEnv->NewObject(jclassV8ValueLong, jmethodIDV8ValueLongConstructorFromString, mStringValue);
- jniEnv->DeleteLocalRef(mStringValue);
- return mV8Value;
-#endif // JAVET_CONVERTER_BIGINT_STANDARD
}
if (v8Value->IsDate()) {
auto v8Date = v8Value->ToObject(v8Context).ToLocalChecked().As();
@@ -424,9 +453,9 @@ namespace Javet {
return v8::Local::New(v8Context->GetIsolate(), *reinterpret_cast*>(
jniEnv->CallLongMethod(obj, jmethodIDV8ValueMapGetHandle)));
}
- else if (IS_JAVA_OBJECT(jniEnv, obj)) {
+ else if (IS_JAVA_ITERATOR(jniEnv, obj)) {
return v8::Local::New(v8Context->GetIsolate(), *reinterpret_cast*>(
- jniEnv->CallLongMethod(obj, jmethodIDV8ValueObjectGetHandle)));
+ jniEnv->CallLongMethod(obj, jmethodIDV8ValueIteratorGetHandle)));
}
else if (IS_JAVA_PROMISE(jniEnv, obj)) {
return v8::Local::New(v8Context->GetIsolate(), *reinterpret_cast*>(
@@ -448,6 +477,10 @@ namespace Javet {
return v8::Local::New(v8Context->GetIsolate(), *reinterpret_cast*>(
jniEnv->CallLongMethod(obj, jmethodIDV8ValueSymbolGetHandle)));
}
+ else if (IS_JAVA_OBJECT(jniEnv, obj)) {
+ return v8::Local::New(v8Context->GetIsolate(), *reinterpret_cast*>(
+ jniEnv->CallLongMethod(obj, jmethodIDV8ValueObjectGetHandle)));
+ }
}
return ToV8Undefined(v8Context);
}
diff --git a/cpp/jni/javet_converter.h b/cpp/jni/javet_converter.h
index 9bbe848b9..ad32f37e5 100644
--- a/cpp/jni/javet_converter.h
+++ b/cpp/jni/javet_converter.h
@@ -21,8 +21,6 @@
#include
#include
-#define JAVET_CONVERTER_BIGINT_STANDARD
-
namespace Javet {
namespace Converter {
// Primitive
@@ -71,6 +69,14 @@ namespace Javet {
static jmethodID jmethodIDV8ValueArrayConstructor;
static jmethodID jmethodIDV8ValueArrayGetHandle;
+ static jclass jclassV8ValueArrayBuffer;
+ static jmethodID jmethodIDV8ValueArrayBufferConstructor;
+ static jmethodID jmethodIDV8ValueArrayBufferGetHandle;
+
+ static jclass jclassV8ValueDataView;
+ static jmethodID jmethodIDV8ValueDataViewConstructor;
+ static jmethodID jmethodIDV8ValueDataViewGetHandle;
+
static jclass jclassV8ValueFunction;
static jmethodID jmethodIDV8ValueFunctionConstructor;
static jmethodID jmethodIDV8ValueFunctionGetHandle;
@@ -87,6 +93,10 @@ namespace Javet {
static jmethodID jmethodIDV8ValueMapConstructor;
static jmethodID jmethodIDV8ValueMapGetHandle;
+ static jclass jclassV8ValueIterator;
+ static jmethodID jmethodIDV8ValueIteratorConstructor;
+ static jmethodID jmethodIDV8ValueIteratorGetHandle;
+
static jclass jclassV8ValueObject;
static jmethodID jmethodIDV8ValueObjectConstructor;
static jmethodID jmethodIDV8ValueObjectGetHandle;
@@ -113,6 +123,10 @@ namespace Javet {
static jmethodID jmethodIDV8ValueSymbolConstructor;
static jmethodID jmethodIDV8ValueSymbolGetHandle;
+ static jclass jclassV8ValueTypedArray;
+ static jmethodID jmethodIDV8ValueTypedArrayConstructor;
+ static jmethodID jmethodIDV8ValueTypedArrayGetHandle;
+
void Initialize(JNIEnv* jniEnv);
jobject ToExternalV8Value(JNIEnv* jniEnv, v8::Local& v8Context, v8::Local v8Value);
diff --git a/cpp/jni/javet_enums.h b/cpp/jni/javet_enums.h
index 001853c44..19380c1d4 100644
--- a/cpp/jni/javet_enums.h
+++ b/cpp/jni/javet_enums.h
@@ -2,7 +2,7 @@
* Copyright (c) 2021 caoccao.com Sam Cao
* All rights reserved.
- * Licensed under the Apache License, Version 2.0 (the "License");
+ * Licensed under the Apache License, Version 2.0 (the "License"),
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
@@ -18,19 +18,34 @@
#pragma once
namespace Javet {
- namespace Enums {
- enum V8ValueReferenceType {
- Object = 1,
- Error = 2,
- RegExp = 3,
- Promise = 4,
- Proxy = 5,
- Symbol = 6,
- Arguments = 7,
- Map = 8,
- Set = 9,
- Array = 10,
- Function = 11,
- };
- }
+ namespace Enums {
+ enum V8ValueReferenceType {
+ Invalid = 0,
+ Object = 1,
+ Error = 2,
+ RegExp = 3,
+ Promise = 4,
+ Proxy = 5,
+ Symbol = 6,
+ Arguments = 7,
+ Map = 8,
+ Set = 9,
+ Array = 10,
+ Function = 11,
+ Iterator = 12,
+ DataView = 30,
+ ArrayBuffer = 31,
+ Int8Array = 32, // -128 to 127 1 8-bit two's complement signed integer byte int8_t
+ Uint8Array = 33, // 0 to 255 1 8-bit unsigned integer octet uint8_t
+ Uint8ClampedArray = 34, // 0 to 255 1 8-bit unsigned integer (clamped) octet uint8_t
+ Int16Array = 35, // -32768 to 32767 2 16-bit two's complement signed integer short int16_t
+ Uint16Array = 36, // 0 to 65535 2 16-bit unsigned integer unsigned short uint16_t
+ Int32Array = 37, // -2147483648 to 2147483647 4 32-bit two's complement signed integer long int32_t
+ Uint32Array = 38, // 0 to 4294967295 4 32-bit unsigned integer unsigned long uint32_t
+ Float32Array = 39, // 1.2¡Á10^-38 to 3.4¡Á10^38 4 32-bit IEEE floating point number (7 significant digits e.g., 1.234567) unrestricted float float
+ Float64Array = 40, // 5.0¡Á10^-324 to 1.8¡Á10^308 8 64-bit IEEE floating point number (16 significant digits e.g., 1.23456789012345) unrestricted double double
+ BigInt64Array = 41, // -2^63 to 2^63-1 8 64-bit two's complement signed integer bigint int64_t (signed long long)
+ BigUint64Array = 42, // 0 to 2^64-1 8 64-bit unsigned integer bigint uint64_t (unsigned long long)
+ };
+ }
}
\ No newline at end of file
diff --git a/cpp/jni/javet_exceptions.cpp b/cpp/jni/javet_exceptions.cpp
index 70b64947f..0e6750f5c 100644
--- a/cpp/jni/javet_exceptions.cpp
+++ b/cpp/jni/javet_exceptions.cpp
@@ -31,6 +31,8 @@ namespace Javet {
jclassJavetConverterException = (jclass)jniEnv->NewGlobalRef(jniEnv->FindClass("com/caoccao/javet/exceptions/JavetConverterException"));
jclassJavetExecutionException = (jclass)jniEnv->NewGlobalRef(jniEnv->FindClass("com/caoccao/javet/exceptions/JavetExecutionException"));
jmethodIDJavetExecutionExceptionConstructor = jniEnv->GetMethodID(jclassJavetExecutionException, "", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IIIII)V");
+ jclassJavetTerminatedException = (jclass)jniEnv->NewGlobalRef(jniEnv->FindClass("com/caoccao/javet/exceptions/JavetTerminatedException"));
+ jmethodIDJavetTerminatedExceptionConstructor = jniEnv->GetMethodID(jclassJavetTerminatedException, "", "(Z)V");
jclassJavetUnknownCompilationException = (jclass)jniEnv->NewGlobalRef(jniEnv->FindClass("com/caoccao/javet/exceptions/JavetUnknownCompilationException"));
jmethodIDJavetUnknownCompilationExceptionConstructor = jniEnv->GetMethodID(jclassJavetUnknownCompilationException, "", "(Ljava/lang/String;)V");
jclassJavetUnknownExecutionException = (jclass)jniEnv->NewGlobalRef(jniEnv->FindClass("com/caoccao/javet/exceptions/JavetUnknownExecutionException"));
@@ -42,8 +44,8 @@ namespace Javet {
auto isolate = v8Context->GetIsolate();
v8::String::Value exceptionMessage(isolate, v8TryCatch.Exception());
jstring jStringExceptionMessage = jniEnv->NewString(*exceptionMessage, exceptionMessage.length());
- auto compileErrorMessage = v8TryCatch.Message();
- if (compileErrorMessage.IsEmpty()) {
+ auto v8LocalMessage = v8TryCatch.Message();
+ if (v8LocalMessage.IsEmpty()) {
jthrowable javetUnknownCompilationException = (jthrowable)jniEnv->NewObject(
jclassJavetUnknownCompilationException,
jmethodIDJavetUnknownCompilationExceptionConstructor,
@@ -51,9 +53,9 @@ namespace Javet {
jniEnv->Throw(javetUnknownCompilationException);
}
else {
- v8::String::Utf8Value scriptResourceName(isolate, compileErrorMessage->GetScriptResourceName());
+ v8::String::Utf8Value scriptResourceName(isolate, v8LocalMessage->GetScriptResourceName());
jstring jStringScriptResourceName = jniEnv->NewStringUTF(*scriptResourceName);
- v8::String::Value sourceLine(isolate, compileErrorMessage->GetSourceLine(v8Context).ToLocalChecked());
+ v8::String::Value sourceLine(isolate, v8LocalMessage->GetSourceLine(v8Context).ToLocalChecked());
jstring jStringSourceLine = jniEnv->NewString(*sourceLine, sourceLine.length());
jthrowable javetConverterException = (jthrowable)jniEnv->NewObject(
jclassJavetCompilationException,
@@ -61,11 +63,11 @@ namespace Javet {
jStringExceptionMessage,
jStringScriptResourceName,
jStringSourceLine,
- compileErrorMessage->GetLineNumber(v8Context).FromMaybe(0),
- compileErrorMessage->GetStartColumn(),
- compileErrorMessage->GetEndColumn(),
- compileErrorMessage->GetStartPosition(),
- compileErrorMessage->GetEndPosition() );
+ v8LocalMessage->GetLineNumber(v8Context).FromMaybe(0),
+ v8LocalMessage->GetStartColumn(),
+ v8LocalMessage->GetEndColumn(),
+ v8LocalMessage->GetStartPosition(),
+ v8LocalMessage->GetEndPosition());
jniEnv->Throw(javetConverterException);
jniEnv->DeleteLocalRef(jStringSourceLine);
jniEnv->DeleteLocalRef(jStringScriptResourceName);
@@ -79,37 +81,46 @@ namespace Javet {
void ThrowJavetExecutionException(JNIEnv* jniEnv, const v8::Local& v8Context, const v8::TryCatch& v8TryCatch) {
auto isolate = v8Context->GetIsolate();
- v8::String::Value exceptionMessage(isolate, v8TryCatch.Exception());
- jstring jStringExceptionMessage = jniEnv->NewString(*exceptionMessage, exceptionMessage.length());
- auto compileErrorMessage = v8TryCatch.Message();
- if (compileErrorMessage.IsEmpty()) {
- jthrowable javetUnknownExecutionException = (jthrowable)jniEnv->NewObject(
- jclassJavetUnknownExecutionException,
- jmethodIDJavetUnknownExecutionExceptionConstructor,
- jStringExceptionMessage);
- jniEnv->Throw(javetUnknownExecutionException);
+ if (v8TryCatch.HasTerminated()) {
+ jthrowable javetTerminatedException = (jthrowable)jniEnv->NewObject(
+ jclassJavetTerminatedException,
+ jmethodIDJavetTerminatedExceptionConstructor,
+ v8TryCatch.CanContinue());
+ jniEnv->Throw(javetTerminatedException);
}
else {
- v8::String::Utf8Value scriptResourceName(isolate, compileErrorMessage->GetScriptResourceName());
- jstring jStringScriptResourceName = jniEnv->NewStringUTF(*scriptResourceName);
- v8::String::Value sourceLine(isolate, compileErrorMessage->GetSourceLine(v8Context).ToLocalChecked());
- jstring jStringSourceLine = jniEnv->NewString(*sourceLine, sourceLine.length());
- jthrowable javetConverterException = (jthrowable)jniEnv->NewObject(
- jclassJavetExecutionException,
- jmethodIDJavetExecutionExceptionConstructor,
- jStringExceptionMessage,
- jStringScriptResourceName,
- jStringSourceLine,
- compileErrorMessage->GetLineNumber(v8Context).FromMaybe(0),
- compileErrorMessage->GetStartColumn(),
- compileErrorMessage->GetEndColumn(),
- compileErrorMessage->GetStartPosition(),
- compileErrorMessage->GetEndPosition() );
- jniEnv->Throw(javetConverterException);
- jniEnv->DeleteLocalRef(jStringSourceLine);
- jniEnv->DeleteLocalRef(jStringScriptResourceName);
+ v8::String::Value exceptionMessage(isolate, v8TryCatch.Exception());
+ jstring jStringExceptionMessage = jniEnv->NewString(*exceptionMessage, exceptionMessage.length());
+ auto v8LocalMessage = v8TryCatch.Message();
+ if (v8LocalMessage.IsEmpty()) {
+ jthrowable javetUnknownExecutionException = (jthrowable)jniEnv->NewObject(
+ jclassJavetUnknownExecutionException,
+ jmethodIDJavetUnknownExecutionExceptionConstructor,
+ jStringExceptionMessage);
+ jniEnv->Throw(javetUnknownExecutionException);
+ }
+ else {
+ v8::String::Utf8Value scriptResourceName(isolate, v8LocalMessage->GetScriptResourceName());
+ jstring jStringScriptResourceName = jniEnv->NewStringUTF(*scriptResourceName);
+ v8::String::Value sourceLine(isolate, v8LocalMessage->GetSourceLine(v8Context).ToLocalChecked());
+ jstring jStringSourceLine = jniEnv->NewString(*sourceLine, sourceLine.length());
+ jthrowable javetConverterException = (jthrowable)jniEnv->NewObject(
+ jclassJavetExecutionException,
+ jmethodIDJavetExecutionExceptionConstructor,
+ jStringExceptionMessage,
+ jStringScriptResourceName,
+ jStringSourceLine,
+ v8LocalMessage->GetLineNumber(v8Context).FromMaybe(0),
+ v8LocalMessage->GetStartColumn(),
+ v8LocalMessage->GetEndColumn(),
+ v8LocalMessage->GetStartPosition(),
+ v8LocalMessage->GetEndPosition());
+ jniEnv->Throw(javetConverterException);
+ jniEnv->DeleteLocalRef(jStringSourceLine);
+ jniEnv->DeleteLocalRef(jStringScriptResourceName);
+ }
+ jniEnv->DeleteLocalRef(jStringExceptionMessage);
}
- jniEnv->DeleteLocalRef(jStringExceptionMessage);
}
void ThrowJavetV8RuntimeLockConflictException(JNIEnv* jniEnv, const char* message) {
diff --git a/cpp/jni/javet_exceptions.h b/cpp/jni/javet_exceptions.h
index f1cab06cd..767b8bf52 100644
--- a/cpp/jni/javet_exceptions.h
+++ b/cpp/jni/javet_exceptions.h
@@ -27,6 +27,8 @@ namespace Javet {
static jclass jclassJavetConverterException;
static jclass jclassJavetExecutionException;
static jmethodID jmethodIDJavetExecutionExceptionConstructor;
+ static jclass jclassJavetTerminatedException;
+ static jmethodID jmethodIDJavetTerminatedExceptionConstructor;
static jclass jclassJavetUnknownCompilationException;
static jmethodID jmethodIDJavetUnknownCompilationExceptionConstructor;
static jclass jclassJavetUnknownExecutionException;
diff --git a/docs/development/best_practices.rst b/docs/development/best_practices.rst
new file mode 100644
index 000000000..b9a57e2ca
--- /dev/null
+++ b/docs/development/best_practices.rst
@@ -0,0 +1,28 @@
+==============
+Best Practices
+==============
+
+Thread, Engine and Pool
+=======================
+
+* Always get 1 Javet engine from the pool in 1 thread.
+* If multiple context is required in 1 thread, there are 2 options.
+ * Call ``resetContext()`` between context switch.
+ * Obtain multiple V8Runtime instances.
+* Do not pass Javet engine to other threads.
+* Always return Javet engine to pool in the end via try-with-resource or calling ``close()`` explicitly.
+* Subclass Javet engine pool and Javet engine to complete your customization. Indeed, they are open to full customization.
+
+Resource Management
+===================
+
+* Dangling V8 objects will be forced to be recycled by Javet under the following scenarios and corresponding log will reflect that. Keeping an eye on the log helps address memory leak issues in the early stage.
+ * Engine is closed.
+ * Pool is closed.
+ * Context is reset.
+ * Isolate is reset.
+* Always apply try-with-resource to Javet objects regardless of primitive or reference if they are not returned to Javet.
+* Always prohibit calling ``close()`` of Javet objects if they will be returned to Javet.
+* If the lifecycle of V8 objects is uncertain, calling ``setWeak()`` is the only way so that calling ``close()`` is no longer required. Be careful, calling ``close()`` after calling ``setWeak()`` may lead to V8 core dump immediately.
+
+[`Home <../../README.rst>`_] [`Development `_]
diff --git a/docs/build.rst b/docs/development/build.rst
similarity index 97%
rename from docs/build.rst
rename to docs/development/build.rst
index 8f3d866a1..3d610bb24 100644
--- a/docs/build.rst
+++ b/docs/development/build.rst
@@ -89,4 +89,4 @@ Also, please make sure ``args.gn`` file looks like the following.
``v8_monolith`` is the build target.
-[`Home <../README.rst>`_]
+[`Home <../../README.rst>`_] [`Development `_]
diff --git a/docs/development/design.rst b/docs/development/design.rst
new file mode 100644
index 000000000..4620f25c8
--- /dev/null
+++ b/docs/development/design.rst
@@ -0,0 +1,58 @@
+============
+Javet Design
+============
+
+Architecture
+============
+
+.. image:: ../resources/images/javet_architecture.png?raw=true
+ :alt: Javet Architecture
+
+Primitive and Reference Types in Javet
+--------------------------------------
+
+There is a vague boundary between V8 primitive and reference types. In Javet, the definition of primitive is a mixture of both V8 and Java primitive types as a trade-off in design.
+
+=========================== ======================= ==============================
+Feature Primitive Reference
+=========================== ======================= ==============================
+Interception No Yes
+Memory Copy Copy by Value Copy by Reference
+Resource Leak Not Possible Possible
+Set to Weak No Yes
+=========================== ======================= ==============================
+
+Reference typed objects keep memory footprint in V8 + JNI + JVM. All resource will be recycled when ``close()`` is called. That is quite an old school way of managing resource. Javet tries to hide that kind of tedious work from Java applications via try-with-resource.
+
+Please refer to `Best Practices `_ for detail.
+
+Engine Pool
+===========
+
+.. image:: ../resources/images/javet_engine_pool.png?raw=true
+ :alt: Javet Engine Pool
+
+V8 Isolate and Context in Javet
+-------------------------------
+
+`Getting started with embedding V8 `_ is an excellent article that explains the concepts, design, insights of V8. In summary:
+
+* An isolate is a VM instance with its own heap.
+* A context is an execution environment that allows separate, unrelated, JavaScript applications to run in a single instance of V8.
+
+In Javet, that model is simplified to 1 engine - 1 runtime - 1 isolate - 1 context. In V8Runtime, ``resetIsolate()`` and ``resetContext()`` are both exposed. It is recommended to always use ``resetContext()`` to get a brand new V8 context for the following reasons.
+
+* ``resetContext()`` is a much cheaper operation with much better performance.
+* ``resetContext()`` is good enough in terms of getting a brand new V8 context.
+
+Javet Engine Pool
+-----------------
+
+Multiple Javet engines are managed by Javet Engine Pool which works almost the same way as a typical DB connection pool. Javet Engine Pool is thread-safe. However, Javet Engine is **NOT** thread-safe because it is designed to be single-threaded and lock free for the following reasons.
+
+* V8 isolate and V8 context are single-threaded. Thread context violation results in V8 core dump immediately.
+* Javet Engine performs better without locks. Actually, Javet engine only validates current thread ID to minimize the performance overhead.
+
+Please refer to `Best Practices `_ for detail.
+
+[`Home <../../README.rst>`_] [`Development `_]
diff --git a/docs/development/index.rst b/docs/development/index.rst
new file mode 100644
index 000000000..28869a82f
--- /dev/null
+++ b/docs/development/index.rst
@@ -0,0 +1,11 @@
+===========
+Development
+===========
+
+* `Development Tools `_
+* `Build `_
+* `Design `_
+* `Best Practices `_
+* `Performance `_
+
+[`Home <../../README.rst>`_]
diff --git a/docs/performance.rst b/docs/development/performance.rst
similarity index 73%
rename from docs/performance.rst
rename to docs/development/performance.rst
index bf8624ec3..816904c8f 100644
--- a/docs/performance.rst
+++ b/docs/development/performance.rst
@@ -11,12 +11,12 @@ Here is the performance test result from i7 10700K + Windows 10. Test case is ju
=============================== ===============
Case TPS
=============================== ===============
-Single Context with 1 Thread 759,589
-Ad-hoc Context with 1 Thread 2,921
-Single Context with 8 Threads 4,464,285
-Ad-hoc Context with 8 Threads 15,209
+Single Context with 1 Thread 752,728
+Ad-hoc Context with 1 Thread 2,895
+Single Context with 8 Threads 4,268,943
+Ad-hoc Context with 8 Threads 15,278
=============================== ===============
Reference: https://v8.dev/docs/embed#contexts
-[`Home <../README.rst>`_]
+[`Home <../../README.rst>`_] [`Development `_]
diff --git a/docs/development.rst b/docs/development/tools.rst
similarity index 65%
rename from docs/development.rst
rename to docs/development/tools.rst
index 49776a008..58f950747 100644
--- a/docs/development.rst
+++ b/docs/development/tools.rst
@@ -1,38 +1,40 @@
=================
-Javet Development
-=================
-
Development Tools
=================
JDK
----
+===
Javet development requires JDK 8 to be installed, though Javet supports JDK 8+. JDK 6 support has been dropped because a few JDK 8 features are heavily used in Javet.
-IDE
----
+IntelliJ
+========
I personally recommend IntelliJ IDEA.
Gradle
-------
+======
For now, Gradle v6.7 + Kotlin DSL constructs the build system.
-Maven
------
+Maven (Optional)
+================
+
+Maven v3.6.3+ is used for packaging bundle to maven central.
-Maven v3.6.3+ is the one.
+Visual Studio Community 2019 (Optional)
+=======================================
+
+Visual Studio Community 2019 is used for JNI development.
Python 3.8+ (Optional)
-----------------------
+======================
Python 3.8+ is required if you want to upgrade the version.
NodeJS (Optional)
------------------
+=================
NodeJS 14.5+ is required if you want to go over the tutorial because a few examples use some node modules. After installing NodeJS, please visit ``scripts/node`` directory and run ``npm install``.
-[`Home <../README.rst>`_]
+[`Home <../../README.rst>`_] [`Development `_]
diff --git a/docs/faq/history_with_j2v8.rst b/docs/faq/history_with_j2v8.rst
index a7d0e9516..9d6161d03 100644
--- a/docs/faq/history_with_j2v8.rst
+++ b/docs/faq/history_with_j2v8.rst
@@ -1,3 +1,4 @@
+=================
History with J2V8
=================
diff --git a/docs/faq/index.rst b/docs/faq/index.rst
index d010528a6..727c78929 100644
--- a/docs/faq/index.rst
+++ b/docs/faq/index.rst
@@ -3,5 +3,6 @@ FAQ
===
* `History with J2V8 `_
+* `What is the Motivation? `_
[`Home <../../README.rst>`_]
diff --git a/docs/faq/what_is_the_motivation.rst b/docs/faq/what_is_the_motivation.rst
new file mode 100644
index 000000000..57490579b
--- /dev/null
+++ b/docs/faq/what_is_the_motivation.rst
@@ -0,0 +1,13 @@
+=======================
+What is the Motivation?
+=======================
+
+I used to take a try of J2V8 and find it's quite compelling. However, J2V8 is slowly dying, with serious memory leak issues, V8 version issue, etc.
+
+Sometimes starting from scratch implies lower cost than upgrading an existing solution. I think it might be true here in this project. I've learned quite a lot by manually fixing the Windows and Linux build system of J2V8.
+
+Also, I had got many ideas on how the API will look like. At the end of 2020, I thought I would be able to write a new one from scratch and leave J2V8 behind. Indeed, I made it few months later.
+
+Please refer to `History with J2V8 `_ for detail.
+
+[`Home <../../README.rst>`_] [`FAQ `_]
diff --git a/docs/release_notes.rst b/docs/release_notes.rst
index ccd612c25..df8a86609 100644
--- a/docs/release_notes.rst
+++ b/docs/release_notes.rst
@@ -2,6 +2,16 @@
Release Notes
=============
+0.7.2
+-----
+
+* Added ``setFunction(String functionName, String codeString)`` to ``IV8ValueObject``
+* Added ``equals()`` and ``strictEquals()`` and ``sameValue()`` to ``IV8Value``
+* Added ``getIdentityHash()`` to ``IV8ValueReference``
+* Added ``isDead()``, ``isInUse()``, ``callAsConstructor()`` and ``terminateExecution()`` to ``V8Runtime``
+* Added V8 typed array and data view
+* Added ``IJavetEngineGuard``
+
0.7.1
-----
diff --git a/docs/resources/images/javet_architecture.drawio b/docs/resources/images/javet_architecture.drawio
new file mode 100644
index 000000000..128975c74
--- /dev/null
+++ b/docs/resources/images/javet_architecture.drawio
@@ -0,0 +1 @@
+7Z1bd5s4EIB/jR83BxBg/Jhr25ymm2160mbfZJCxshjlYDmx++tXwgIDIyfOrrl0tfFDzAAC5huNNGLmeITOF+sPGX6a37CIJCPHitYjdDFyHNtFvvgnJRslsWwliTMaKdlOcEd/kuJAJV3RiCxrB3LGEk6f6sKQpSkJeU2Gs4y91A+bsaR+1SccEyC4C3ECpd9pxOdbaeBZO/lHQuN5cWXbUnsWuDhYCZZzHLGXighdjtB5xhjfflusz0kitVfoZXve1Z695Y1lJOWHnDB5/PjlDza/9n8u3Yg+4IdH9OG3YNvKM05W6oHVzfJNoYGMrdKIyEasETp7mVNO7p5wKPe+COhCNueLRGzZ4uuMpVxBtOXh8CbVfT+TjJN1RaRu+gNhC8KzjThE7UVKfy879XuF+ucV1aOJEmKFPC6b2mlFfFGKeYeS7PcoyT5ASTRJzlnCsvxcNJsRPwyFfMkz9hep7InGk6l1JDW6Sjub+mZFq7av0aoTtKVVB2j1PgB6FQ/H68qrKyllKWloVIlwQuNUbIZCZUTIz6SqqOjYp2rHgkaRvIyWVt3oc6tWN6Xpd+9mUToJBcODMFwdi7ZQoHYNPMIkmGkN3A8DMp0dx8APsPCgUwN3gVavv3wyxMIdf1gW7rVs4R4JIldn4YEzRb5/pJHQf9PCy3lTNybuQxO/vzHExF3XG5SJTyAL/Ey4EJ1modROyFcZ+SXg1OeRR+o9jeHB1kwrUZe8iht4zSeRNDqVQcxO6RFezksnVYEm5beYCxDp1r4tVKIsAhdHo1ihz2zzQzWSbzxIJCdesXmxVoi2W5tia035j8r3yllia3eS3CjO2QtxyVZZSF7T1fY4jrOY8LfdPIlqQR00iSp0DfNClpEEc/pcDwV1hqCucMtoyncW5zUsrumGt4+tTqpGbo12mtNFGzUa2uoFNJSbZfnU/8JS4VT9NqMLmqtmmP7kCP5i0lC6Dx2GNmBqzV/AWfpXMiPiCcM2KCRkxgfHIOibAZzTf2ZCO0D/75tMNhZNQEdoLhh48qONp/I/sSfOcETF6ZV90/zTyliKNGs03XKB8/tbki3pkhPlEtuDo1E1wf40x9AEF4REv9IzDTzXa2elB/XuuGCUkK4WU6E8w3rNuB4waJxZpwGDPQZcpjSmrXeYoXOxNaFBt2DgqvyUsYTg1HQymhWPbsnAIFvohqaxaWBsZ1i+rGi4AuYCczgvNgxL766sfIQdl5P8z3gyfbuyYrWpQub36aN8hW7YdLmxSuNYfYOBcf5pluGN6Vw0MWa3XGDsfyO0bDgVTXDZLRUY+d8R433YpG8qMOS/WqUhp6ztEGZwaJqL9/2PLzDsv9sspqztRczhk+l9hIFx/1cSX66NG2QAmd5HGRj332ZsQZdtR5jDR9P3UFN02jqatXHTZXtocQyCof8noTvMxdObzqbvkQbBGPMyy/4H0/tAgzQvmOmMhJtQEBHnLuVFZWpInkpqzcpJtZWQ57z2AqfRSFYfpDgm8ttUPu59ABfchpAi0EK5QLnk+cq7aW3ST3tMYYgKmDZ4FZl7VJK9vr8xl56mQ3ZMD4ZLAEaVQlHlIxVSJutpveFezYs2nmTLi3Usq6pOtnVMzgl/Yd/xRiUEnuUlVdaJ9J15vRXyNEheW9V+/xr5EQA7DcC2Jm3W7tblwqjrnD1tSteZi4/f/Y6WNVuhLbcr3NwL+WmJm8atdswNxmS/dsfsdyoEAGsCu24BFxfb0zHbTH7soHNeXVnWsWr7mux0ye0ds4PB332gd6WtvvglduSRsa7vTPwxwscqLWi+3B1D/Wtrz1pTP4zv9mds/8ffvAM4hxYGtgYHxnj7fVm7cN4eWV4bp1qAo1u16hbOAZWCsCrnFQbvnpO9WQxT+NaBVLm4dgOh3WBzaJmL6zc6qt9oqOUyF/eASO8o6Muaq0qZ1cOoWmX1Rs1VWWf1oK7cRs1VYWZvFl0V/mwg9uh4DXv0/qE9ImuPb+rKHmFgemZmGjAaWoa2C2PPC7aaJsZNrtBkWHnAHowZPwndxeYVmzTL03snAyPCz8y8xHl3aB3GAVjujKxo8OyBjTEejOH/FFPOSNY1fKML44YaEMdrAHUaKvpwrDEzgx4Vy11DSW/w4VhjZAo9ANN3eoMPRxsDc+gBlr5z6Hw41BiYRO86Q3NjcKG4k+K5wZEBaVq9dxi4SmxqfQPoNb2PMbD2xMz6BkCm914DF9gNzaL3Btdp4FqzkVn07uBCGbjSbGSmNgDTd48p7sf4Yi3gy/ruMmNd9B+vFuIRl6bBAd1GMwcYHweO2Nz9mMH2HejuNyHQ5d8=
\ No newline at end of file
diff --git a/docs/resources/images/javet_architecture.png b/docs/resources/images/javet_architecture.png
new file mode 100644
index 000000000..295eeac6c
Binary files /dev/null and b/docs/resources/images/javet_architecture.png differ
diff --git a/docs/resources/images/javet_engine_pool.drawio b/docs/resources/images/javet_engine_pool.drawio
new file mode 100644
index 000000000..c9e98852e
--- /dev/null
+++ b/docs/resources/images/javet_engine_pool.drawio
@@ -0,0 +1 @@
+7VpZc5s6FP41fkyH3fCYOGm63KW9mdvbPCpIBqUy8sjy1l9/JSPMImHHtcHNOMlMgo4WxPed83E4MHBHk9U9A9P0TwoRGTgWXA3c24Hj2J4biH/SslYWy1aWhGGobKXhAf9ExUBlnWOIZrWBnFLC8bRujGmWoZjXbIAxuqwPG1NSP+sUJEgzPMSA6Nb/MORpbg19q7R/QDhJizPbluqZgGKwMsxSAOmyYnLvBu6IUcrzo8lqhIhEr8Aln/e+pXe7MYYy/pIJ0fOHv77S9FPwc+ZB/Agen937qzBfZQHIXF2w2ixfFwgwOs8gkotYA/dmmWKOHqYglr1LQbqwpXxCRMsWh2OacUWiLYfrm1T7XiDG0apiUpu+R3SCOFuLIarXVfgtS/jdobKlFeidwggU5cl2qRIVcaCAOQCkSAPpE1ggLkx3WYIzJA6+CJ/UkBMXyOvwzDijP9CIEsqEJaNirsAME9IwAYKTTDRjARsS9hsJFxZeea06JhhCeRojH3XGNpSoTTUpCk5DkaeQ3wa5zphvYqwrwobOIW5tv8CtKxQNHHc8RkEca3yKHjiMnqwTOX4DVU9HdSs2NVS7g9XVYP0WvgqvP56MYZ0MXyfD69XDAw13BMWNSzUp4ylNaAbIXWltIFSO+YPSqaLqGXG+VuoA5pzWiUQrzL/L6e981Xqs9Nyu1MqbxrpoZOJ6v1cbj+UKsllO27TKefBa3r9L9xCW91jCVBJcudPIdiUQvVv5uysQZ3TOYrQLY0/lG4AliO8a6OcDJQM7fYkhAjhe1FMLk29sporLB+vKgCnFGZ9VVv4iDa0uatfzAXGQL1g63XZnR/ihp0nCxxkVV4mOFNwGu5o0aIocQyfcqcgJAxCjmpOMx8A/lVr7dfTDcwuErxEzEphKbe6XGAAj6JuIAcizXec04EcN1zdkIP2ir98W+5TnijiXUt0mz2eX2WEn6rlXHq0G+bnMq0kl/8eqsN+HCg8vOdgNiXG/wR695WJdi0RxO92bi4X275iLFY/EnapAgdFbLtbIxezhmRWicMqL1GfHOjf6evHnLRlrw8o9TzIW9ZKMFX7XrQzrVbILCnZDtb6rYL8Zsmj1+fPXh8Vy9O9HmPwNn+MrXWmPRL0OKvRRCD0TqKHz5AZlPV1D0IBzK6h24wZmKv3aJlQ7g1UvqL++Vx8n4CXYWwWO+nR2vcbzCjO9kzJiKLuZGPG7YiTQGPkW/jPPOJ70nYS/VP2Pg7+tqFLB3/iutiv89UJIoVO/r0Bpr8uPoyT090VErzfkg74wuAiNMj2O9ipS+vcMlyVS0ZlFqkjd3lTqLCUaMyd6hlt85IOKTDcVZ3UsmhGx6euBExDJzRMTRwnfwJJb5qRpIbiwCFSsSrDl3WLD5Yi2OdtS3gFzts+dO+YIo75hiBeFSUMBSxBmOEsIuuIpQ0A4yrvKapW5huXaYds7tYKBBTJYv0IrBpn4+4Q2tYkZ4q1bOnmIETTmhgDjslD0C9HVKOpYm5/TRF2zHhIYnisdQ9RtX7EcEHaiWX7bmNdWyk9E3bv/AQ==
\ No newline at end of file
diff --git a/docs/resources/images/javet_engine_pool.png b/docs/resources/images/javet_engine_pool.png
new file mode 100644
index 000000000..51a51630d
Binary files /dev/null and b/docs/resources/images/javet_engine_pool.png differ
diff --git a/docs/todo_list.rst b/docs/todo_list.rst
index 383cbed75..5a57f3824 100644
--- a/docs/todo_list.rst
+++ b/docs/todo_list.rst
@@ -2,8 +2,8 @@
TODO List
=========
-* To support more types that are not supported by ECMAScript, e.g. BigDecimal, etc.
-* To revive NodeJS.
+* To support more types that are not supported by ECMAScript, e.g. BigDecimal, byte[], etc.
+* To build NodeJS in.
* To implement runtime debugging capability.
[`Home <../README.rst>`_]
diff --git a/docs/tutorial/hello_javet.rst b/docs/tutorial/hello_javet.rst
index 2141b833f..516700a38 100644
--- a/docs/tutorial/hello_javet.rst
+++ b/docs/tutorial/hello_javet.rst
@@ -13,24 +13,22 @@ Maven
com.caoccao.javetjavet
- 0.7.1
+ 0.7.2
-Gradle Kotlin
--------------
+Gradle Kotlin DSL
+-----------------
.. code-block:: kotlin
- dependencies {
- implementation("com.caoccao.javet:javet:0.7.1")
- }
+ implementation("com.caoccao.javet:javet:0.7.2")
-Gradle Groovy
--------------
+Gradle Groovy DSL
+-----------------
.. code-block:: groovy
- compile group: 'com.caoccao.javet', name: 'javet', version: '0.7.1'
+ implementation 'com.caoccao.javet:javet:0.7.2'
Print **Hello Javet**
=====================
@@ -51,9 +49,8 @@ Print **1 + 1**
.. code-block:: java
// Step 1: Create a V8 runtime from V8 host in try resource.
- try (V8Runtime v8Runtime = V8Host.getInstance().createV8Runtime()) {
- // Step 2: Request a lock.
- v8Runtime.lock();
+ // Step 2: Request a lock.
+ try (V8Runtime v8Runtime = V8Host.getInstance().createV8Runtime().lock()) {
// Step 3: Execute a string as JavaScript code and print the result to console.
System.out.println("1 + 1 = " + v8Runtime.getExecutor("1 + 1").executeInteger()); // 2
// Step 4: Resource including the lock is recycled automatically at the end of the try resource block.
diff --git a/docs/tutorial/index.rst b/docs/tutorial/index.rst
index eb8575b86..39de783c0 100644
--- a/docs/tutorial/index.rst
+++ b/docs/tutorial/index.rst
@@ -6,6 +6,9 @@ Tutorial
* `Know the Lock `_
* `Memory Management `_
* `Manipulate V8 Function `_
+* `Spring Integration `_
+* `Logging `_
+* `Termination `_
* `Polyfill `_
Complete tutorial is available at `here <../../src/test/java/com/caoccao/javet/tutorial>`_.
diff --git a/docs/tutorial/logging.rst b/docs/tutorial/logging.rst
new file mode 100644
index 000000000..a4d77f373
--- /dev/null
+++ b/docs/tutorial/logging.rst
@@ -0,0 +1,79 @@
+=======
+Logging
+=======
+
+As Javet is a fundamental SDK, it doesn't rely on any other libraries except JDK so that Javet users don't get dependency hell. That also means Javet has to use the JDK logging API, but Javet allows injecting 3rd party logging API.
+
+Step 1: Implement IJavetLogger
+==============================
+
+``IJavetLogger`` is the the only logging interface accepted by Javet. You may implement ``IJavetLogger`` with ``slf4j`` as following.
+
+.. code-block:: java
+
+ import com.caoccao.javet.interfaces.IJavetLogger;
+ import org.slf4j.Logger;
+ import org.slf4j.LoggerFactory;
+
+ public class MyJavetLogger implements IJavetLogger {
+ protected Logger logger;
+
+ public MyJavetLogger(String name) {
+ logger = LoggerFactory.getLogger(name);
+ }
+
+ @Override
+ public void debug(String message) {
+ if (logger.isDebugEnabled()) {
+ logger.debug(message);
+ }
+ }
+
+ @Override
+ public void error(String message) {
+ if (logger.isDebugEnabled()) {
+ logger.error(message);
+ }
+ }
+
+ @Override
+ public void error(String message, Throwable throwable) {
+ if (logger.isDebugEnabled()) {
+ logger.error(message, throwable);
+ }
+ }
+
+ @Override
+ public void info(String message) {
+ if (logger.isInfoEnabled()) {
+ logger.info(message);
+ }
+ }
+
+ @Override
+ public void warn(String message) {
+ if (logger.isWarnEnabled()) {
+ logger.warn(message);
+ }
+ }
+ }
+
+Step 2: Inject the Logger
+=========================
+
+Injecting the logger is quite simple.
+
+* Create an instance of the logger.
+* Set the logger to a config.
+* Set the config to a pool.
+
+.. code-block:: java
+
+ MyJavetLogger javetLogger = new MyJavetLogger("TestLogger");
+ JavetEngineConfig javetEngineConfig = new JavetEngineConfig();
+ javetEngineConfig.setJavetLogger(javetLogger);
+ JavetEnginePool javetEnginePool = new JavetEnginePool(javetEngineConfig);
+
+Now, Javet is integrated into your logging system.
+
+[`Home <../../README.rst>`_] [`Tutorial `_]
diff --git a/docs/tutorial/manipulate_v8_function.rst b/docs/tutorial/manipulate_v8_function.rst
index 9f9f48e6c..7defa8416 100644
--- a/docs/tutorial/manipulate_v8_function.rst
+++ b/docs/tutorial/manipulate_v8_function.rst
@@ -36,10 +36,14 @@ Option 2: The Recommended Way
// Once this function is set to weak, its lifecycle is automatically managed by Javet + V8.
// There is no need to call close() any more.
+ // Alternatively, setFunction() makes that easy with only one line.
+ v8ValueObject.setFunction("test", javetCallbackContext);
+ // An instance of V8ValueFunction is created and set to weak internally.
+
Automatic Type Conversion
=========================
-Javet is capable of automatically converting its internal ``V8Value`` to other types and that capability can be manipulated by ``JavetConverterUtils`` which also supports custom type conversion. So, the following 4 functions are all the same and valid.
+Javet is capable of automatically converting its internal ``V8Value`` to primitive types by inspecting the function signature. So, the following 4 functions are all the same and valid.
.. code-block:: java
@@ -68,4 +72,6 @@ Javet is capable of automatically converting its internal ``V8Value`` to other t
Note: Primitive types must be in their object form in the method signature. E.g. ``boolean`` must be set to ``Boolean``, ``int`` must be set to ``Integer``, etc. Why? Because the converted value could be ``null`` which would cause JDK to complain with an exception.
+Please review `test cases <../../src/test/java/com/caoccao/javet/values/reference/TestV8ValueFunction.java>`_ for more detail.
+
[`Home <../../README.rst>`_] [`Tutorial `_]
diff --git a/docs/tutorial/memory_management.rst b/docs/tutorial/memory_management.rst
index 554b79a93..725474a79 100644
--- a/docs/tutorial/memory_management.rst
+++ b/docs/tutorial/memory_management.rst
@@ -24,8 +24,8 @@ V8 generally categorizes objects in memory to 3 types.
2. ``v8::Persistent`` - Its lifecycle is managed by V8 GC.
3. ``v8::External`` - V8 GC treats it as root object so that it lives as long as the V8 isolate lives.
-Solution: Weak Reference
-========================
+Solution 1: Weak Reference
+==========================
Javet directly borrows the way V8 manages objects in JVM. The rule is simple in the following 2 patterns.
@@ -59,4 +59,41 @@ Automatically Manage V8 Objects
Note: V8 does not recycle objects that are referenced by other objects. Please make sure the object chain is broken so that GC can work as expected. ``com.caoccao.javet.interception.logging.JavetStandardConsoleInterceptor`` is a good sample showing how to deal with that.
+Solution 2: ArrayBuffer
+=======================
+
+The ArrayBuffer object is used to represent a generic, fixed-length raw binary data buffer.
+
+It is an array of bytes, often referred to in other languages as a "byte array".You cannot directly manipulate the contents of an ArrayBuffer; instead, you create one of the typed array objects or a DataView object which represents the buffer in a specific format, and use that to read and write the contents of the buffer.
+
+Javet offers complete support to all the typed arrays as well as ``DataView`` as following. There is a ``java.nio.ByteBuffer`` inside every typed array and ``DataView``. That ``ByteBuffer`` directly links to the corresponding backing store of V8 typed array. In other words, Javet and V8 can both access the same address to achieve zero memory copy. Please consider using typed array in performance sensitive scenarios.
+
++-------------------+-----------------------------+---------------+------------------------------------------------------------------------------------+---------------------+-------------------------------+
+| Type | Value Range | Size in bytes | Description | Web IDL type | Equivalent C type |
++===================+=============================+===============+====================================================================================+=====================+===============================+
+| Int8Array | -128 to 127 | 1 | 8-bit two's complement signed integer | byte | int8_t |
++-------------------+-----------------------------+---------------+------------------------------------------------------------------------------------+---------------------+-------------------------------+
+| Uint8Array | 0 to 255 | 1 | 8-bit unsigned integer | octet | uint8_t |
++-------------------+-----------------------------+---------------+------------------------------------------------------------------------------------+---------------------+-------------------------------+
+| Uint8ClampedArray | 0 to 255 | 1 | 8-bit unsigned integer (clamped) | octet | uint8_t |
++-------------------+-----------------------------+---------------+------------------------------------------------------------------------------------+---------------------+-------------------------------+
+| Int16Array | -32768 to 32767 | 2 | 16-bit two's complement signed integer | short | int16_t |
++-------------------+-----------------------------+---------------+------------------------------------------------------------------------------------+---------------------+-------------------------------+
+| Uint16Array | 0 to 65535 | 2 | 16-bit unsigned integer | unsigned short | uint16_t |
++-------------------+-----------------------------+---------------+------------------------------------------------------------------------------------+---------------------+-------------------------------+
+| Int32Array | -2147483648 to 2147483647 | 4 | 32-bit two's complement signed integer | long | int32_t |
++-------------------+-----------------------------+---------------+------------------------------------------------------------------------------------+---------------------+-------------------------------+
+| Uint32Array | 0 to 4294967295 | 4 | 32-bit unsigned integer | unsigned long | uint32_t |
++-------------------+-----------------------------+---------------+------------------------------------------------------------------------------------+---------------------+-------------------------------+
+| Float32Array | 1.2×10-38 to 3.4×1038 | 4 | 32-bit IEEE floating point number (7 significant digits e.g., 1.234567) | unrestricted float | float |
++-------------------+-----------------------------+---------------+------------------------------------------------------------------------------------+---------------------+-------------------------------+
+| Float64Array | 5.0×10-324 to 1.8×10308 | 8 | 64-bit IEEE floating point number (16 significant digits e.g., 1.23456789012345) | unrestricted double | double |
++-------------------+-----------------------------+---------------+------------------------------------------------------------------------------------+---------------------+-------------------------------+
+| BigInt64Array | -263 to 263-1 | 8 | 64-bit two's complement signed integer | bigint | int64_t (signed long long) |
++-------------------+-----------------------------+---------------+------------------------------------------------------------------------------------+---------------------+-------------------------------+
+| BigUint64Array | 0 to 264-1 | 8 | 64-bit unsigned integer | bigint | uint64_t (unsigned long long) |
++-------------------+-----------------------------+---------------+------------------------------------------------------------------------------------+---------------------+-------------------------------+
+
+Please refer to `TestV8ValueTypedArray <../../src/test/java/com/caoccao/javet/values/reference/TestV8ValueTypedArray.java>`_ and `TestV8ValueDataView <../../src/test/java/com/caoccao/javet/values/reference/TestV8ValueDataView.java>`_ for sample code snippets.
+
[`Home <../../README.rst>`_] [`Tutorial `_]
diff --git a/docs/tutorial/polyfill.rst b/docs/tutorial/polyfill.rst
index 8ee325473..a5fb807f2 100644
--- a/docs/tutorial/polyfill.rst
+++ b/docs/tutorial/polyfill.rst
@@ -14,21 +14,36 @@ decimal.js
JavetOSUtils.WORKING_DIRECTORY,
"scripts/node/node_modules/decimal.js/decimal.js");
if (decimalJSFile.exists() && decimalJSFile.canRead()) {
- logger.logInfo("Loading {0}.", decimalJSFile.getAbsolutePath());
- v8Runtime = V8Host.getInstance().createV8Runtime();
- v8Runtime.lock();
+ getLogger().logInfo("Loading {0}.", decimalJSFile.getAbsolutePath());
+ V8Runtime v8Runtime = iJavetEngine.getV8Runtime();
v8Runtime.getExecutor(decimalJSFile).executeVoid();
} else {
- logger.logError("{0} is not found.", decimalJSFile.getAbsolutePath());
- logger.logError("Please make sure NodeJS is installed, then visit script/node directory and run npm install.");
+ getLogger().logError("{0} is not found.", decimalJSFile.getAbsolutePath());
+ getLogger().logError("Please make sure NodeJS is installed, then visit script/node directory and run npm install.");
}
}
public void test() throws JavetException {
- logger.logInfo("1.23 + 2.34 = {0}", v8Runtime.getExecutor(
+ V8Runtime v8Runtime = iJavetEngine.getV8Runtime();
+ getLogger().logInfo("1.23 + 2.34 = {0}", v8Runtime.getExecutor(
"const a = new Decimal(1.23);" +
"const b = new Decimal(2.34);" +
"a.add(b).toString();").executeString());
+ try (V8ValueFunction v8ValueFunctionDecimal = v8Runtime.getGlobalObject().get("Decimal")) {
+ try (V8ValueObject v8ValueObjectDecimal = v8ValueFunctionDecimal.call(
+ null, new V8ValueString("123.45"))) {
+ getLogger().logInfo(v8ValueObjectDecimal.toString());
+ if (v8ValueObjectDecimal.hasOwnProperty("constructor")) {
+ try (V8ValueFunction v8ValueFunction = v8ValueObjectDecimal.get("constructor")) {
+ String name = v8ValueFunction.getString("name");
+ if ("Decimal".equals(name)) {
+ BigDecimal bigDecimal = new BigDecimal(v8ValueObjectDecimal.toString());
+ getLogger().logInfo("BigDecimal: {0}", bigDecimal.toString());
+ }
+ }
+ }
+ }
+ }
}
Please refer to `source code <../../src/test/java/com/caoccao/javet/tutorial/DecimalJavet.java>`_ for more detail.
diff --git a/docs/tutorial/spring_integration.rst b/docs/tutorial/spring_integration.rst
new file mode 100644
index 000000000..13ccd3ae5
--- /dev/null
+++ b/docs/tutorial/spring_integration.rst
@@ -0,0 +1,70 @@
+==================
+Spring Integration
+==================
+
+As Javet is a fundamental SDK, it doesn't rely on Spring Framework so that Javet users don't get dependency hell. But, Javet can be integrated with Spring easily.
+
+Configuration
+=============
+
+* Create a Spring configuration.
+* Declare ``IJavetEnginePool`` as ``@Bean``.
+* Set the pool implement in ``@PostConstruct``.
+
+.. code-block:: java
+
+ @Configuration
+ @PropertySource("classpath:javet-engine.properties")
+ @ConfigurationProperties(prefix = "javet.engine")
+ public class MyJavetEngineConfig {
+ @Value("32")
+ private int poolMaxSize;
+ @Value("8")
+ private int poolMinSize;
+ @Value("60")
+ private int poolIdleTimeoutSeconds;
+ @Value("1000")
+ private int poolDaemonCheckIntervalMillis;
+ @Value("3600")
+ private int resetEngineTimeoutSeconds;
+ private IJavetLogger javetLogger;
+ private IJavetEnginePool javetEnginePool;
+
+ @PostConstruct
+ public void postConstruct() {
+ initializeJavet();
+ }
+
+ @PreDestroy
+ public void preDestroy() throws JavetException {
+ // There is no need to close Javet engine pool explicitly because spring does so.
+ }
+
+ @Bean
+ public IJavetEnginePool getJavetEnginePool() {
+ return javetEnginePool;
+ }
+
+ private void initializeJavet() {
+ javetLogger = new MyJavetLogger("SampleLogger");
+ JavetEngineConfig javetEngineConfig = new JavetEngineConfig();
+ javetEngineConfig.setPoolDaemonCheckIntervalMillis(getPoolDaemonCheckIntervalMillis());
+ javetEngineConfig.setPoolIdleTimeoutSeconds(getPoolIdleTimeoutSeconds());
+ javetEngineConfig.setPoolMinSize(getPoolMinSize());
+ javetEngineConfig.setPoolMaxSize(getPoolMaxSize());
+ javetEngineConfig.setResetEngineTimeoutSeconds(getResetEngineTimeoutSeconds());
+ javetEngineConfig.setJavetLogger(javetLogger);
+ javetEnginePool = new MyJavetEnginePool(javetEngineConfig);
+ }
+
+Injection
+=========
+
+You may easily inject your engine pool in the Spring way.
+
+.. code-block:: java
+
+ @Resource
+ protected IJavetEnginePool javetEnginePool;
+
+[`Home <../../README.rst>`_] [`Tutorial `_]
diff --git a/docs/tutorial/termination.rst b/docs/tutorial/termination.rst
new file mode 100644
index 000000000..13281cffd
--- /dev/null
+++ b/docs/tutorial/termination.rst
@@ -0,0 +1,71 @@
+===========
+Termination
+===========
+
+Terminating scripts that run out of control is quite important in terms of protecting the applications from being attacked by malicious scripts. In Javet, there are 2 typical ways of terminating scripts.
+
+Automatic Termination with Pool and Engine
+==========================================
+
+``IJavetEngineGuard`` is the built-in support for terminating a script which runs out of control.
+
+.. code-block:: java
+
+ // Get an engine from the pool as usual.
+ try (IJavetEngine iJavetEngine = iJavetEnginePool.getEngine()) {
+ V8Runtime v8Runtime = iJavetEngine.getV8Runtime();
+ // Get a guard from the engine and apply try-with-resource pattern.
+ try (IJavetEngineGuard iJavetEngineGuard = iJavetEngine.getGuard(10000)) {
+ v8Runtime.getExecutor("while (true) {}").executeVoid();
+ // That infinite loop will be terminated in 10 seconds by the guard.
+ } catch (JavetTerminatedException e) {
+ // JavetTerminatedException will be thrown to mark that.
+ assertFalse(e.isContinuable());
+ }
+ assertEquals(2, v8Runtime.getExecutor("1 + 1").executeInteger(),
+ "The V8 runtime is not dead and still be able to execute code afterwards.");
+ }
+
+Does ``IJavetEngineGuard`` hang normal scripts till timeout is hit? No, it doesn't cause any overhead. If the script completes, ``IJavetEngineGuard.close()`` will be called via try-with-resource pattern and cancel the daemon thread immediately.
+
+Please refer to `source code <../../src/test/java/com/caoccao/javet/interop/engine/TestJavetEngineGuard.java>`_ for more detail.
+
+Manual Termination
+==================
+
+Manual termination gives applications complete control. In return, the coding effort is considerable.
+
+.. code-block:: java
+
+ V8Host v8Host = V8Host.getInstance();
+ try (V8Runtime v8Runtime = v8Host.createV8Runtime()) {
+ // Create a daemon thread monitoring the V8 runtime status.
+ Thread daemonThread = new Thread(() -> {
+ // V8 runtime isInUse() does not require lock.
+ while (!v8Runtime.isInUse()) {
+ try {
+ TimeUnit.MILLISECONDS.sleep(1);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ // V8 runtime terminateExecution() does not require lock.
+ v8Runtime.terminateExecution();
+ });
+ daemonThread.start();
+ v8Runtime.lock();
+ try {
+ v8Runtime.getExecutor(
+ "var count = 0; while (true) { ++count; }")
+ .executeVoid();
+ fail("Failed to throw exception when execution is terminated.");
+ } catch (JavetTerminatedException e) {
+ assertFalse(e.isContinuable());
+ }
+ final int count = v8Runtime.getGlobalObject().getInteger("count");
+ assertTrue(count > 0, "Count should be greater than 0.");
+ assertEquals(2, v8Runtime.getExecutor("1 + 1").executeInteger(),
+ "V8 runtime should still be able to execute script after being terminated.");
+ }
+
+[`Home <../../README.rst>`_] [`Tutorial `_]
diff --git a/pom.xml b/pom.xml
index 028e5fa7d..ad8da3b90 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
com.caoccao.javetjavet
- 0.7.1
+ 0.7.2javetJavet is Java + V8 (JAVa + V + EighT). It is a way of embedding V8 in Java.https://github.com/caoccao/Javet
@@ -28,7 +28,7 @@
scm:git:git://github.com/caoccao/Javet.gitscm:git:git@github.com:caoccao/caoccao.githttps://github.com/caoccao/Javet
- javet-0.7.1
+ javet-0.7.2
diff --git a/scripts/python/change_javet_version.py b/scripts/python/change_javet_version.py
index 5eda91f5c..f82d40ac7 100644
--- a/scripts/python/change_javet_version.py
+++ b/scripts/python/change_javet_version.py
@@ -32,9 +32,9 @@ def __init__(self, version) -> None:
def update(self):
self._update(
'README.rst', '\n',
- re.compile(r'\*(?P\d+\.\d+\.\d+)\*'),
re.compile(r'^ (?P\d+\.\d+\.\d+)$'),
re.compile(r'javet:(?P\d+\.\d+\.\d+)"'),
+ re.compile(r'javet:(?P\d+\.\d+\.\d+)\''),
re.compile(r'version: \'(?P\d+\.\d+\.\d+)\''))
self._update(
'build.gradle.kts', '\n',
@@ -43,13 +43,14 @@ def update(self):
'docs/tutorial/hello_javet.rst', '\n',
re.compile(r'^ (?P\d+\.\d+\.\d+)$'),
re.compile(r'javet:(?P\d+\.\d+\.\d+)"'),
+ re.compile(r'javet:(?P\d+\.\d+\.\d+)\''),
re.compile(r'version: \'(?P\d+\.\d+\.\d+)\''))
self._update(
'pom.xml', '\n',
re.compile(r'^ (?P\d+\.\d+\.\d+)$'),
re.compile(r'^ javet-(?P\d+\.\d+\.\d+)$'))
self._update(
- 'cpp/build.cmd', '\n',
+ 'cpp/build.cmd', '\r\n',
re.compile(r'JAVET_VERSION=(?P\d+\.\d+\.\d+)$'))
self._update(
'cpp/build.sh', '\n',
@@ -58,7 +59,7 @@ def update(self):
'src/main/java/com/caoccao/javet/interop/JavetLibLoader.java', '\n',
re.compile(r'LIB_VERSION = "(?P\d+\.\d+\.\d+)";$'))
self._update(
- 'cpp/jni/javet.rc', '\n',
+ 'cpp/jni/javet.rc', '\r\n',
re.compile(r'"(?P\d+\.\d+\.\d+)'),
re.compile(r'v\.(?P\d+\.\d+\.\d+)'),
re.compile(r'(?P\d+,\d+,\d+)'))
@@ -67,7 +68,8 @@ def _update(self, relative_file_path: str, line_separator: str, *patterns: list)
file_path = (self._root_path / relative_file_path).resolve().absolute()
logging.info('Updating %s.', str(file_path))
lines, line_number = [], 1
- for line in file_path.read_text('utf-8').split(line_separator):
+ original_buffer = file_path.read_bytes()
+ for line in original_buffer.decode('utf-8').split(line_separator):
for pattern in patterns:
match_object = pattern.search(line)
if match_object is not None:
@@ -86,10 +88,15 @@ def _update(self, relative_file_path: str, line_separator: str, *patterns: list)
break
lines.append(line)
line_number += 1
- file_path.write_text(line_separator.join(lines), 'utf-8')
+ new_buffer = line_separator.join(lines).encode('utf-8')
+ if original_buffer == new_buffer:
+ logging.warn(' Skipped.')
+ else:
+ file_path.write_bytes(new_buffer)
+ logging.info(' Updated.')
def main():
- change_javet_version = ChangeJavetVersion('0.7.1')
+ change_javet_version = ChangeJavetVersion('0.7.2')
change_javet_version.update()
return 0
diff --git a/src/main/java/com/caoccao/javet/entities/JavetEntityMap.java b/src/main/java/com/caoccao/javet/entities/JavetEntityMap.java
new file mode 100644
index 000000000..30c6c47a6
--- /dev/null
+++ b/src/main/java/com/caoccao/javet/entities/JavetEntityMap.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2021. caoccao.com Sam Cao
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.caoccao.javet.entities;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class JavetEntityMap extends HashMap {
+ public JavetEntityMap(int initialCapacity, float loadFactor) {
+ super(initialCapacity, loadFactor);
+ }
+
+ public JavetEntityMap(int initialCapacity) {
+ super(initialCapacity);
+ }
+
+ public JavetEntityMap() {
+ }
+
+ public JavetEntityMap(Map extends String, ?> m) {
+ super(m);
+ }
+
+ @Override
+ public Object clone() {
+ return new JavetEntityMap(this);
+ }
+}
diff --git a/src/main/java/com/caoccao/javet/exceptions/JavetTerminatedException.java b/src/main/java/com/caoccao/javet/exceptions/JavetTerminatedException.java
new file mode 100644
index 000000000..d42fe569a
--- /dev/null
+++ b/src/main/java/com/caoccao/javet/exceptions/JavetTerminatedException.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2021. caoccao.com Sam Cao
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.caoccao.javet.exceptions;
+
+import java.text.MessageFormat;
+
+public class JavetTerminatedException extends JavetException {
+ protected boolean continuable;
+
+ public JavetTerminatedException(boolean continuable) {
+ super(MessageFormat.format("V8 execution is terminated, continuable: {0}", continuable));
+ this.continuable = continuable;
+ }
+
+ public boolean isContinuable() {
+ return continuable;
+ }
+}
diff --git a/src/main/java/com/caoccao/javet/exceptions/JavetV8RuntimeLockConflictException.java b/src/main/java/com/caoccao/javet/exceptions/JavetV8RuntimeLockConflictException.java
index ac5ba768b..0ea288f2c 100644
--- a/src/main/java/com/caoccao/javet/exceptions/JavetV8RuntimeLockConflictException.java
+++ b/src/main/java/com/caoccao/javet/exceptions/JavetV8RuntimeLockConflictException.java
@@ -20,16 +20,16 @@
import java.text.MessageFormat;
public class JavetV8RuntimeLockConflictException extends JavetException {
- public JavetV8RuntimeLockConflictException(String message) {
+ protected JavetV8RuntimeLockConflictException(String message) {
super(message);
}
- public JavetV8RuntimeLockConflictException() {
- this("V8 runtime lock conflict is detected");
+ public static JavetV8RuntimeLockConflictException lockNotRequired() {
+ return new JavetV8RuntimeLockConflictException("V8 runtime lock is not required");
}
- public JavetV8RuntimeLockConflictException(long lockedThreadId, long currentThreadId) {
- this(MessageFormat.format(
+ public static JavetV8RuntimeLockConflictException threadIdMismatch(long lockedThreadId, long currentThreadId) {
+ return new JavetV8RuntimeLockConflictException(MessageFormat.format(
"V8 runtime lock conflict is detected with locked thread ID {0} and current thread ID {1}",
Long.toString(lockedThreadId), Long.toString(currentThreadId)));
}
diff --git a/src/main/java/com/caoccao/javet/interop/IV8Creatable.java b/src/main/java/com/caoccao/javet/interop/IV8Creatable.java
index 1d99918e3..cab60d21c 100644
--- a/src/main/java/com/caoccao/javet/interop/IV8Creatable.java
+++ b/src/main/java/com/caoccao/javet/interop/IV8Creatable.java
@@ -19,16 +19,28 @@
import com.caoccao.javet.exceptions.JavetException;
import com.caoccao.javet.utils.JavetCallbackContext;
+import com.caoccao.javet.values.primitive.V8ValueNull;
+import com.caoccao.javet.values.primitive.V8ValueUndefined;
import com.caoccao.javet.values.reference.*;
public interface IV8Creatable {
V8ValueArray createV8ValueArray() throws JavetException;
+ V8ValueArrayBuffer createV8ValueArrayBuffer(int length) throws JavetException;
+
+ V8ValueDataView createV8ValueDataView(V8ValueArrayBuffer v8ValueArrayBuffer) throws JavetException;
+
V8ValueFunction createV8ValueFunction(JavetCallbackContext javetCallbackContext) throws JavetException;
V8ValueMap createV8ValueMap() throws JavetException;
+ V8ValueNull createV8ValueNull();
+
V8ValueObject createV8ValueObject() throws JavetException;
V8ValueSet createV8ValueSet() throws JavetException;
+
+ V8ValueTypedArray createV8ValueTypedArray(int type, int length) throws JavetException;
+
+ V8ValueUndefined createV8ValueUndefined();
}
diff --git a/src/main/java/com/caoccao/javet/interop/JavetLibLoader.java b/src/main/java/com/caoccao/javet/interop/JavetLibLoader.java
index 77d810009..e892b17d7 100644
--- a/src/main/java/com/caoccao/javet/interop/JavetLibLoader.java
+++ b/src/main/java/com/caoccao/javet/interop/JavetLibLoader.java
@@ -1,122 +1,123 @@
-/*
- * Copyright 2021. caoccao.com Sam Cao
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.caoccao.javet.interop;
-
-import com.caoccao.javet.exceptions.JavetIOException;
-import com.caoccao.javet.exceptions.JavetOSNotSupportedException;
-import com.caoccao.javet.utils.JavetOSUtils;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.InputStream;
-import java.text.MessageFormat;
-
-final class JavetLibLoader {
- private static final String CHMOD = "chmod";
- private static final String XRR = "755";
- static final String LIB_VERSION = "0.7.1";
- private static final String LIB_FILE_NAME_FORMAT = "libjavet-{0}-x86_64.v.{1}.{2}";
- private static final String RESOURCE_NAME_FORMAT = "/{0}";
- private static final String LIB_FILE_EXTENSION_LINUX = "so";
- private static final String LIB_FILE_EXTENSION_WINDOWS = "dll";
- private static final String OS_LINUX = "linux";
- private static final String OS_WINDOWS = "windows";
- private static int BUFFER_LENGTH = 4096;
-
- private static Object lockObject = new Object();
- private static boolean javetLibLoaded = false;
-
- private JavetLibLoader() {
- }
-
- static boolean load() throws JavetOSNotSupportedException, JavetIOException {
- if (!javetLibLoaded) {
- synchronized (lockObject) {
- if (!javetLibLoaded) {
- internalLoad();
- javetLibLoaded = true;
- }
- }
- }
- return javetLibLoaded;
- }
-
- private static boolean deployLibFile(File libFile) {
- boolean isDeployed = false;
- boolean isLibFileLocked = false;
- if (libFile.exists()) {
- try {
- libFile.delete();
- } catch (Exception e) {
- isLibFileLocked = true;
- }
- }
- if (!isLibFileLocked) {
- byte[] buffer = new byte[BUFFER_LENGTH];
- String resourceName = MessageFormat.format(RESOURCE_NAME_FORMAT, libFile.getName());
- try (InputStream inputStream = JavetLibLoader.class.getResourceAsStream(resourceName);
- FileOutputStream outputStream = new FileOutputStream(libFile.getAbsolutePath())) {
- while (true) {
- int length = inputStream.read(buffer);
- if (length == -1) {
- break;
- }
- outputStream.write(buffer, 0, length);
- }
- isDeployed = true;
- } catch (Exception e) {
- // Lib file is locked.
- }
- if (isDeployed && JavetOSUtils.IS_LINUX) {
- try {
- Runtime.getRuntime().exec(new String[]{CHMOD, XRR, libFile.getAbsolutePath()}).waitFor();
- } catch (Throwable e) {
- }
- }
- }
- return isDeployed;
- }
-
- private static File getLibFile(String rootDirectory) throws JavetOSNotSupportedException {
- if (JavetOSUtils.IS_WINDOWS) {
- return new File(
- rootDirectory,
- MessageFormat.format(
- LIB_FILE_NAME_FORMAT,
- OS_WINDOWS, LIB_VERSION, LIB_FILE_EXTENSION_WINDOWS));
- } else if (JavetOSUtils.IS_LINUX) {
- return new File(
- rootDirectory,
- MessageFormat.format(
- LIB_FILE_NAME_FORMAT,
- OS_LINUX, LIB_VERSION, LIB_FILE_EXTENSION_LINUX));
- } else {
- throw new JavetOSNotSupportedException(JavetOSUtils.OS_NAME);
- }
- }
-
- private static void internalLoad() throws JavetOSNotSupportedException, JavetIOException {
- File tempDirectoryLibFile = getLibFile(JavetOSUtils.TEMP_DIRECTORY);
- try {
- deployLibFile(tempDirectoryLibFile);
- System.load(tempDirectoryLibFile.getAbsolutePath());
- } catch (Throwable t) {
- throw JavetIOException.failedToReadPath(tempDirectoryLibFile.toPath(), t);
- }
- }
-}
+/*
+ * Copyright 2021. caoccao.com Sam Cao
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.caoccao.javet.interop;
+
+import com.caoccao.javet.exceptions.JavetIOException;
+import com.caoccao.javet.exceptions.JavetOSNotSupportedException;
+import com.caoccao.javet.utils.JavetOSUtils;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.text.MessageFormat;
+
+final class JavetLibLoader {
+ private static final String CHMOD = "chmod";
+ private static final String XRR = "755";
+ static final String LIB_VERSION = "0.7.2";
+ static final String V8_VERSION = "8.9.255";
+ private static final String LIB_FILE_NAME_FORMAT = "libjavet-{0}-x86_64.v.{1}.{2}";
+ private static final String RESOURCE_NAME_FORMAT = "/{0}";
+ private static final String LIB_FILE_EXTENSION_LINUX = "so";
+ private static final String LIB_FILE_EXTENSION_WINDOWS = "dll";
+ private static final String OS_LINUX = "linux";
+ private static final String OS_WINDOWS = "windows";
+ private static int BUFFER_LENGTH = 4096;
+
+ private static Object lockObject = new Object();
+ private static boolean javetLibLoaded = false;
+
+ private JavetLibLoader() {
+ }
+
+ static boolean load() throws JavetOSNotSupportedException, JavetIOException {
+ if (!javetLibLoaded) {
+ synchronized (lockObject) {
+ if (!javetLibLoaded) {
+ internalLoad();
+ javetLibLoaded = true;
+ }
+ }
+ }
+ return javetLibLoaded;
+ }
+
+ private static boolean deployLibFile(File libFile) {
+ boolean isDeployed = false;
+ boolean isLibFileLocked = false;
+ if (libFile.exists()) {
+ try {
+ libFile.delete();
+ } catch (Exception e) {
+ isLibFileLocked = true;
+ }
+ }
+ if (!isLibFileLocked) {
+ byte[] buffer = new byte[BUFFER_LENGTH];
+ String resourceName = MessageFormat.format(RESOURCE_NAME_FORMAT, libFile.getName());
+ try (InputStream inputStream = JavetLibLoader.class.getResourceAsStream(resourceName);
+ FileOutputStream outputStream = new FileOutputStream(libFile.getAbsolutePath())) {
+ while (true) {
+ int length = inputStream.read(buffer);
+ if (length == -1) {
+ break;
+ }
+ outputStream.write(buffer, 0, length);
+ }
+ isDeployed = true;
+ } catch (Exception e) {
+ // Lib file is locked.
+ }
+ if (isDeployed && JavetOSUtils.IS_LINUX) {
+ try {
+ Runtime.getRuntime().exec(new String[]{CHMOD, XRR, libFile.getAbsolutePath()}).waitFor();
+ } catch (Throwable e) {
+ }
+ }
+ }
+ return isDeployed;
+ }
+
+ private static File getLibFile(String rootDirectory) throws JavetOSNotSupportedException {
+ if (JavetOSUtils.IS_WINDOWS) {
+ return new File(
+ rootDirectory,
+ MessageFormat.format(
+ LIB_FILE_NAME_FORMAT,
+ OS_WINDOWS, LIB_VERSION, LIB_FILE_EXTENSION_WINDOWS));
+ } else if (JavetOSUtils.IS_LINUX) {
+ return new File(
+ rootDirectory,
+ MessageFormat.format(
+ LIB_FILE_NAME_FORMAT,
+ OS_LINUX, LIB_VERSION, LIB_FILE_EXTENSION_LINUX));
+ } else {
+ throw new JavetOSNotSupportedException(JavetOSUtils.OS_NAME);
+ }
+ }
+
+ private static void internalLoad() throws JavetOSNotSupportedException, JavetIOException {
+ File tempDirectoryLibFile = getLibFile(JavetOSUtils.TEMP_DIRECTORY);
+ try {
+ deployLibFile(tempDirectoryLibFile);
+ System.load(tempDirectoryLibFile.getAbsolutePath());
+ } catch (Throwable t) {
+ throw JavetIOException.failedToReadPath(tempDirectoryLibFile.toPath(), t);
+ }
+ }
+}
diff --git a/src/main/java/com/caoccao/javet/interop/V8Host.java b/src/main/java/com/caoccao/javet/interop/V8Host.java
index 6ea72f257..6a8ad7b93 100644
--- a/src/main/java/com/caoccao/javet/interop/V8Host.java
+++ b/src/main/java/com/caoccao/javet/interop/V8Host.java
@@ -29,6 +29,7 @@
import java.util.concurrent.ConcurrentHashMap;
public final class V8Host implements AutoCloseable {
+ public static final String GLOBAL_THIS = "globalThis";
private static final long INVALID_HANDLE = 0L;
private static final String FLAG_ALLOW_NATIVES_SYNTAX = "--allow-natives-syntax";
private static final String FLAG_EXPOSE_GC = "--expose_gc";
@@ -66,10 +67,6 @@ public static V8Host getInstance() {
return instance;
}
- public V8Runtime createV8Runtime() {
- return createV8Runtime(null);
- }
-
public V8Flags getFlags() {
return flags;
}
@@ -78,6 +75,10 @@ public String getJavetVersion() {
return JavetLibLoader.LIB_VERSION;
}
+ public V8Runtime createV8Runtime() {
+ return createV8Runtime(GLOBAL_THIS);
+ }
+
public V8Runtime createV8Runtime(String globalName) {
return createV8Runtime(false, globalName);
}
diff --git a/src/main/java/com/caoccao/javet/interop/V8Native.java b/src/main/java/com/caoccao/javet/interop/V8Native.java
index ccc179f19..fb55a14d2 100644
--- a/src/main/java/com/caoccao/javet/interop/V8Native.java
+++ b/src/main/java/com/caoccao/javet/interop/V8Native.java
@@ -37,6 +37,9 @@ native static Object call(
long v8RuntimeHandle, long v8ValueHandle, int v8ValueType,
Object receiver, boolean returnResult, Object[] values);
+ native static Object callAsConstructor(
+ long v8RuntimeHandle, long v8ValueHandle, int v8ValueType, Object[] values);
+
native static void clearWeak(long v8RuntimeHandle, long v8ValueHandle, int v8ValueType);
native static Object cloneV8Value(
@@ -55,6 +58,8 @@ native static void compileOnly(
native static boolean delete(long v8RuntimeHandle, long v8ValueHandle, int v8ValueType, Object key);
+ native static boolean equals(long v8RuntimeHandle, long v8ValueHandle1, long v8ValueHandle2);
+
native static Object execute(
long v8RuntimeHandle, String script, boolean returnResult,
String resourceName, int resourceLineOffset, int resourceColumnOffset,
@@ -64,6 +69,8 @@ native static Object execute(
native static Object getGlobalObject(long v8RuntimeHandle);
+ native static int getIdentityHash(long v8RuntimeHandle, long v8ValueHandle, int v8ValueType);
+
native static int getLength(long v8RuntimeHandle, long v8ValueHandle, int v8ValueType);
native static int getSize(long v8RuntimeHandle, long v8ValueHandle, int v8ValueType);
@@ -84,6 +91,10 @@ native static Object invoke(
long v8RuntimeHandle, long v8ValueHandle, int v8ValueType,
String functionName, boolean returnResult, Object[] values);
+ native static boolean isDead(long v8RuntimeHandle);
+
+ native static boolean isInUse(long v8RuntimeHandle);
+
native static boolean isWeak(long v8RuntimeHandle, long v8ValueHandle, int v8ValueType);
native static void lockV8Runtime(long v8RuntimeHandle);
@@ -114,6 +125,12 @@ native static Object invoke(
native static void setWeak(long v8RuntimeHandle, long v8ValueHandle, int v8ValueType, Object objectReference);
+ native static boolean sameValue(long v8RuntimeHandle, long v8ValueHandle1, long v8ValueHandle2);
+
+ native static boolean strictEquals(long v8RuntimeHandle, long v8ValueHandle1, long v8ValueHandle2);
+
+ native static void terminateExecution(long v8RuntimeHandle);
+
native static String toProtoString(long v8RuntimeHandle, long v8ValueHandle, int v8ValueType);
native static String toString(long v8RuntimeHandle, long v8ValueHandle, int v8ValueType);
diff --git a/src/main/java/com/caoccao/javet/interop/V8Runtime.java b/src/main/java/com/caoccao/javet/interop/V8Runtime.java
index fce3ad934..72427ff46 100644
--- a/src/main/java/com/caoccao/javet/interop/V8Runtime.java
+++ b/src/main/java/com/caoccao/javet/interop/V8Runtime.java
@@ -30,6 +30,9 @@
import com.caoccao.javet.utils.JavetDefaultLogger;
import com.caoccao.javet.values.V8Value;
import com.caoccao.javet.values.V8ValueReferenceType;
+import com.caoccao.javet.values.primitive.V8ValueInteger;
+import com.caoccao.javet.values.primitive.V8ValueNull;
+import com.caoccao.javet.values.primitive.V8ValueUndefined;
import com.caoccao.javet.values.reference.*;
import java.nio.file.Path;
@@ -42,6 +45,7 @@ public final class V8Runtime implements
IJavetClosable, IV8Executable, IV8Creatable {
private static final long INVALID_THREAD_ID = -1L;
private static final long INVALID_HANDLE = 0L;
+ private static final String PROPERTY_DATA_VIEW = "DataView";
private String globalName;
private long handle;
@@ -83,13 +87,21 @@ public T call(
handle, iV8ValueObject.getHandle(), iV8ValueObject.getType(), receiver, returnResult, v8Values));
}
+ public T callAsConstructor(
+ IV8ValueObject iV8ValueObject, V8Value... v8Values) throws JavetException {
+ checkLock();
+ decorateV8Values(v8Values);
+ return decorateV8Value((T) V8Native.callAsConstructor(
+ handle, iV8ValueObject.getHandle(), iV8ValueObject.getType(), v8Values));
+ }
+
public V8Runtime checkLock() throws JavetV8RuntimeLockConflictException, JavetV8RuntimeAlreadyClosedException {
if (handle == INVALID_HANDLE) {
throw new JavetV8RuntimeAlreadyClosedException();
}
final long currentThreadId = Thread.currentThread().getId();
if (threadId != currentThreadId) {
- throw new JavetV8RuntimeLockConflictException(threadId, currentThreadId);
+ throw JavetV8RuntimeLockConflictException.threadIdMismatch(threadId, currentThreadId);
}
return this;
}
@@ -140,14 +152,30 @@ public void compileOnly(String scriptString, V8ScriptOrigin v8ScriptOrigin) thro
@Override
public V8ValueArray createV8ValueArray() throws JavetException {
checkLock();
- return decorateV8Value((V8ValueArray) V8Native.createV8Value(handle, V8ValueReferenceType.Array, null));
+ return decorateV8Value((V8ValueArray) V8Native.createV8Value(
+ handle, V8ValueReferenceType.Array, null));
+ }
+
+ @Override
+ public V8ValueArrayBuffer createV8ValueArrayBuffer(int length) throws JavetException {
+ checkLock();
+ return decorateV8Value((V8ValueArrayBuffer) V8Native.createV8Value(
+ handle, V8ValueReferenceType.ArrayBuffer, new V8ValueInteger(length)));
+ }
+
+ @Override
+ public V8ValueDataView createV8ValueDataView(V8ValueArrayBuffer v8ValueArrayBuffer) throws JavetException {
+ checkLock();
+ try (V8ValueFunction v8ValueFunction = getGlobalObject().get(PROPERTY_DATA_VIEW)) {
+ return v8ValueFunction.callAsConstructor(v8ValueArrayBuffer);
+ }
}
@Override
public V8ValueFunction createV8ValueFunction(JavetCallbackContext javetCallbackContext) throws JavetException {
checkLock();
- V8ValueFunction v8ValueFunction = decorateV8Value(
- (V8ValueFunction) V8Native.createV8Value(handle, V8ValueReferenceType.Function, javetCallbackContext));
+ V8ValueFunction v8ValueFunction = decorateV8Value((V8ValueFunction) V8Native.createV8Value(
+ handle, V8ValueReferenceType.Function, javetCallbackContext));
v8ValueFunction.setV8CallbackContext(javetCallbackContext);
return v8ValueFunction;
}
@@ -158,6 +186,16 @@ public V8ValueMap createV8ValueMap() throws JavetException {
return decorateV8Value((V8ValueMap) V8Native.createV8Value(handle, V8ValueReferenceType.Map, null));
}
+ @Override
+ public V8ValueNull createV8ValueNull() {
+ V8ValueNull v8ValueNull = new V8ValueNull();
+ try {
+ v8ValueNull.setV8Runtime(this);
+ } catch (JavetException javetException) {
+ }
+ return v8ValueNull;
+ }
+
@Override
public V8ValueObject createV8ValueObject() throws JavetException {
checkLock();
@@ -170,6 +208,23 @@ public V8ValueSet createV8ValueSet() throws JavetException {
return decorateV8Value((V8ValueSet) V8Native.createV8Value(handle, V8ValueReferenceType.Set, null));
}
+ @Override
+ public V8ValueTypedArray createV8ValueTypedArray(int type, int length) throws JavetException {
+ try (V8ValueFunction v8ValueFunction = getGlobalObject().get(V8ValueTypedArray.getName(type))) {
+ return v8ValueFunction.callAsConstructor(new V8ValueInteger(length));
+ }
+ }
+
+ @Override
+ public V8ValueUndefined createV8ValueUndefined() {
+ V8ValueUndefined v8ValueUndefined = new V8ValueUndefined();
+ try {
+ v8ValueUndefined.setV8Runtime(this);
+ } catch (JavetException javetException) {
+ }
+ return v8ValueUndefined;
+ }
+
public T decorateV8Value(T v8Value) throws JavetException {
if (v8Value != null) {
if (v8Value.getV8Runtime() == null) {
@@ -197,6 +252,13 @@ public boolean delete(IV8ValueObject iV8ValueObject, V8Value key) throws JavetEx
return V8Native.delete(handle, iV8ValueObject.getHandle(), iV8ValueObject.getType(), key);
}
+ public boolean equals(V8ValueReference v8ValueReference1, V8ValueReference v8ValueReference2)
+ throws JavetException {
+ checkLock();
+ decorateV8Values(v8ValueReference1, v8ValueReference2);
+ return V8Native.equals(handle, v8ValueReference1.getHandle(), v8ValueReference2.getHandle());
+ }
+
@Override
public T execute(
String scriptString, V8ScriptOrigin v8ScriptOrigin, boolean resultRequired) throws JavetException {
@@ -232,6 +294,11 @@ public void setGlobalName(String globalName) {
this.globalName = globalName;
}
+ public int getIdentityHash(IV8ValueObject iV8ValueObject) throws JavetException {
+ checkLock();
+ return V8Native.getIdentityHash(handle, iV8ValueObject.getHandle(), iV8ValueObject.getType());
+ }
+
public IJavetLogger getLogger() {
return logger;
}
@@ -253,6 +320,11 @@ public int getLength(IV8ValueArray iV8ValueArray) throws JavetException {
return V8Native.getLength(handle, iV8ValueArray.getHandle(), iV8ValueArray.getType());
}
+ public int getLength(IV8ValueTypedArray iV8ValueTypedArray) throws JavetException {
+ checkLock();
+ return V8Native.getLength(handle, iV8ValueTypedArray.getHandle(), iV8ValueTypedArray.getType());
+ }
+
public IV8ValueArray getOwnPropertyNames(
IV8ValueObject iV8ValueObject) throws JavetException {
checkLock();
@@ -286,16 +358,16 @@ public int getSize(IV8ValueKeyContainer iV8ValueKeyContainer) throws JavetExcept
return V8Native.getSize(handle, iV8ValueKeyContainer.getHandle(), iV8ValueKeyContainer.getType());
}
- public boolean hasOwnProperty(IV8ValueObject iV8ValueObject, V8Value key) throws JavetException {
+ public boolean has(IV8ValueObject iV8ValueObject, V8Value value) throws JavetException {
checkLock();
- decorateV8Value(key);
- return V8Native.hasOwnProperty(handle, iV8ValueObject.getHandle(), iV8ValueObject.getType(), key);
+ decorateV8Value(value);
+ return V8Native.has(handle, iV8ValueObject.getHandle(), iV8ValueObject.getType(), value);
}
- public boolean has(IV8ValueKeyContainer iV8ValueKeyContainer, V8Value value) throws JavetException {
+ public boolean hasOwnProperty(IV8ValueObject iV8ValueObject, V8Value key) throws JavetException {
checkLock();
- decorateV8Value(value);
- return V8Native.has(handle, iV8ValueKeyContainer.getHandle(), iV8ValueKeyContainer.getType(), value);
+ decorateV8Value(key);
+ return V8Native.hasOwnProperty(handle, iV8ValueObject.getHandle(), iV8ValueObject.getType(), key);
}
public T invoke(
@@ -307,6 +379,14 @@ public T invoke(
handle, iV8ValueObject.getHandle(), iV8ValueObject.getType(), functionName, returnResult, v8Values));
}
+ public boolean isDead() {
+ return V8Native.isDead(handle);
+ }
+
+ public boolean isInUse() {
+ return V8Native.isInUse(handle);
+ }
+
public boolean isLocked() {
return threadId != INVALID_THREAD_ID;
}
@@ -387,36 +467,32 @@ public void requestGarbageCollectionForTesting(boolean fullGC)
* Reset V8 context.
* This is a light-weight and recommended reset.
*
+ * @return the self
* @throws JavetException the javet exception
*/
- public void resetContext() throws JavetException {
- removeReferences();
- boolean locked = isLocked();
- if (locked) {
- unlock();
+ public V8Runtime resetContext() throws JavetException {
+ if (isLocked()) {
+ throw JavetV8RuntimeLockConflictException.lockNotRequired();
}
+ removeReferences();
V8Native.resetV8Context(handle, globalName);
- if (locked) {
- lock();
- }
+ return this;
}
/**
* Reset V8 isolate.
* This is a heavy reset. Please avoid using it in performance sensitive scenario.
*
+ * @return the self
* @throws JavetException the javet exception
*/
- public void resetIsolate() throws JavetException {
- removeReferences();
- boolean locked = isLocked();
- if (locked) {
- unlock();
+ public V8Runtime resetIsolate() throws JavetException {
+ if (isLocked()) {
+ throw JavetV8RuntimeLockConflictException.lockNotRequired();
}
+ removeReferences();
V8Native.resetV8Isolate(handle, globalName);
- if (locked) {
- lock();
- }
+ return this;
}
public boolean set(IV8ValueObject iV8ValueObject, V8Value key, V8Value value) throws JavetException {
@@ -436,6 +512,33 @@ public void setWeak(IV8ValueReference iV8ValueReference) throws JavetException {
V8Native.setWeak(handle, iV8ValueReference.getHandle(), iV8ValueReference.getType(), iV8ValueReference);
}
+ public boolean sameValue(V8ValueReference v8ValueReference1, V8ValueReference v8ValueReference2)
+ throws JavetException {
+ checkLock();
+ decorateV8Values(v8ValueReference1, v8ValueReference2);
+ return V8Native.sameValue(handle, v8ValueReference1.getHandle(), v8ValueReference2.getHandle());
+ }
+
+ public boolean strictEquals(V8ValueReference v8ValueReference1, V8ValueReference v8ValueReference2)
+ throws JavetException {
+ checkLock();
+ decorateV8Values(v8ValueReference1, v8ValueReference2);
+ return V8Native.strictEquals(handle, v8ValueReference1.getHandle(), v8ValueReference2.getHandle());
+ }
+
+ /**
+ * Terminate execution.
+ *
+ * Forcefully terminate the current thread of JavaScript execution
+ * in the given isolate.
+ *
+ * This method can be used by any thread even if that thread has not
+ * acquired the V8 lock with a Locker object.
+ */
+ public void terminateExecution() {
+ V8Native.terminateExecution(handle);
+ }
+
public String toProtoString(IV8ValueReference iV8ValueReference)
throws JavetV8RuntimeLockConflictException, JavetV8RuntimeAlreadyClosedException {
checkLock();
diff --git a/src/main/java/com/caoccao/javet/interop/engine/IJavetEngine.java b/src/main/java/com/caoccao/javet/interop/engine/IJavetEngine.java
index 4acceab5f..8635a392b 100644
--- a/src/main/java/com/caoccao/javet/interop/engine/IJavetEngine.java
+++ b/src/main/java/com/caoccao/javet/interop/engine/IJavetEngine.java
@@ -22,9 +22,17 @@
import com.caoccao.javet.interop.V8Runtime;
public interface IJavetEngine extends IJavetClosable {
+ JavetEngineConfig getConfig();
+
V8Runtime getV8Runtime() throws JavetException;
+ IJavetEngineGuard getGuard();
+
+ IJavetEngineGuard getGuard(long timeoutMillis);
+
boolean isActive();
void resetContext() throws JavetException;
+
+ void resetContext(boolean skipLock) throws JavetException;
}
diff --git a/src/main/java/com/caoccao/javet/interop/engine/IJavetEngineGuard.java b/src/main/java/com/caoccao/javet/interop/engine/IJavetEngineGuard.java
new file mode 100644
index 000000000..fdb75fe91
--- /dev/null
+++ b/src/main/java/com/caoccao/javet/interop/engine/IJavetEngineGuard.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2021. caoccao.com Sam Cao
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.caoccao.javet.interop.engine;
+
+import com.caoccao.javet.interfaces.IJavetClosable;
+
+/**
+ * The interface Javet engine guard is the one guarding the script execution with a timeout.
+ *
+ * Usage:
+ *
+ *
+ * try (IJavetEngineGuard iJavetEngineGuard = iJavetEngine.getGuard(5000)) {
+ * v8Runtime.getExecutor("while (true) {}").executeVoid();
+ * // That infinite loop will be terminated in 5 seconds by the guard.
+ * }
+ *
+ */
+public interface IJavetEngineGuard extends IJavetClosable, Runnable {
+ /**
+ * Cancel.
+ */
+ void cancel();
+
+ /**
+ * Gets timeout millis.
+ *
+ * @return the timeout millis
+ */
+ long getTimeoutMillis();
+
+ /**
+ * Sets timeout millis.
+ *
+ * @param timeoutMillis the timeout millis
+ */
+ void setTimeoutMillis(long timeoutMillis);
+}
diff --git a/src/main/java/com/caoccao/javet/interop/engine/IJavetEnginePool.java b/src/main/java/com/caoccao/javet/interop/engine/IJavetEnginePool.java
index 34cba8859..284b4035e 100644
--- a/src/main/java/com/caoccao/javet/interop/engine/IJavetEnginePool.java
+++ b/src/main/java/com/caoccao/javet/interop/engine/IJavetEnginePool.java
@@ -28,5 +28,9 @@ public interface IJavetEnginePool extends IJavetClosable {
int getIdleEngineCount();
+ boolean isActive();
+
+ boolean isQuitting();
+
void releaseEngine(IJavetEngine engine);
}
diff --git a/src/main/java/com/caoccao/javet/interop/engine/JavetEngine.java b/src/main/java/com/caoccao/javet/interop/engine/JavetEngine.java
index 7591022eb..def94aca0 100644
--- a/src/main/java/com/caoccao/javet/interop/engine/JavetEngine.java
+++ b/src/main/java/com/caoccao/javet/interop/engine/JavetEngine.java
@@ -55,6 +55,21 @@ protected void close(boolean forceClose) throws JavetException {
}
}
+ @Override
+ public JavetEngineConfig getConfig() {
+ return iJavetEnginePool.getConfig();
+ }
+
+ @Override
+ public IJavetEngineGuard getGuard() {
+ return getGuard(iJavetEnginePool.getConfig().getDefaultEngineGuardTimeoutMillis());
+ }
+
+ @Override
+ public IJavetEngineGuard getGuard(long timeoutMillis) {
+ return new JavetEngineGuard(this, v8Runtime, timeoutMillis);
+ }
+
protected JavetEngineUsage getUsage() {
return usage;
}
@@ -79,13 +94,34 @@ protected ZonedDateTime getUTCNow() {
@Override
public void resetContext() throws JavetException {
+ resetContext(false);
+ }
+
+ @Override
+ public void resetContext(boolean skipLock) throws JavetException {
+ if (!skipLock) {
+ v8Runtime.unlock();
+ }
v8Runtime.resetContext();
usage.reset();
+ if (!skipLock) {
+ v8Runtime.lock();
+ }
}
protected void resetIsolate() throws JavetException {
+ resetIsolate(false);
+ }
+
+ protected void resetIsolate(boolean skipLock) throws JavetException {
+ if (!skipLock) {
+ v8Runtime.unlock();
+ }
v8Runtime.resetIsolate();
usage.reset();
+ if (!skipLock) {
+ v8Runtime.lock();
+ }
}
protected void touchLastActiveZonedDateTime() {
diff --git a/src/main/java/com/caoccao/javet/interop/engine/JavetEngineConfig.java b/src/main/java/com/caoccao/javet/interop/engine/JavetEngineConfig.java
index 8f4f2d63e..c376a4353 100644
--- a/src/main/java/com/caoccao/javet/interop/engine/JavetEngineConfig.java
+++ b/src/main/java/com/caoccao/javet/interop/engine/JavetEngineConfig.java
@@ -22,23 +22,31 @@
import com.caoccao.javet.utils.JavetOSUtils;
import java.util.Objects;
+import java.util.concurrent.ExecutorService;
public final class JavetEngineConfig {
+ public static final int DEFAULT_ENGINE_GUARD_TIMEOUT_MILLIS = 30000;
+ public static final int DEFAULT_ENGINE_GUARD_CHECK_INTERVAL_MILLIS = 1000;
public static final int DEFAULT_MAX_ENGINE_USED_COUNT = 100;
public static final int DEFAULT_POOL_MIN_SIZE = 1;
public static final int DEFAULT_POOL_IDLE_TIMEOUT_SECONDS = 60;
public static final int DEFAULT_POOL_DAEMON_CHECK_INTERVAL_MILLIS = 1000;
public static final int DEFAULT_RESET_ENGINE_TIMEOUT_SECONDS = 3600;
public static final String DEFAULT_GLOBAL_NAME = "window";
+ public static final int DEFAULT_POOL_SHUTDOWN_TIMEOUT_SECONDS = 5;
public static IJavetLogger DEFAULT_JAVET_LOGGER = new JavetDefaultLogger(JavetEnginePool.class.getName());
private IJavetLogger javetLogger;
private String globalName;
+ private int defaultEngineGuardTimeoutMillis;
+ private int engineGuardCheckIntervalMillis;
private int maxEngineUsedCount;
+ private int poolDaemonCheckIntervalMillis;
private int poolMaxSize;
private int poolMinSize;
private int poolIdleTimeoutSeconds;
- private int poolDaemonCheckIntervalMillis;
+ private int poolShutdownTimeoutSeconds;
private int resetEngineTimeoutSeconds;
+ private ExecutorService executorService;
public JavetEngineConfig() {
reset();
@@ -47,15 +55,42 @@ public JavetEngineConfig() {
public void reset() {
javetLogger = DEFAULT_JAVET_LOGGER;
globalName = DEFAULT_GLOBAL_NAME;
+ defaultEngineGuardTimeoutMillis = DEFAULT_ENGINE_GUARD_TIMEOUT_MILLIS;
+ engineGuardCheckIntervalMillis = DEFAULT_ENGINE_GUARD_CHECK_INTERVAL_MILLIS;
maxEngineUsedCount = DEFAULT_MAX_ENGINE_USED_COUNT;
final int cpuCount = JavetOSUtils.getCPUCount();
poolMinSize = Math.max(DEFAULT_POOL_MIN_SIZE, cpuCount >> 1);
poolMaxSize = Math.max(DEFAULT_POOL_MIN_SIZE, cpuCount);
poolIdleTimeoutSeconds = DEFAULT_POOL_IDLE_TIMEOUT_SECONDS;
+ poolShutdownTimeoutSeconds = DEFAULT_POOL_SHUTDOWN_TIMEOUT_SECONDS;
poolDaemonCheckIntervalMillis = DEFAULT_POOL_DAEMON_CHECK_INTERVAL_MILLIS;
resetEngineTimeoutSeconds = DEFAULT_RESET_ENGINE_TIMEOUT_SECONDS;
}
+ public ExecutorService getExecutorService() {
+ return executorService;
+ }
+
+ void setExecutorService(ExecutorService executorService) {
+ this.executorService = executorService;
+ }
+
+ public int getPoolShutdownTimeoutSeconds() {
+ return poolShutdownTimeoutSeconds;
+ }
+
+ public void setPoolShutdownTimeoutSeconds(int poolShutdownTimeoutSeconds) {
+ this.poolShutdownTimeoutSeconds = poolShutdownTimeoutSeconds;
+ }
+
+ public int getEngineGuardCheckIntervalMillis() {
+ return engineGuardCheckIntervalMillis;
+ }
+
+ public void setEngineGuardCheckIntervalMillis(int engineGuardCheckIntervalMillis) {
+ this.engineGuardCheckIntervalMillis = engineGuardCheckIntervalMillis;
+ }
+
public String getGlobalName() {
return globalName;
}
@@ -64,6 +99,14 @@ public void setGlobalName(String globalName) {
this.globalName = globalName;
}
+ public int getDefaultEngineGuardTimeoutMillis() {
+ return defaultEngineGuardTimeoutMillis;
+ }
+
+ public void setDefaultEngineGuardTimeoutMillis(int defaultEngineGuardTimeoutMillis) {
+ this.defaultEngineGuardTimeoutMillis = defaultEngineGuardTimeoutMillis;
+ }
+
public int getResetEngineTimeoutSeconds() {
return resetEngineTimeoutSeconds;
}
diff --git a/src/main/java/com/caoccao/javet/interop/engine/JavetEngineGuard.java b/src/main/java/com/caoccao/javet/interop/engine/JavetEngineGuard.java
new file mode 100644
index 000000000..bef1d31c7
--- /dev/null
+++ b/src/main/java/com/caoccao/javet/interop/engine/JavetEngineGuard.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2021. caoccao.com Sam Cao
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.caoccao.javet.interop.engine;
+
+import com.caoccao.javet.exceptions.JavetException;
+import com.caoccao.javet.interfaces.IJavetLogger;
+import com.caoccao.javet.interop.V8Runtime;
+import com.caoccao.javet.utils.JavetDateTimeUtils;
+
+import java.time.Duration;
+import java.time.ZonedDateTime;
+import java.util.Objects;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+public class JavetEngineGuard implements IJavetEngineGuard {
+ protected long timeoutMillis;
+ protected IJavetEngine iJavetEngine;
+ protected boolean quitting;
+ protected V8Runtime v8Runtime;
+ protected Future future;
+
+ public JavetEngineGuard(IJavetEngine iJavetEngine, V8Runtime v8Runtime, long timeoutMills) {
+ Objects.requireNonNull(iJavetEngine);
+ this.iJavetEngine = iJavetEngine;
+ this.timeoutMillis = timeoutMills;
+ quitting = false;
+ this.v8Runtime = v8Runtime;
+ future = this.iJavetEngine.getConfig().getExecutorService().submit(this);
+ }
+
+ @Override
+ public void cancel() {
+ quitting = true;
+ }
+
+ @Override
+ public void close() throws JavetException {
+ cancel();
+ if (!future.isDone() && !future.isCancelled()) {
+ future.cancel(true);
+ }
+ }
+
+ @Override
+ public long getTimeoutMillis() {
+ return timeoutMillis;
+ }
+
+ @Override
+ public void setTimeoutMillis(long timeoutSeconds) {
+ this.timeoutMillis = timeoutSeconds;
+ }
+
+ public boolean isQuitting() {
+ return quitting;
+ }
+
+ protected ZonedDateTime getUTCNow() {
+ return JavetDateTimeUtils.getUTCNow();
+ }
+
+ @Override
+ public void run() {
+ JavetEngineConfig config = iJavetEngine.getConfig();
+ IJavetLogger logger = config.getJavetLogger();
+ ZonedDateTime startZonedDateTime = getUTCNow();
+ while (!isQuitting() && iJavetEngine.isActive()) {
+ ZonedDateTime currentZonedDateTime = getUTCNow();
+ if (startZonedDateTime.plusNanos(TimeUnit.MILLISECONDS.toNanos(timeoutMillis))
+ .isBefore(currentZonedDateTime)) {
+ try {
+ if (v8Runtime.isInUse()) {
+ // Javet only terminates the execution when V8 runtime is in use.
+ v8Runtime.terminateExecution();
+ Duration duration = Duration.between(startZonedDateTime, currentZonedDateTime);
+ logger.logWarn("Execution was terminated after {0}ms.", duration.toMillis());
+ }
+ } catch (Exception e) {
+ logger.error(e.getMessage(), e);
+ } finally {
+ break;
+ }
+ } else {
+ try {
+ Thread.sleep(config.getEngineGuardCheckIntervalMillis());
+ } catch (InterruptedException e) {
+ // It's closed.
+ }
+ }
+ }
+ quitting = true;
+ }
+}
diff --git a/src/main/java/com/caoccao/javet/interop/engine/JavetEnginePool.java b/src/main/java/com/caoccao/javet/interop/engine/JavetEnginePool.java
index 85232cc2d..c3d8a868f 100644
--- a/src/main/java/com/caoccao/javet/interop/engine/JavetEnginePool.java
+++ b/src/main/java/com/caoccao/javet/interop/engine/JavetEnginePool.java
@@ -18,6 +18,7 @@
package com.caoccao.javet.interop.engine;
import com.caoccao.javet.exceptions.JavetException;
+import com.caoccao.javet.interfaces.IJavetLogger;
import com.caoccao.javet.interop.V8Host;
import com.caoccao.javet.interop.V8Runtime;
import com.caoccao.javet.utils.JavetDateTimeUtils;
@@ -26,6 +27,7 @@
import java.time.temporal.ChronoUnit;
import java.util.LinkedList;
import java.util.Objects;
+import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class JavetEnginePool implements IJavetEnginePool, Runnable {
@@ -79,7 +81,8 @@ public JavetEngineConfig getConfig() {
@Override
public IJavetEngine getEngine() {
- config.getJavetLogger().debug("JavetEnginePool.getEngine() begins.");
+ IJavetLogger logger = config.getJavetLogger();
+ logger.debug("JavetEnginePool.getEngine() begins.");
JavetEngine engine = null;
while (!quitting) {
synchronized (internalLock) {
@@ -99,12 +102,12 @@ public IJavetEngine getEngine() {
try {
TimeUnit.MILLISECONDS.sleep(config.getPoolDaemonCheckIntervalMillis());
} catch (InterruptedException e) {
- config.getJavetLogger().logError(e, "Failed to sleep a while to wait for an idle engine.");
+ logger.logError(e, "Failed to sleep a while to wait for an idle engine.");
}
}
JavetEngineUsage usage = engine.getUsage();
usage.increaseUsedCount();
- config.getJavetLogger().debug("JavetEnginePool.getEngine() ends.");
+ logger.debug("JavetEnginePool.getEngine() ends.");
return engine;
}
@@ -119,22 +122,30 @@ protected ZonedDateTime getUTCNow() {
return JavetDateTimeUtils.getUTCNow();
}
+ @Override
public boolean isActive() {
return active;
}
+ @Override
+ public boolean isQuitting() {
+ return quitting;
+ }
+
@Override
public void releaseEngine(IJavetEngine engine) {
- config.getJavetLogger().debug("JavetEnginePool.releaseEngine() begins.");
+ IJavetLogger logger = config.getJavetLogger();
+ logger.debug("JavetEnginePool.releaseEngine() begins.");
synchronized (externalLock) {
externalLock.notify();
}
- config.getJavetLogger().debug("JavetEnginePool.releaseEngine() ends.");
+ logger.debug("JavetEnginePool.releaseEngine() ends.");
}
@Override
public void run() {
- config.getJavetLogger().debug("JavetEnginePool.run() begins.");
+ IJavetLogger logger = config.getJavetLogger();
+ logger.debug("JavetEnginePool.run() begins.");
while (!quitting) {
synchronized (internalLock) {
if (!activeEngineList.isEmpty()) {
@@ -144,17 +155,19 @@ public void run() {
if (engine.isActive()) {
activeEngineList.push(engine);
} else {
- JavetEngineUsage usage = engine.getUsage();
- ZonedDateTime resetEngineZonedDateTime = usage.getLastActiveZonedDatetime()
- .plus(config.getResetEngineTimeoutSeconds(), ChronoUnit.SECONDS);
- if (usage.getEngineUsedCount() >= config.getMaxEngineUsedCount() ||
- resetEngineZonedDateTime.isBefore(getUTCNow())) {
- try {
- config.getJavetLogger().debug("JavetEnginePool reset engine begins.");
- engine.resetIsolate();
- config.getJavetLogger().debug("JavetEnginePool reset engine ends.");
- } catch (Exception e) {
- config.getJavetLogger().logError(e, "Failed to reset idle engine.");
+ if (config.getMaxEngineUsedCount() > 0) {
+ JavetEngineUsage usage = engine.getUsage();
+ ZonedDateTime resetEngineZonedDateTime = usage.getLastActiveZonedDatetime()
+ .plus(config.getResetEngineTimeoutSeconds(), ChronoUnit.SECONDS);
+ if (usage.getEngineUsedCount() >= config.getMaxEngineUsedCount() ||
+ resetEngineZonedDateTime.isBefore(getUTCNow())) {
+ try {
+ logger.debug("JavetEnginePool reset engine begins.");
+ engine.resetContext(true);
+ logger.debug("JavetEnginePool reset engine ends.");
+ } catch (Exception e) {
+ logger.logError(e, "Failed to reset idle engine.");
+ }
}
}
idleEngineList.push(engine);
@@ -175,7 +188,7 @@ public void run() {
try {
engine.close(true);
} catch (Throwable t) {
- config.getJavetLogger().logError(t, "Failed to release idle engine.");
+ logger.logError(t, "Failed to release idle engine.");
}
} else {
idleEngineList.push(engine);
@@ -187,12 +200,12 @@ public void run() {
try {
externalLock.wait(config.getPoolDaemonCheckIntervalMillis());
} catch (InterruptedException e) {
- config.getJavetLogger().logError(e,
+ logger.logError(e,
"Failed to sleep a while to wait for next round in Javet engine pool daemon.");
}
}
}
- config.getJavetLogger().debug("JavetEnginePool daemon is quitting.");
+ logger.debug("JavetEnginePool daemon is quitting.");
synchronized (internalLock) {
if (!idleEngineList.isEmpty()) {
final int idleEngineCount = getIdleEngineCount();
@@ -201,7 +214,7 @@ public void run() {
try {
engine.close(true);
} catch (Throwable t) {
- config.getJavetLogger().logError(t, "Failed to release idle engine.");
+ logger.logError(t, "Failed to release idle engine.");
}
}
}
@@ -212,39 +225,50 @@ public void run() {
try {
engine.close(true);
} catch (Throwable t) {
- config.getJavetLogger().logError(t, "Failed to release active engine.");
+ logger.logError(t, "Failed to release active engine.");
}
}
}
}
- config.getJavetLogger().debug("JavetEnginePool.run() ends.");
+ logger.debug("JavetEnginePool.run() ends.");
}
protected void startDaemon() {
- config.getJavetLogger().debug("JavetEnginePool.startDaemon() begins.");
+ IJavetLogger logger = config.getJavetLogger();
+ logger.debug("JavetEnginePool.startDaemon() begins.");
activeEngineList.clear();
idleEngineList.clear();
quitting = false;
+ config.setExecutorService(Executors.newCachedThreadPool());
daemonThread = new Thread(this);
daemonThread.start();
active = true;
- config.getJavetLogger().debug("JavetEnginePool.startDaemon() ends.");
+ logger.debug("JavetEnginePool.startDaemon() ends.");
}
protected void stopDaemon() {
- config.getJavetLogger().debug("JavetEnginePool.stopDaemon() begins.");
+ IJavetLogger logger = config.getJavetLogger();
+ logger.debug("JavetEnginePool.stopDaemon() begins.");
quitting = true;
+ try {
+ config.getExecutorService().shutdown();
+ config.getExecutorService().awaitTermination(config.getPoolShutdownTimeoutSeconds(), TimeUnit.SECONDS);
+ } catch (Exception e) {
+ logger.logError(e, e.getMessage());
+ } finally {
+ config.setExecutorService(null);
+ }
try {
if (daemonThread != null) {
daemonThread.join();
}
} catch (Exception e) {
- config.getJavetLogger().logError(e, e.getMessage());
+ logger.logError(e, e.getMessage());
} finally {
daemonThread = null;
}
active = false;
quitting = false;
- config.getJavetLogger().debug("JavetEnginePool.stopDaemon() ends.");
+ logger.debug("JavetEnginePool.stopDaemon() ends.");
}
}
diff --git a/src/main/java/com/caoccao/javet/utils/JavetDefaultLogger.java b/src/main/java/com/caoccao/javet/utils/JavetDefaultLogger.java
index 3b44b84c3..eba4a949b 100644
--- a/src/main/java/com/caoccao/javet/utils/JavetDefaultLogger.java
+++ b/src/main/java/com/caoccao/javet/utils/JavetDefaultLogger.java
@@ -2,6 +2,10 @@
import com.caoccao.javet.interfaces.IJavetLogger;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.nio.charset.StandardCharsets;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -35,7 +39,13 @@ public void error(String message) {
@Override
public void error(String message, Throwable cause) {
logger.severe(message);
- logger.severe(cause.getMessage());
+ try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
+ try (PrintStream printStream = new PrintStream(byteArrayOutputStream)) {
+ cause.printStackTrace(printStream);
+ logger.severe(byteArrayOutputStream.toString(StandardCharsets.UTF_8.name()));
+ }
+ } catch (IOException e) {
+ }
}
@Override
diff --git a/src/main/java/com/caoccao/javet/utils/V8ValueUtils.java b/src/main/java/com/caoccao/javet/utils/V8ValueUtils.java
index 54a83ac3c..5ad496fbe 100644
--- a/src/main/java/com/caoccao/javet/utils/V8ValueUtils.java
+++ b/src/main/java/com/caoccao/javet/utils/V8ValueUtils.java
@@ -17,19 +17,12 @@
package com.caoccao.javet.utils;
-import com.caoccao.javet.exceptions.JavetException;
import com.caoccao.javet.values.V8Value;
-import com.caoccao.javet.values.reference.V8ValueObject;
-import com.caoccao.javet.values.virtual.V8VirtualList;
import java.util.Arrays;
import java.util.stream.Collectors;
-@SuppressWarnings("unchecked")
public final class V8ValueUtils {
- public static final String FUNCTION_NEXT = "next";
- public static final String PROPERTY_DONE = "done";
- public static final String PROPERTY_VALUE = "value";
public static final String EMPTY = "";
private V8ValueUtils() {
@@ -44,32 +37,6 @@ public static String concat(String delimiter, V8Value... v8Values) {
}
return String.join(
delimiter,
- Arrays.stream(v8Values).map(v8Value -> v8Value.toString()).collect(Collectors.toList()));
- }
-
- public static V8VirtualList convertIteratorToIntegerList(V8ValueObject iterator) throws JavetException {
- V8VirtualList resultList = new V8VirtualList<>();
- while (true) {
- try (V8ValueObject next = iterator.invoke(FUNCTION_NEXT)) {
- if (next.getBoolean(PROPERTY_DONE)) {
- break;
- }
- resultList.add(next.getInteger(PROPERTY_VALUE));
- }
- }
- return resultList;
- }
-
- public static V8VirtualList convertIteratorToV8ValueList(V8ValueObject iterator) throws JavetException {
- V8VirtualList resultList = new V8VirtualList<>();
- while (true) {
- try (V8ValueObject next = iterator.invoke(FUNCTION_NEXT)) {
- if (next.getBoolean(PROPERTY_DONE)) {
- break;
- }
- resultList.add(next.get(PROPERTY_VALUE));
- }
- }
- return resultList;
+ Arrays.stream(v8Values).map(V8Value::toString).collect(Collectors.toList()));
}
}
diff --git a/src/main/java/com/caoccao/javet/utils/converters/IJavetConverter.java b/src/main/java/com/caoccao/javet/utils/converters/IJavetConverter.java
index e6986a1a2..bcaffe597 100644
--- a/src/main/java/com/caoccao/javet/utils/converters/IJavetConverter.java
+++ b/src/main/java/com/caoccao/javet/utils/converters/IJavetConverter.java
@@ -21,8 +21,9 @@
import com.caoccao.javet.interop.V8Runtime;
import com.caoccao.javet.values.V8Value;
+@SuppressWarnings("unchecked")
public interface IJavetConverter {
Object toObject(V8Value v8Value) throws JavetException;
- V8Value toV8Value(V8Runtime v8Runtime, Object object) throws JavetException;
+ T toV8Value(V8Runtime v8Runtime, Object object) throws JavetException;
}
diff --git a/src/main/java/com/caoccao/javet/utils/converters/JavetObjectConverter.java b/src/main/java/com/caoccao/javet/utils/converters/JavetObjectConverter.java
index b7a459544..f65320f6b 100644
--- a/src/main/java/com/caoccao/javet/utils/converters/JavetObjectConverter.java
+++ b/src/main/java/com/caoccao/javet/utils/converters/JavetObjectConverter.java
@@ -17,21 +17,34 @@
package com.caoccao.javet.utils.converters;
+import com.caoccao.javet.entities.JavetEntityMap;
import com.caoccao.javet.exceptions.JavetException;
import com.caoccao.javet.interop.V8Runtime;
import com.caoccao.javet.values.V8Value;
+import com.caoccao.javet.values.V8ValueReferenceType;
import com.caoccao.javet.values.primitive.*;
import com.caoccao.javet.values.reference.*;
-import com.caoccao.javet.values.virtual.V8VirtualList;
import java.util.*;
+@SuppressWarnings("unchecked")
public class JavetObjectConverter extends JavetPrimitiveConverter {
+ public static final String PROPERTY_CONSTRUCTOR = "constructor";
+ public static final String PROPERTY_NAME = "name";
+
public JavetObjectConverter() {
super();
}
+ protected Map createEntityMap() {
+ return new JavetEntityMap();
+ }
+
+ protected boolean isEntityMap(Object object) {
+ return object instanceof JavetEntityMap;
+ }
+
@Override
public Object toObject(V8Value v8Value) throws JavetException {
Object returnObject = super.toObject(v8Value);
@@ -61,21 +74,76 @@ public Object toObject(V8Value v8Value) throws JavetException {
} else if (v8Value instanceof V8ValueSet) {
V8ValueSet v8ValueSet = (V8ValueSet) v8Value;
HashSet