Skip to content

Commit

Permalink
Javet v0.9.1 (#47)
Browse files Browse the repository at this point in the history
* Moved V8 to a custom classloader
* Enabled `unloadLibrary()` and `loadLibrary()` in `V8Host`
caoccao authored Jun 15, 2021

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent 0fe198b commit 9b54b12
Showing 127 changed files with 2,309 additions and 1,455 deletions.
6 changes: 3 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
@@ -40,22 +40,22 @@ Maven
<dependency>
<groupId>com.caoccao.javet</groupId>
<artifactId>javet</artifactId>
<version>0.9.0</version>
<version>0.9.1</version>
</dependency>
Gradle Kotlin DSL
^^^^^^^^^^^^^^^^^

.. code-block:: kotlin
implementation("com.caoccao.javet:javet:0.9.0")
implementation("com.caoccao.javet:javet:0.9.1")
Gradle Groovy DSL
^^^^^^^^^^^^^^^^^

.. code-block:: groovy
implementation 'com.caoccao.javet:javet:0.9.0'
implementation 'com.caoccao.javet:javet:0.9.1'
Hello Javet
-----------
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@ repositories {
}

group = "com.caoccao.javet"
version = "0.9.0"
version = "0.9.1"

repositories {
mavenCentral()
2 changes: 1 addition & 1 deletion cpp/build.cmd
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
@echo off
REM Usage for V8: build -DV8_DIR=C:\v8
REM Usage for Node: build -DNODE_DIR=C:\node
SET JAVET_VERSION=0.9.0
SET JAVET_VERSION=0.9.1
rd /s/q build
mkdir build
cd build
2 changes: 1 addition & 1 deletion cpp/build.sh
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@

# Usage for V8: build -DV8_DIR=~/v8
# Usage for Node: build -DNODE_DIR=~/node
JAVET_VERSION=0.9.0
JAVET_VERSION=0.9.1
rm -rf build
mkdir build
cd build
58 changes: 40 additions & 18 deletions cpp/jni/com_caoccao_javet_interop_V8Native.cpp
Original file line number Diff line number Diff line change
@@ -43,14 +43,24 @@
namespace Javet {
#ifdef ENABLE_NODE
namespace NodeNative {
static jclass jclassV8Host;
static jmethodID jmethodIDV8HostIsLibraryReloadable;

static std::shared_ptr<node::ArrayBufferAllocator> GlobalNodeArrayBufferAllocator;

void Dispose() {
GlobalNodeArrayBufferAllocator.reset();
void Dispose(JNIEnv* jniEnv) {
if (!jniEnv->CallStaticBooleanMethod(jclassV8Host, jmethodIDV8HostIsLibraryReloadable)) {
GlobalNodeArrayBufferAllocator.reset();
}
}

void Initialize(JNIEnv* jniEnv) {
GlobalNodeArrayBufferAllocator = node::ArrayBufferAllocator::Create();
jclassV8Host = (jclass)jniEnv->NewGlobalRef(jniEnv->FindClass("com/caoccao/javet/interop/V8Host"));
jmethodIDV8HostIsLibraryReloadable = jniEnv->GetStaticMethodID(jclassV8Host, "isLibraryReloadable", "()Z");

if (!GlobalNodeArrayBufferAllocator) {
GlobalNodeArrayBufferAllocator = node::ArrayBufferAllocator::Create();
}
}
}
#endif
@@ -62,15 +72,20 @@ namespace Javet {
static std::unique_ptr<V8Platform> GlobalV8Platform;
#endif

static jclass jclassV8Host;
static jmethodID jmethodIDV8HostIsLibraryReloadable;

static jclass jclassV8ValueInteger;
static jmethodID jmethodIDV8ValueIntegerToPrimitive;

static jclass jclassV8ValueString;
static jmethodID jmethodIDV8ValueStringToPrimitive;

void Dispose() {
v8::V8::Dispose();
v8::V8::ShutdownPlatform();
void Dispose(JNIEnv* jniEnv) {
if (!jniEnv->CallStaticBooleanMethod(jclassV8Host, jmethodIDV8HostIsLibraryReloadable)) {
v8::V8::Dispose();
v8::V8::ShutdownPlatform();
}
}

/*
@@ -79,6 +94,8 @@ namespace Javet {
or runtime memory corruption will take place.
*/
void Initialize(JNIEnv* jniEnv) {
jclassV8Host = (jclass)jniEnv->NewGlobalRef(jniEnv->FindClass("com/caoccao/javet/interop/V8Host"));
jmethodIDV8HostIsLibraryReloadable = jniEnv->GetStaticMethodID(jclassV8Host, "isLibraryReloadable", "()Z");

jclassV8ValueInteger = (jclass)jniEnv->NewGlobalRef(jniEnv->FindClass("com/caoccao/javet/values/primitive/V8ValueInteger"));
jmethodIDV8ValueIntegerToPrimitive = jniEnv->GetMethodID(jclassV8ValueInteger, JAVA_METHOD_TO_PRIMITIVE, "()I");
@@ -90,21 +107,26 @@ namespace Javet {
#ifdef ENABLE_I18N
v8::V8::InitializeICU();
#endif
#ifdef ENABLE_NODE
uv_setup_args(0, nullptr);
std::vector<std::string> args{ "" };
std::vector<std::string> execArgs{ "" };
std::vector<std::string> errors;
int errorCode = node::InitializeNodeWithArgs(&args, &execArgs, &errors);
if (errorCode != 0) {
LOG_ERROR("Failed to call node::InitializeNodeWithArgs().");
if (Javet::V8Native::GlobalV8Platform) {
LOG_INFO("V8::Initialize() is skipped.");
}
Javet::V8Native::GlobalV8Platform = node::MultiIsolatePlatform::Create(4);
else {
#ifdef ENABLE_NODE
uv_setup_args(0, nullptr);
std::vector<std::string> args{ "" };
std::vector<std::string> execArgs{ "" };
std::vector<std::string> errors;
int errorCode = node::InitializeNodeWithArgs(&args, &execArgs, &errors);
if (errorCode != 0) {
LOG_ERROR("Failed to call node::InitializeNodeWithArgs().");
}
Javet::V8Native::GlobalV8Platform = node::MultiIsolatePlatform::Create(4);
#else
Javet::V8Native::GlobalV8Platform = v8::platform::NewDefaultPlatform();
Javet::V8Native::GlobalV8Platform = v8::platform::NewDefaultPlatform();
#endif
v8::V8::InitializePlatform(Javet::V8Native::GlobalV8Platform.get());
v8::V8::Initialize();
v8::V8::InitializePlatform(Javet::V8Native::GlobalV8Platform.get());
v8::V8::Initialize();
}
LOG_INFO("V8::Initialize() ends.");
}
}
16 changes: 8 additions & 8 deletions cpp/jni/com_caoccao_javet_interop_V8Native.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 11 additions & 2 deletions cpp/jni/javet_native.cpp
Original file line number Diff line number Diff line change
@@ -51,10 +51,19 @@ jint JNI_OnLoad(JavaVM* javaVM, void* reserved) {

void JNI_OnUnload(JavaVM* javaVM, void* reserved) {
LOG_INFO("JNI_OnUnload() begins.");
JNIEnv* jniEnv;
if (javaVM->GetEnv((void**)&jniEnv, JNI_VERSION_1_8) != JNI_OK) {
LOG_ERROR("Failed to call JavaVM.GetEnv().");
}
if (jniEnv == nullptr) {
LOG_ERROR("Failed to get JNIEnv.");
}
else {
#ifdef ENABLE_NODE
Javet::NodeNative::Dispose();
Javet::NodeNative::Dispose(jniEnv);
#endif
Javet::V8Native::Dispose();
Javet::V8Native::Dispose(jniEnv);
}
LOG_INFO("JNI_OnUnload() ends.");
}

4 changes: 2 additions & 2 deletions cpp/jni/javet_native.h
Original file line number Diff line number Diff line change
@@ -92,13 +92,13 @@ namespace Javet {

#ifdef ENABLE_NODE
namespace NodeNative {
void Dispose();
void Dispose(JNIEnv* jniEnv);
void Initialize(JNIEnv* jniEnv);
}
#endif

namespace V8Native {
void Dispose();
void Dispose(JNIEnv* jniEnv);
void Initialize(JNIEnv* jniEnv);
}
}
2 changes: 2 additions & 0 deletions cpp/jni/javet_node.h
Original file line number Diff line number Diff line change
@@ -21,6 +21,8 @@

#pragma warning(disable: 4275)
#pragma warning(disable: 4251)
// #define NODE_WANT_INTERNALS 1
// #include <node_binding.h>
#include <node.h>
#include <uv.h>
#pragma warning(default: 4275)
12 changes: 6 additions & 6 deletions cpp/jni/javet_resource_node.rc
Original file line number Diff line number Diff line change
@@ -61,8 +61,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//

VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,9,0,0
PRODUCTVERSION 0,9,0,0
FILEVERSION 0,9,1,0
PRODUCTVERSION 0,9,1,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -79,12 +79,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "caoccao.com"
VALUE "FileDescription", "caoccao.com"
VALUE "FileVersion", "0.9.0.0"
VALUE "InternalName", "libjavet-node-windows-x86_64.v.0.9.0.dll"
VALUE "FileVersion", "0.9.1.0"
VALUE "InternalName", "libjavet-node-windows-x86_64.v.0.9.1.dll"
VALUE "LegalCopyright", "Copyright (C) 2021"
VALUE "OriginalFilename", "libjavet-node-windows-x86_64.v.0.9.0.dll"
VALUE "OriginalFilename", "libjavet-node-windows-x86_64.v.0.9.1.dll"
VALUE "ProductName", "Javet Windows"
VALUE "ProductVersion", "0.9.0.0"
VALUE "ProductVersion", "0.9.1.0"
END
END
BLOCK "VarFileInfo"
12 changes: 6 additions & 6 deletions cpp/jni/javet_resource_v8.rc
Original file line number Diff line number Diff line change
@@ -61,8 +61,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//

VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,9,0,0
PRODUCTVERSION 0,9,0,0
FILEVERSION 0,9,1,0
PRODUCTVERSION 0,9,1,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -79,12 +79,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "caoccao.com"
VALUE "FileDescription", "caoccao.com"
VALUE "FileVersion", "0.9.0.0"
VALUE "InternalName", "libjavet-v8-windows-x86_64.v.0.9.0.dll"
VALUE "FileVersion", "0.9.1.0"
VALUE "InternalName", "libjavet-v8-windows-x86_64.v.0.9.1.dll"
VALUE "LegalCopyright", "Copyright (C) 2021"
VALUE "OriginalFilename", "libjavet-v8-windows-x86_64.v.0.9.0.dll"
VALUE "OriginalFilename", "libjavet-v8-windows-x86_64.v.0.9.1.dll"
VALUE "ProductName", "Javet Windows"
VALUE "ProductVersion", "0.9.0.0"
VALUE "ProductVersion", "0.9.1.0"
END
END
BLOCK "VarFileInfo"
6 changes: 3 additions & 3 deletions docs/development/design.rst
Original file line number Diff line number Diff line change
@@ -34,16 +34,16 @@ Javet supports both Node.js mode and V8 mode both of which can co-exist in one J
.. image:: ../resources/images/javet_modes.png?raw=true
:alt: Javet Modes

As the diagram shows, Javet loads V8 v8.9+ in the default classloader as an out-of-box solution. Node.js is lazy loaded in a custom classloader. Detailed comparisons are as following.
As the diagram shows, both Node.js and V8 are lazy loaded in dedicated custom classloaders. Detailed comparisons are as following.

=========================== ======================= ==============================
Feature Node.js Mode V8 Mode
=========================== ======================= ==============================
Built-in No **Yes**
Lazy Loadable **Yes** **Yes**
Customization **High** **High**
Node.js Ecosystem **Complete** No
Security Low **High**
Unload Potentially Yes No
Unload **Yes** **Yes**
V8 Ecosystem **Complete** **Complete**
V8 Version Low **High**
=========================== ======================= ==============================
2 changes: 1 addition & 1 deletion docs/development/tools.rst
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ For now, Gradle v6.7 + Kotlin DSL constructs the build system.
Node.js
=================

Node.js 14.16.1+ is supported.
Node.js 14.17.0+ is supported.

Maven (Optional)
================
1 change: 1 addition & 0 deletions docs/reference/index.rst
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@ Javet Reference
* `Lock <lock.rst>`_
* `Termination <termination.rst>`_
* `Logging <logging.rst>`_
* `Load and Unload <load_and_unload.rst>`_
* `Best Practices <best_practices.rst>`_
* `Performance <performance.rst>`_
* `Error Codes <error_codes.rst>`_
47 changes: 47 additions & 0 deletions docs/reference/load_and_unload.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
===============
Load and Unload
===============

As documented in `design <../development/design.rst>`_, Javet supports loading and unloading the JNI libraries during runtime in both Node.js and V8 modes.

How?
====

Unload
------

Assuming the JNI library per mode is already loaded, here are the step-by-step on how to unload it.

.. code-block:: java
// Step 1: Set library reloadable. Why? Because Javet defaults that switch to false.
V8Host.setLibraryReloadable(true);
// Step 2: Get V8Host per JS runtime type.
V8Host v8Host = V8Host.getInstance(jsRuntimeType);
// Step 3: Unload the library.
v8Host.unloadLibrary();
// Step 4: Restore the switch.
V8Host.setLibraryReloadable(false);
How does ``unloadLibrary()`` work? There is no API that allows unloading a JNI library explicitly. The only way is GC will automatically unload the library if all references to that library are garbage collectable. So, application is supposed to close all V8 values, V8 runtimes prior to calling ``unloadLibrary()``.

Load
----

Assuming the JNI library per mode is already unloaded, here are the step-by-step on how to load it again.

.. code-block:: java
// Step 1: Get V8Host per JS runtime type.
V8Host v8Host = V8Host.getInstance(jsRuntimeType);
// Step 2: Load the library.
v8Host.loadLibrary();
Notes
=====

* ``unloadLibrary()`` can only take effect after all references are garbage collectable.
* ``loadLibrary()`` is internally called by Javet in the first time and only takes effect after ``unloadLibrary()`` is called.
* ``loadLibrary()`` and ``unloadLibrary()`` are for experiment only. **They may be unstable and crash JVM. Please use this feature at your own risk.**

[`Home <../../README.rst>`_] [`Javet Reference <index.rst>`_]
6 changes: 6 additions & 0 deletions docs/release_notes.rst
Original file line number Diff line number Diff line change
@@ -2,6 +2,12 @@
Release Notes
=============

0.9.1
-----

* Moved V8 to a custom classloader
* Enabled ``unloadLibrary()`` and ``loadLibrary()`` in ``V8Host``

0.9.0
-----

Binary file modified docs/resources/images/javet_modes.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 9b54b12

Please sign in to comment.