Last active
March 25, 2019 08:17
-
-
Save danielgindi/3e6a8b830d649a6f84a10a8b6f2ec153 to your computer and use it in GitHub Desktop.
Patch to add a "sourceless" feature to node.js v11.x
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- 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