Last active
March 25, 2019 08:16
-
-
Save danielgindi/933b6ef0feab40888465205de37e09da to your computer and use it in GitHub Desktop.
Patch to add a "sourceless" feature to node.js v10.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 | |
@@ -1449,12 +1449,13 @@ class V8_EXPORT ScriptCompiler { | |
enum CompileOptions { | |
kNoCompileOptions = 0, | |
- kProduceParserCache, | |
- kConsumeParserCache, | |
- kProduceCodeCache, | |
- kProduceFullCodeCache, | |
- kConsumeCodeCache, | |
- kEagerCompile | |
+ kProduceParserCache = 1, | |
+ kConsumeParserCache = 2, | |
+ kProduceCodeCache = 4, | |
+ kProduceFullCodeCache = 8, | |
+ kConsumeCodeCache = 16, | |
+ kEagerCompile = 32, | |
+ kSourcelessCodeCache = 64 | |
}; | |
/** | |
--- a/deps/v8/src/api.cc | |
+++ b/deps/v8/src/api.cc | |
@@ -2407,6 +2407,14 @@ MaybeLocal<UnboundScript> ScriptCompiler::CompileUnboundInternal( | |
ENTER_V8_NO_SCRIPT(isolate, v8_isolate->GetCurrentContext(), ScriptCompiler, | |
CompileUnbound, MaybeLocal<UnboundScript>(), | |
InternalEscapableScope); | |
+ | |
+ CompileOptions compile_options = options; | |
+ | |
+ bool sourcelessCodeCache = | |
+ (options & ScriptCompiler::kSourcelessCodeCache) != 0; | |
+ options = static_cast<ScriptCompiler::CompileOptions>( | |
+ options & ~ScriptCompiler::kSourcelessCodeCache); | |
+ | |
// ProduceParserCache, ProduceCodeCache, ProduceFullCodeCache and | |
// ConsumeParserCache are not supported. They are present only for | |
// backward compatability. All these options behave as kNoCompileOptions. | |
@@ -2415,11 +2415,22 @@ MaybeLocal<UnboundScript> ScriptCompiler::CompileUnboundInternal( | |
// rejected to signal an error. | |
options = kNoCompileOptions; | |
source->cached_data->rejected = true; | |
- } else if (options == kProduceParserCache || options == kProduceCodeCache || | |
+ } else if (options == kProduceParserCache || | |
+ options == kProduceCodeCache || | |
options == kProduceFullCodeCache) { | |
options = kNoCompileOptions; | |
} | |
+ 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); | |
@@ -2438,12 +2438,27 @@ MaybeLocal<UnboundScript> ScriptCompiler::CompileUnboundInternal( | |
i::MaybeHandle<i::SharedFunctionInfo> maybe_function_info = | |
i::Compiler::GetSharedFunctionInfoForScript( | |
str, script_details, source->resource_options, nullptr, script_data, | |
- options, no_cache_reason, i::NOT_NATIVES_CODE); | |
+ compile_options, no_cache_reason, i::NOT_NATIVES_CODE); | |
if (options == kConsumeCodeCache) { | |
source->cached_data->rejected = script_data->rejected(); | |
} | |
delete script_data; | |
has_pending_exception = !maybe_function_info.ToHandle(&result); | |
+ | |
+ 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()); | |
+ } | |
+ | |
RETURN_ON_FAILED_EXECUTION(UnboundScript); | |
RETURN_ESCAPED(ToApiHandle<UnboundScript>(result)); | |
} | |
@@ -2538,6 +2538,9 @@ 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); | |
--- a/deps/v8/src/assembler.h | |
+++ b/deps/v8/src/assembler.h | |
@@ -304,6 +304,11 @@ class CpuFeatures : public AllStatic { | |
static void PrintTarget(); | |
static void PrintFeatures(); | |
+ static void Reinitialize() { | |
+ supported_ = 0; | |
+ initialized_ = false; | |
+ } | |
+ | |
private: | |
friend class ExternalReference; | |
friend class AssemblerBase; | |
--- a/deps/v8/src/compiler.cc | |
+++ b/deps/v8/src/compiler.cc | |
@@ -1646,6 +1646,11 @@ MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript( | |
Isolate* isolate = source->GetIsolate(); | |
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); | |
@@ -1691,8 +1691,12 @@ MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript( | |
.ToHandle(&inner_result)) { | |
// Promote to per-isolate compilation cache. | |
DCHECK(inner_result->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 { | |
@@ -1720,8 +1720,10 @@ MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript( | |
Handle<SharedFunctionInfo> result; | |
if (extension == nullptr && maybe_result.ToHandle(&result)) { | |
DCHECK(result->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.cc | |
+++ b/deps/v8/src/objects.cc | |
@@ -13182,6 +13182,11 @@ Handle<String> JSFunction::ToString(Handle<JSFunction> function) { | |
function, isolate->factory()->class_positions_symbol()); | |
if (maybe_class_positions->IsTuple2()) { | |
Tuple2* class_positions = Tuple2::cast(*maybe_class_positions); | |
+ | |
+ if (Script::cast(shared_info->script())->source()->IsUndefined(isolate)) { | |
+ return isolate->factory()->NewStringFromAsciiChecked("class {}"); | |
+ } | |
+ | |
int start_position = Smi::ToInt(class_positions->value1()); | |
int end_position = Smi::ToInt(class_positions->value2()); | |
Handle<String> script_source( | |
--- a/deps/v8/src/snapshot/code-serializer.cc | |
+++ b/deps/v8/src/snapshot/code-serializer.cc | |
@@ -261,7 +261,7 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize( | |
SerializedCodeData::CHECK_SUCCESS; | |
const SerializedCodeData scd = SerializedCodeData::FromCachedData( | |
isolate, cached_data, SerializedCodeData::SourceHash(source), | |
- &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()); | |
@@ -400,7 +400,7 @@ 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 != ComputeMagicNumber(isolate)) return MAGIC_NUMBER_MISMATCH; | |
@@ -412,8 +412,12 @@ SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck( | |
uint32_t c1 = GetHeaderValue(kChecksum1Offset); | |
uint32_t c2 = GetHeaderValue(kChecksum2Offset); | |
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; | |
@@ -474,10 +474,10 @@ 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 | |
@@ -134,7 +134,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, | |
@@ -160,7 +160,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