Skip to content

Instantly share code, notes, and snippets.

@danielgindi
Last active March 25, 2019 08:17
Show Gist options
  • Save danielgindi/3e6a8b830d649a6f84a10a8b6f2ec153 to your computer and use it in GitHub Desktop.
Save danielgindi/3e6a8b830d649a6f84a10a8b6f2ec153 to your computer and use it in GitHub Desktop.
Patch to add a "sourceless" feature to node.js v11.x
--- a/deps/v8/include/v8.h
+++ b/deps/v8/include/v8.h
@@ -1564,9 +1564,10 @@ class V8_EXPORT ScriptCompiler {
};
enum CompileOptions {
- kNoCompileOptions = 0,
- kConsumeCodeCache,
- kEagerCompile
+ kNoCompileOptions = 0x00,
+ kConsumeCodeCache = 0x01,
+ kEagerCompile = 0x02,
+ kSourcelessCodeCache = 0x04
};
/**
--- a/deps/v8/src/api.cc
+++ b/deps/v8/src/api.cc
@@ -2396,6 +2396,24 @@ MaybeLocal<UnboundScript> ScriptCompiler::CompileUnboundInternal(
CompileUnbound, MaybeLocal<UnboundScript>(),
InternalEscapableScope);
+ CompileOptions compile_options = options;
+
+ bool sourcelessCodeCache =
+ (options & ScriptCompiler::kSourcelessCodeCache) != 0;
+ options = static_cast<CompileOptions>(
+ options & ~CompileOptions::kSourcelessCodeCache);
+
+ bool original_flag_lazy = i::FLAG_lazy;
+ bool original_flag_predictable = i::FLAG_predictable;
+
+ if (sourcelessCodeCache &&
+ options == ScriptCompiler::kNoCompileOptions) {
+ i::FLAG_lazy = false;
+ i::FLAG_predictable = true;
+ i::CpuFeatures::Reinitialize();
+ }
+
i::ScriptData* script_data = nullptr;
if (options == kConsumeCodeCache) {
DCHECK(source->cached_data);
@@ -2414,10 +2432,27 @@ MaybeLocal<UnboundScript> ScriptCompiler::CompileUnboundInternal(
i::MaybeHandle<i::SharedFunctionInfo> maybe_function_info =
i::Compiler::GetSharedFunctionInfoForScript(
isolate, str, script_details, source->resource_options, nullptr,
- script_data, options, no_cache_reason, i::NOT_NATIVES_CODE);
+ script_data, compile_options, no_cache_reason, i::NOT_NATIVES_CODE);
if (options == kConsumeCodeCache) {
source->cached_data->rejected = script_data->rejected();
}
+
+ if (sourcelessCodeCache &&
+ options == ScriptCompiler::kNoCompileOptions) {
+ i::FLAG_lazy = original_flag_lazy;
+ i::FLAG_predictable = original_flag_predictable;
+ i::CpuFeatures::Reinitialize();
+ }
+
+ if (sourcelessCodeCache &&
+ options == ScriptCompiler::kConsumeCodeCache &&
+ !source->cached_data->rejected) {
+ auto script = reinterpret_cast<i::Script*>(
+ maybe_function_info.ToHandleChecked()->script());
+ script->set_source(isolate->heap()->undefined_value());
+ }
+
delete script_data;
has_pending_exception = !maybe_function_info.ToHandle(&result);
RETURN_ON_FAILED_EXECUTION(UnboundScript);
@@ -2453,6 +2488,11 @@ MaybeLocal<Script> ScriptCompiler::Compile(Local<Context> context,
MaybeLocal<Module> ScriptCompiler::CompileModule(
Isolate* isolate, Source* source, CompileOptions options,
NoCacheReason no_cache_reason) {
+
+ CompileOptions compile_options = options;
+ options = static_cast<CompileOptions>(
+ options & ~CompileOptions::kSourcelessCodeCache);
+
CHECK(options == kNoCompileOptions || options == kConsumeCodeCache);
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
@@ -2461,7 +2501,7 @@ MaybeLocal<Module> ScriptCompiler::CompileModule(
"v8::ScriptCompiler::CompileModule",
"Invalid ScriptOrigin: is_module must be true");
auto maybe =
- CompileUnboundInternal(isolate, source, options, no_cache_reason);
+ CompileUnboundInternal(isolate, source, compile_options, no_cache_reason);
Local<UnboundScript> unbound;
if (!maybe.ToLocal(&unbound)) return MaybeLocal<Module>();
@@ -2501,6 +2541,8 @@ MaybeLocal<Function> ScriptCompiler::CompileFunctionInContext(
Function);
TRACE_EVENT_CALL_STATS_SCOPED(isolate, "v8", "V8.ScriptCompiler");
+ options = static_cast<CompileOptions>(
+ options & ~CompileOptions::kSourcelessCodeCache);
+
DCHECK(options == CompileOptions::kConsumeCodeCache ||
options == CompileOptions::kEagerCompile ||
options == CompileOptions::kNoCompileOptions);
@@ -2569,6 +2611,10 @@ ScriptCompiler::ScriptStreamingTask* ScriptCompiler::StartStreamingScript(
if (!i::FLAG_script_streaming) {
return nullptr;
}
+
+ options = static_cast<CompileOptions>(
+ options & ~CompileOptions::kSourcelessCodeCache);
+
// We don't support other compile options on streaming background compiles.
// TODO(rmcilroy): remove CompileOptions from the API.
CHECK(options == ScriptCompiler::kNoCompileOptions);
--- a/deps/v8/src/assembler.h
+++ b/deps/v8/src/assembler.h
@@ -315,6 +315,11 @@ class V8_EXPORT_PRIVATE AssemblerBase : public Malloced {
CodeCommentsWriter code_comments_writer_;
+ static void Reinitialize() {
+ supported_ = 0;
+ initialized_ = false;
+ }
+
private:
// Before we copy code into the code space, we sometimes cannot encode
// call/jump code targets as we normally would, as the difference between the
--- a/deps/v8/src/compiler.cc
+++ b/deps/v8/src/compiler.cc
@@ -1718,6 +1718,11 @@ MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript(
ScriptCompiler::NoCacheReason no_cache_reason, NativesFlag natives) {
ScriptCompileTimerScope compile_timer(isolate, no_cache_reason);
+ bool sourcelessCodeCache =
+ (compile_options & ScriptCompiler::kSourcelessCodeCache) != 0;
+ compile_options = static_cast<ScriptCompiler::CompileOptions>(
+ compile_options & ~ScriptCompiler::kSourcelessCodeCache);
+
if (compile_options == ScriptCompiler::kNoCompileOptions ||
compile_options == ScriptCompiler::kEagerCompile) {
DCHECK_NULL(cached_data);
@@ -1765,8 +1770,12 @@ MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript(
// Promote to per-isolate compilation cache.
is_compiled_scope = inner_result->is_compiled_scope();
DCHECK(is_compiled_scope.is_compiled());
- compilation_cache->PutScript(source, isolate->native_context(),
- language_mode, inner_result);
+
+ if (!sourcelessCodeCache && !source->IsNullOrUndefined(isolate)) {
+ compilation_cache->PutScript(source, isolate->native_context(),
+ language_mode, inner_result);
+ }
+
Handle<Script> script(Script::cast(inner_result->script()), isolate);
maybe_result = inner_result;
} else {
@@ -1793,8 +1802,10 @@ MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript(
Handle<SharedFunctionInfo> result;
if (extension == nullptr && maybe_result.ToHandle(&result)) {
DCHECK(is_compiled_scope.is_compiled());
- compilation_cache->PutScript(source, isolate->native_context(),
- language_mode, result);
+ if (!sourcelessCodeCache && !source->IsNullOrUndefined(isolate)) {
+ compilation_cache->PutScript(source, isolate->native_context(),
+ language_mode, result);
+ }
} else if (maybe_result.is_null() && natives != EXTENSION_CODE &&
natives != NATIVES_CODE) {
isolate->ReportPendingMessages();
--- a/deps/v8/src/objects/js-objects.cc
+++ b/deps/v8/src/objects/js-objects.cc
@@ -5386,6 +5386,11 @@ Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
if (maybe_class_positions->IsClassPositions()) {
ClassPositions class_positions =
ClassPositions::cast(*maybe_class_positions);
+
+ if (Script::cast(shared_info->script())->source()->IsUndefined(isolate)) {
+ return isolate->factory()->NewStringFromAsciiChecked("class {}");
+ }
+
int start_position = class_positions->start();
int end_position = class_positions->end();
Handle<String> script_source(
--- a/deps/v8/src/snapshot/code-serializer.cc
+++ b/deps/v8/src/snapshot/code-serializer.cc
@@ -236,7 +236,7 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
const SerializedCodeData scd = SerializedCodeData::FromCachedData(
isolate, cached_data,
SerializedCodeData::SourceHash(source, origin_options),
- &sanity_check_result);
+ &sanity_check_result, source->IsUndefined(isolate));
if (sanity_check_result != SerializedCodeData::CHECK_SUCCESS) {
if (FLAG_profile_deserialization) PrintF("[Cached code failed check]\n");
DCHECK(cached_data->rejected());
@@ -353,7 +353,8 @@ SerializedCodeData::SerializedCodeData(const std::vector<byte>* payload,
}
SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck(
- Isolate* isolate, uint32_t expected_source_hash) const {
+ Isolate* isolate, uint32_t expected_source_hash,
+ bool sourceless) const {
if (this->size_ < kHeaderSize) return INVALID_HEADER;
uint32_t magic_number = GetMagicNumber();
if (magic_number != kMagicNumber) return MAGIC_NUMBER_MISMATCH;
@@ -365,8 +366,13 @@ SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck(
uint32_t c1 = GetHeaderValue(kChecksumPartAOffset);
uint32_t c2 = GetHeaderValue(kChecksumPartBOffset);
if (version_hash != Version::Hash()) return VERSION_MISMATCH;
- if (source_hash != expected_source_hash) return SOURCE_MISMATCH;
- if (cpu_features != static_cast<uint32_t>(CpuFeatures::SupportedFeatures())) {
+ if (!sourceless && source_hash != expected_source_hash)
+ return SOURCE_MISMATCH;
+ uint32_t host_features = static_cast<uint32_t>(
+ CpuFeatures::SupportedFeatures());
+ if (sourceless ?
+ (cpu_features & (~host_features)) != 0 :
+ cpu_features != host_features) {
return CPU_FEATURES_MISMATCH;
}
if (flags_hash != FlagList::Hash()) return FLAGS_MISMATCH;
@@ -425,10 +431,11 @@ SerializedCodeData::SerializedCodeData(ScriptData* data)
SerializedCodeData SerializedCodeData::FromCachedData(
Isolate* isolate, ScriptData* cached_data, uint32_t expected_source_hash,
- SanityCheckResult* rejection_result) {
+ SanityCheckResult* rejection_result, bool sourceless) {
DisallowHeapAllocation no_gc;
SerializedCodeData scd(cached_data);
- *rejection_result = scd.SanityCheck(isolate, expected_source_hash);
+ *rejection_result = scd.SanityCheck(isolate, expected_source_hash,
+ sourceless);
if (*rejection_result != CHECK_SUCCESS) {
cached_data->Reject();
return SerializedCodeData(nullptr, 0);
--- a/deps/v8/src/snapshot/code-serializer.h
+++ b/deps/v8/src/snapshot/code-serializer.h
@@ -120,7 +120,8 @@ class SerializedCodeData : public SerializedData {
static SerializedCodeData FromCachedData(Isolate* isolate,
ScriptData* cached_data,
uint32_t expected_source_hash,
- SanityCheckResult* rejection_result);
+ SanityCheckResult* rejection_result,
+ bool sourceless);
// Used when producing.
SerializedCodeData(const std::vector<byte>* payload,
@@ -145,7 +146,8 @@ class SerializedCodeData : public SerializedData {
}
SanityCheckResult SanityCheck(Isolate* isolate,
- uint32_t expected_source_hash) const;
+ uint32_t expected_source_hash,
+ bool sourceless) const;
};
} // namespace internal
--- a/lib/internal/bootstrap/loaders.js
+++ b/lib/internal/bootstrap/loaders.js
@@ -339,7 +339,7 @@
// cachedData, produceCachedData, parsingContext)
const script = new ContextifyScript(
source, this.filename, 0, 0,
- cache, false, undefined
+ cache, false, undefined, false
);
// This will be used to create code cache in tools/generate_code_cache.js
--- a/lib/vm.js
+++ b/lib/vm.js
@@ -55,8 +55,9 @@ class Script extends ContextifyScript {
columnOffset = 0,
cachedData,
produceCachedData = false,
importModuleDynamically,
[kParsingContext]: parsingContext,
+ sourceless = false,
} = options;
if (typeof filename !== 'string') {
@@ -82,7 +82,8 @@ class Script extends ContextifyScript {
columnOffset,
cachedData,
produceCachedData,
- parsingContext);
+ parsingContext,
+ sourceless);
} catch (e) {
throw e; /* node-do-not-add-exception-line */
}
--- a/src/node_contextify.cc
+++ b/src/node_contextify.cc
@@ -65,6 +65,7 @@ using v8::TryCatch;
using v8::Uint32;
using v8::Uint8Array;
using v8::UnboundScript;
+using v8::V8;
using v8::Value;
using v8::WeakCallbackInfo;
using v8::WeakCallbackType;
@@ -630,12 +630,13 @@ void ContextifyScript::New(const FunctionCallbackInfo<Value>& args) {
Local<Integer> column_offset;
Local<Uint8Array> cached_data_buf;
bool produce_cached_data = false;
+ bool sourceless = false;
Local<Context> parsing_context = context;
if (argc > 2) {
// new ContextifyScript(code, filename, lineOffset, columnOffset,
// cachedData, produceCachedData, parsingContext)
- CHECK_EQ(argc, 7);
+ CHECK_EQ(argc, 8);
CHECK(args[2]->IsNumber());
line_offset = args[2].As<Integer>();
CHECK(args[3]->IsNumber());
@@ -648,6 +648,7 @@ void ContextifyScript::New(const FunctionCallbackInfo<Value>& args) {
}
CHECK(args[5]->IsBoolean());
produce_cached_data = args[5]->IsTrue();
+ sourceless = args[7]->IsTrue();
if (!args[6]->IsUndefined()) {
CHECK(args[6]->IsObject());
ContextifyContext* sandbox =
@@ -680,9 +680,13 @@ void ContextifyScript::New(const FunctionCallbackInfo<Value>& args) {
data + cached_data_buf->ByteOffset(), cached_data_buf->ByteLength());
}
+ if (cached_data != nullptr && sourceless) {
+ code = v8::Undefined(isolate).As<v8::String>();
+ }
+
Local<PrimitiveArray> host_defined_options =
PrimitiveArray::New(isolate, loader::HostDefinedOptions::kLength);
host_defined_options->Set(isolate, loader::HostDefinedOptions::kType,
Number::New(isolate, loader::ScriptType::kScript));
host_defined_options->Set(isolate, loader::HostDefinedOptions::kID,
Number::New(isolate, contextify_script->id()));
@@ -711,5 +711,9 @@ void ContextifyScript::New(const FunctionCallbackInfo<Value>& args) {
if (source.GetCachedData() != nullptr)
compile_options = ScriptCompiler::kConsumeCodeCache;
+
+ if (sourceless)
+ compile_options = (ScriptCompiler::CompileOptions)(
+ compile_options | ScriptCompiler::kSourcelessCodeCache);
TryCatch try_catch(isolate);
Environment::ShouldNotAbortOnUncaughtScope no_abort_scope(env);
@@ -734,9 +734,9 @@ void ContextifyScript::New(const FunctionCallbackInfo<Value>& args) {
contextify_script);
return;
}
contextify_script->script_.Reset(isolate, v8_script.ToLocalChecked());
- if (compile_options == ScriptCompiler::kConsumeCodeCache) {
+ if ((compile_options & ScriptCompiler::kConsumeCodeCache)) {
args.This()->Set(
env->cached_data_rejected_string(),
Boolean::New(isolate, source.GetCachedData()->rejected));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment