Skip to content

Commit

Permalink
🦄 refactor: Revise snapshot native code
Browse files Browse the repository at this point in the history
  • Loading branch information
caoccao committed Apr 17, 2024
1 parent f5699dc commit 5b3c583
Show file tree
Hide file tree
Showing 5 changed files with 14 additions and 50 deletions.
5 changes: 0 additions & 5 deletions cpp/jni/javet_jni_core_v8.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -357,12 +357,7 @@ JNIEXPORT void JNICALL Java_com_caoccao_javet_interop_V8Native_setWeak

JNIEXPORT jbyteArray JNICALL Java_com_caoccao_javet_interop_V8Native_snapshotCreate
(JNIEnv* jniEnv, jobject caller, jlong v8RuntimeHandle) {
#ifdef ENABLE_NODE
auto v8Runtime = Javet::V8Runtime::FromHandle(v8RuntimeHandle);
auto v8Locker = v8Runtime->GetSharedV8Locker();
#else
RUNTIME_HANDLES_TO_OBJECTS_WITH_SCOPE(v8RuntimeHandle);
#endif
return v8Runtime->CreateSnapshot(jniEnv);
}

Expand Down
4 changes: 3 additions & 1 deletion cpp/jni/javet_node.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
#include <env-inl.h>
#include <crypto/crypto_util.h>
#include <node_snapshot_builder.h>
// Hack Begins (The hack is for resolving the conflicts between Node.js and V8)
// Hack Begins (The hack is for resolving the conflicts between Node.js and V8)
#define BASE_TRACE_EVENT_COMMON_TRACE_EVENT_COMMON_H_
#define V8_TRACING_TRACE_EVENT_H_
#undef CHECK
Expand Down Expand Up @@ -72,5 +72,7 @@
#endif

constexpr auto DEFAULT_SCRIPT_NAME = "javet.js";
constexpr auto INIT_SCRIPT_WITH_SNAPSHOT = "globalThis.require = require;";
constexpr auto INIT_SCRIPT_WITHOUT_SNAPSHOT = "globalThis.require = require('module').createRequire(process.cwd() + '/');";

#endif
1 change: 1 addition & 0 deletions cpp/jni/javet_v8.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
// Scope

using V8ContextScope = v8::Context::Scope;
using V8EscapableHandleScope = v8::EscapableHandleScope;
using V8HandleScope = v8::HandleScope;
using V8IsolateScope = v8::Isolate::Scope;

Expand Down
51 changes: 9 additions & 42 deletions cpp/jni/javet_v8_runtime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,50 +220,18 @@ namespace Javet {
jbyteArray V8Runtime::CreateSnapshot(JNIEnv* jniEnv) noexcept {
jbyteArray jbytes = nullptr;
if (v8SnapshotCreator) {
#ifdef ENABLE_NODE
v8::MaybeLocal<v8::Context> v8MaybeLocalContext;
{
auto v8IsolateScope = GetV8IsolateScope();
V8HandleScope v8HandleScope(v8Isolate);
auto v8LocalContext = GetV8LocalContext();
auto v8ContextScope = GetV8ContextScope(v8LocalContext);
// Backup context and global object (Begin)
v8GlobalContext.Reset();
v8GlobalObject.Reset();
// Backup context and global object (End)
nodeIsolateData->Serialize(v8SnapshotCreator.get());
nodeEnvironment->Serialize(v8SnapshotCreator.get());
v8SnapshotCreator->SetDefaultContext(v8LocalContext, { node::SerializeNodeContextInternalFields, nodeEnvironment.get() });
v8MaybeLocalContext = v8::MaybeLocal<v8::Context>(v8LocalContext);
}
// TODO: Unknown external reference
v8::StartupData newV8StartupData = v8SnapshotCreator->CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kKeep);
if (newV8StartupData.IsValid()) {
jbytes = jniEnv->NewByteArray(newV8StartupData.raw_size);
jboolean isCopy;
void* data = jniEnv->GetPrimitiveArrayCritical(jbytes, &isCopy);
memcpy(data, newV8StartupData.data, newV8StartupData.raw_size);
jniEnv->ReleasePrimitiveArrayCritical(jbytes, data, JNI_ABORT);
delete[] newV8StartupData.data;
}
{
auto v8IsolateScope = GetV8IsolateScope();
V8HandleScope v8HandleScope(v8Isolate);
auto v8LocalContext = v8MaybeLocalContext.ToLocalChecked();
auto v8ContextScope = GetV8ContextScope(v8LocalContext);
// Restore context and global object (Begin)
v8GlobalContext.Reset(v8Isolate, v8LocalContext);
v8GlobalObject.Reset(
v8Isolate, v8LocalContext->Global()->GetPrototype()->ToObject(v8LocalContext).ToLocalChecked());
// Restore context and global object (End)
}
#else
// Backup context and global object (Begin)
auto v8LocalContext = GetV8LocalContext();
v8GlobalContext.Reset();
v8GlobalObject.Reset();
// Backup context and global object (End)
#ifdef ENABLE_NODE
nodeIsolateData->Serialize(v8SnapshotCreator.get());
nodeEnvironment->Serialize(v8SnapshotCreator.get());
v8SnapshotCreator->SetDefaultContext(v8LocalContext, { node::SerializeNodeContextInternalFields, nodeEnvironment.get() });
#else
v8SnapshotCreator->SetDefaultContext(v8LocalContext);
#endif
v8::StartupData newV8StartupData = v8SnapshotCreator->CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kKeep);
if (newV8StartupData.IsValid()) {
jbytes = jniEnv->NewByteArray(newV8StartupData.raw_size);
Expand All @@ -278,7 +246,6 @@ namespace Javet {
v8GlobalObject.Reset(
v8Isolate, v8LocalContext->Global()->GetPrototype()->ToObject(v8LocalContext).ToLocalChecked());
// Restore context and global object (End)
#endif
}
return jbytes;
}
Expand Down Expand Up @@ -324,10 +291,10 @@ namespace Javet {
execArgs,
flags));
// node::LoadEnvironment is thread-safe.
auto v8MaybeLocalValue = node::LoadEnvironment(
V8MaybeLocalValue v8MaybeLocalValue;
v8MaybeLocalValue = node::LoadEnvironment(
nodeEnvironment.get(),
"const publicRequire = require('module').createRequire(process.cwd() + '/');"
"globalThis.require = publicRequire;"
v8SnapshotCreator ? INIT_SCRIPT_WITH_SNAPSHOT : INIT_SCRIPT_WITHOUT_SNAPSHOT
);
}
#else
Expand Down
3 changes: 1 addition & 2 deletions docs/reference/resource_management/snapshot.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Benefits
Limitations
-----------

* **Not all modules supported**: Only a subset of the built-in Node.js modules are currently supported in snapshots, so some applications might not be suitable for snapshotting.
* **Node.js mode not supported**: Snapshot is only available in the V8 mode. There are some technical difficulties to be resolved in the Node.js mode.
* **Dynamic code updates not possible**: Once a snapshot is created, it's static and cannot be updated with new code without creating a new snapshot.
* **V8 version dependent**: The snapshot created from a particular version of V8 only works in that version of V8. If you want to support a new version of V8, you will have to create a new snapshot in that new version of V8.

Expand Down Expand Up @@ -87,7 +87,6 @@ It's simple to create a snapshot or provide an existing snapshot in Javet via th
.. note::

* Snapshot is only available in the V8 mode. There are some technical difficulties to be resolved in the Node.js mode.
* Both ``setCreateSnapshotEnabled()`` and ``setSnapshotBlob()`` can be used together so that you may create a V8 runtime by an existing snapshot, then create a new snapshot from that V8 runtime.

Create a Snapshot via mksnapshot
Expand Down

0 comments on commit 5b3c583

Please sign in to comment.