Skip to content

Instantly share code, notes, and snippets.

@danielgindi
Last active March 25, 2019 08:16
Show Gist options
  • Save danielgindi/933b6ef0feab40888465205de37e09da to your computer and use it in GitHub Desktop.
Save danielgindi/933b6ef0feab40888465205de37e09da to your computer and use it in GitHub Desktop.
Patch to add a "sourceless" feature to node.js v10.x
--- 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