patches: drop Node < 8 and old point releases (#140)

This commit is contained in:
Jesse Chan 2021-03-29 21:20:23 +08:00 committed by GitHub
parent f4264a8a09
commit d8a494b5f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 1 additions and 12261 deletions

View File

@ -1,139 +0,0 @@
From d1cacb814f6d42395184beaaba906ba930e711eb Mon Sep 17 00:00:00 2001
From: Fedor Indutny <fedor@indutny.com>
Date: Wed, 20 Jan 2016 19:34:19 -0500
Subject: vm: introduce `cachedData`/`produceCachedData`
Introduce `cachedData`/`produceCachedData` options for `v8.Script`.
Could be used to consume/produce V8's code cache for speeding up
compilation of known code.
PR-URL: https://github.com/nodejs/node/pull/4777
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
diff --git a/src/node_contextify.cc b/src/node_contextify.cc
index 2e8fd2c..1b3d618 100644
--- a/src/node_contextify.cc
+++ b/src/node_contextify.cc
@@ -18,10 +18,11 @@
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "node.h"
+#include "node_buffer.h"
#include "node_internals.h"
#include "node_watchdog.h"
#include "base-object.h"
#include "base-object-inl.h"
#include "env.h"
@@ -484,28 +485,60 @@ class ContextifyScript : public BaseObject {
TryCatch try_catch;
Local<String> code = args[0]->ToString();
Local<String> filename = GetFilenameArg(args, 1);
bool display_errors = GetDisplayErrorsArg(args, 1);
+ Local<Value> cached_data_buf = GetCachedData(args, 1);
+ bool produce_cached_data = GetProduceCachedData(args, 1);
if (try_catch.HasCaught()) {
try_catch.ReThrow();
return;
}
+ ScriptCompiler::CachedData* cached_data = NULL;
+ if (!cached_data_buf.IsEmpty()) {
+ cached_data = new ScriptCompiler::CachedData(
+ reinterpret_cast<uint8_t*>(Buffer::Data(cached_data_buf)),
+ Buffer::Length(cached_data_buf));
+ }
+
ScriptOrigin origin(filename);
- ScriptCompiler::Source source(code, origin);
- Local<UnboundScript> v8_script =
- ScriptCompiler::CompileUnbound(env->isolate(), &source);
+ ScriptCompiler::Source source(code, origin, cached_data);
+ ScriptCompiler::CompileOptions compile_options =
+ ScriptCompiler::kNoCompileOptions;
+
+ if (source.GetCachedData() != NULL)
+ compile_options = ScriptCompiler::kConsumeCodeCache;
+ else if (produce_cached_data)
+ compile_options = ScriptCompiler::kProduceCodeCache;
+
+ Local<UnboundScript> v8_script = ScriptCompiler::CompileUnbound(
+ env->isolate(),
+ &source,
+ compile_options);
if (v8_script.IsEmpty()) {
if (display_errors) {
AppendExceptionLine(env, try_catch.Exception(), try_catch.Message());
}
try_catch.ReThrow();
return;
}
contextify_script->script_.Reset(env->isolate(), v8_script);
+
+ if (compile_options == ScriptCompiler::kConsumeCodeCache) {
+ // no 'rejected' field in cachedData
+ } else if (compile_options == ScriptCompiler::kProduceCodeCache) {
+ const ScriptCompiler::CachedData* cached_data = source.GetCachedData();
+ Local<Object> buf = Buffer::New(
+ env,
+ reinterpret_cast<const char*>(cached_data->data),
+ cached_data->length);
+ Local<String> cached_data_string = FIXED_ONE_BYTE_STRING(
+ args.GetIsolate(), "cachedData");
+ args.This()->Set(cached_data_string, buf);
+ }
}
static bool InstanceOf(Environment* env, const Local<Value>& value) {
return !value.IsEmpty() &&
@@ -656,10 +689,46 @@ class ContextifyScript : public BaseObject {
return value->IsUndefined() ? defaultFilename : value->ToString();
}
+ static Local<Value> GetCachedData(
+ const FunctionCallbackInfo<Value>& args,
+ const int i) {
+ if (!args[i]->IsObject()) {
+ return Local<Value>();
+ }
+ Local<String> key = FIXED_ONE_BYTE_STRING(args.GetIsolate(), "cachedData");
+ Local<Value> value = args[i].As<Object>()->Get(key);
+ if (value->IsUndefined()) {
+ return Local<Value>();
+ }
+
+ if (!Buffer::HasInstance(value)) {
+ Environment::ThrowTypeError(
+ args.GetIsolate(),
+ "options.cachedData must be a Buffer instance");
+ return Local<Value>();
+ }
+
+ return value;
+ }
+
+
+ static bool GetProduceCachedData(
+ const FunctionCallbackInfo<Value>& args,
+ const int i) {
+ if (!args[i]->IsObject()) {
+ return false;
+ }
+ Local<String> key = FIXED_ONE_BYTE_STRING(args.GetIsolate(), "produceCachedData");
+ Local<Value> value = args[i].As<Object>()->Get(key);
+
+ return value->IsTrue();
+ }
+
+
static bool EvalMachine(Environment* env,
const int64_t timeout,
const bool display_errors,
const FunctionCallbackInfo<Value>& args,
TryCatch& try_catch) {

View File

@ -1,178 +0,0 @@
From d1cacb814f6d42395184beaaba906ba930e711eb Mon Sep 17 00:00:00 2001
From: Fedor Indutny <fedor@indutny.com>
Date: Wed, 20 Jan 2016 19:34:19 -0500
Subject: vm: introduce `cachedData`/`produceCachedData`
Introduce `cachedData`/`produceCachedData` options for `v8.Script`.
Could be used to consume/produce V8's code cache for speeding up
compilation of known code.
PR-URL: https://github.com/nodejs/node/pull/4777
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
diff --git a/src/env.h b/src/env.h
index 7b6ffc8..5c99f80 100644
--- a/src/env.h
+++ b/src/env.h
@@ -53,10 +53,12 @@ namespace node {
V(blocks_string, "blocks") \
V(buffer_string, "buffer") \
V(bytes_string, "bytes") \
V(bytes_parsed_string, "bytesParsed") \
V(bytes_read_string, "bytesRead") \
+ V(cached_data_string, "cachedData") \
+ V(cached_data_rejected_string, "cachedDataRejected") \
V(callback_string, "callback") \
V(change_string, "change") \
V(oncertcb_string, "oncertcb") \
V(onclose_string, "_onclose") \
V(code_string, "code") \
@@ -165,10 +167,11 @@ namespace node {
V(pipe_string, "pipe") \
V(port_string, "port") \
V(preference_string, "preference") \
V(priority_string, "priority") \
V(processed_string, "processed") \
+ V(produce_cached_data_string, "produceCachedData") \
V(prototype_string, "prototype") \
V(raw_string, "raw") \
V(rdev_string, "rdev") \
V(readable_string, "readable") \
V(received_shutdown_string, "receivedShutdown") \
diff --git a/src/node_contextify.cc b/src/node_contextify.cc
index 7404bbb..ecf9444 100644
--- a/src/node_contextify.cc
+++ b/src/node_contextify.cc
@@ -1,6 +1,7 @@
#include "node.h"
+#include "node_buffer.h"
#include "node_internals.h"
#include "node_watchdog.h"
#include "base-object.h"
#include "base-object-inl.h"
#include "env.h"
@@ -11,10 +12,11 @@
namespace node {
using v8::AccessType;
using v8::Array;
+using v8::ArrayBuffer;
using v8::Boolean;
using v8::Context;
using v8::Debug;
using v8::EscapableHandleScope;
using v8::External;
@@ -474,28 +476,61 @@ class ContextifyScript : public BaseObject {
Local<String> code = args[0]->ToString(env->isolate());
Local<String> filename = GetFilenameArg(args, 1);
Local<Integer> lineOffset = GetLineOffsetArg(args, 1);
Local<Integer> columnOffset = GetColumnOffsetArg(args, 1);
bool display_errors = GetDisplayErrorsArg(args, 1);
+ MaybeLocal<Value> cached_data_buf = GetCachedData(env, args, 1);
+ bool produce_cached_data = GetProduceCachedData(env, args, 1);
if (try_catch.HasCaught()) {
try_catch.ReThrow();
return;
}
+ ScriptCompiler::CachedData* cached_data = nullptr;
+ if (!cached_data_buf.IsEmpty()) {
+ auto cached_data_local = cached_data_buf.ToLocalChecked();
+ cached_data = new ScriptCompiler::CachedData(
+ reinterpret_cast<uint8_t*>(Buffer::Data(cached_data_local)),
+ Buffer::Length(cached_data_local));
+ }
+
ScriptOrigin origin(filename, lineOffset, columnOffset);
- ScriptCompiler::Source source(code, origin);
- Local<UnboundScript> v8_script =
- ScriptCompiler::CompileUnbound(env->isolate(), &source);
+ ScriptCompiler::Source source(code, origin, cached_data);
+ ScriptCompiler::CompileOptions compile_options =
+ ScriptCompiler::kNoCompileOptions;
+
+ if (source.GetCachedData() != nullptr)
+ compile_options = ScriptCompiler::kConsumeCodeCache;
+ else if (produce_cached_data)
+ compile_options = ScriptCompiler::kProduceCodeCache;
+
+ Local<UnboundScript> v8_script = ScriptCompiler::CompileUnbound(
+ env->isolate(),
+ &source,
+ compile_options);
if (v8_script.IsEmpty()) {
if (display_errors) {
AppendExceptionLine(env, try_catch.Exception(), try_catch.Message());
}
try_catch.ReThrow();
return;
}
contextify_script->script_.Reset(env->isolate(), v8_script);
+
+ if (compile_options == ScriptCompiler::kConsumeCodeCache) {
+ args.This()->Set(
+ env->cached_data_rejected_string(),
+ Boolean::New(env->isolate(), source.GetCachedData()->rejected));
+ } else if (compile_options == ScriptCompiler::kProduceCodeCache) {
+ const ScriptCompiler::CachedData* cached_data = source.GetCachedData();
+ MaybeLocal<Object> buf = Buffer::Copy(
+ env,
+ reinterpret_cast<const char*>(cached_data->data),
+ cached_data->length);
+ args.This()->Set(env->cached_data_string(), buf.ToLocalChecked());
+ }
}
static bool InstanceOf(Environment* env, const Local<Value>& value) {
return !value.IsEmpty() &&
@@ -644,10 +679,47 @@ class ContextifyScript : public BaseObject {
return defaultFilename;
return value->ToString(args.GetIsolate());
}
+ static MaybeLocal<Value> GetCachedData(
+ Environment* env,
+ const FunctionCallbackInfo<Value>& args,
+ const int i) {
+ if (!args[i]->IsObject()) {
+ return MaybeLocal<Value>();
+ }
+ Local<Value> value = args[i].As<Object>()->Get(env->cached_data_string());
+ if (value->IsUndefined()) {
+ return MaybeLocal<Value>();
+ }
+
+ if (!Buffer::HasInstance(value)) {
+ Environment::ThrowTypeError(
+ args.GetIsolate(),
+ "options.cachedData must be a Buffer instance");
+ return MaybeLocal<Value>();
+ }
+
+ return value;
+ }
+
+
+ static bool GetProduceCachedData(
+ Environment* env,
+ const FunctionCallbackInfo<Value>& args,
+ const int i) {
+ if (!args[i]->IsObject()) {
+ return false;
+ }
+ Local<Value> value =
+ args[i].As<Object>()->Get(env->produce_cached_data_string());
+
+ return value->IsTrue();
+ }
+
+
static Local<Integer> GetLineOffsetArg(
const FunctionCallbackInfo<Value>& args,
const int i) {
Local<Integer> defaultLineOffset = Integer::New(args.GetIsolate(), 0);

View File

@ -1,39 +0,0 @@
From 16b0a8c1acb97a84e9a6e1868d600c525f27b0ec Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= <mic.besace@gmail.com>
Date: Mon, 8 Feb 2016 22:36:40 +0100
Subject: src: replace usage of deprecated CompileUnbound
PR-URL: https://github.com/nodejs/node/pull/5159
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
diff --git a/src/node_contextify.cc b/src/node_contextify.cc
index ecf9444..8769b53 100644
--- a/src/node_contextify.cc
+++ b/src/node_contextify.cc
@@ -501,11 +501,11 @@ class ContextifyScript : public BaseObject {
if (source.GetCachedData() != nullptr)
compile_options = ScriptCompiler::kConsumeCodeCache;
else if (produce_cached_data)
compile_options = ScriptCompiler::kProduceCodeCache;
- Local<UnboundScript> v8_script = ScriptCompiler::CompileUnbound(
+ MaybeLocal<UnboundScript> v8_script = ScriptCompiler::CompileUnboundScript(
env->isolate(),
&source,
compile_options);
if (v8_script.IsEmpty()) {
@@ -513,11 +513,12 @@ class ContextifyScript : public BaseObject {
AppendExceptionLine(env, try_catch.Exception(), try_catch.Message());
}
try_catch.ReThrow();
return;
}
- contextify_script->script_.Reset(env->isolate(), v8_script);
+ contextify_script->script_.Reset(env->isolate(),
+ v8_script.ToLocalChecked());
if (compile_options == ScriptCompiler::kConsumeCodeCache) {
args.This()->Set(
env->cached_data_rejected_string(),
Boolean::New(env->isolate(), source.GetCachedData()->rejected));

View File

@ -1,51 +0,0 @@
From 6c8378b15bd9ca378df6e14d5b0d7032caefd774 Mon Sep 17 00:00:00 2001
From: Jiho Choi <jray319@gmail.com>
Date: Sat, 20 Feb 2016 20:44:06 -0600
Subject: vm: fix `produceCachedData`
Fix segmentation faults when compiling the same code with
`produceCachedData` option. V8 ignores the option when the code is in
its compilation cache and does not return cached data. Added
`cachedDataProduced` property to `v8.Script` to denote whether the
cached data is produced successfully.
PR-URL: https://github.com/nodejs/node/pull/5343
Reviewed-By: Fedor Indutny <fedor@indutny.com>
diff --git a/src/node_contextify.cc b/src/node_contextify.cc
index 1b3d618..dfc51e9 100644
--- a/src/node_contextify.cc
+++ b/src/node_contextify.cc
@@ -527,17 +527,25 @@ class ContextifyScript : public BaseObject {
if (compile_options == ScriptCompiler::kConsumeCodeCache) {
// no 'rejected' field in cachedData
} else if (compile_options == ScriptCompiler::kProduceCodeCache) {
const ScriptCompiler::CachedData* cached_data = source.GetCachedData();
- Local<Object> buf = Buffer::New(
- env,
- reinterpret_cast<const char*>(cached_data->data),
- cached_data->length);
- Local<String> cached_data_string = FIXED_ONE_BYTE_STRING(
- args.GetIsolate(), "cachedData");
- args.This()->Set(cached_data_string, buf);
+ bool cached_data_produced = cached_data != NULL;
+ if (cached_data_produced) {
+ Local<Object> buf = Buffer::New(
+ env,
+ reinterpret_cast<const char*>(cached_data->data),
+ cached_data->length);
+ Local<String> cached_data_string = FIXED_ONE_BYTE_STRING(
+ args.GetIsolate(), "cachedData");
+ args.This()->Set(cached_data_string, buf);
+ }
+ Local<String> cached_data_produced_string = FIXED_ONE_BYTE_STRING(
+ args.GetIsolate(), "cachedDataProduced");
+ args.This()->Set(
+ cached_data_produced_string,
+ Boolean::New(env->isolate(), cached_data_produced));
}
}
static bool InstanceOf(Environment* env, const Local<Value>& value) {

View File

@ -1,61 +0,0 @@
From 6c8378b15bd9ca378df6e14d5b0d7032caefd774 Mon Sep 17 00:00:00 2001
From: Jiho Choi <jray319@gmail.com>
Date: Sat, 20 Feb 2016 20:44:06 -0600
Subject: vm: fix `produceCachedData`
Fix segmentation faults when compiling the same code with
`produceCachedData` option. V8 ignores the option when the code is in
its compilation cache and does not return cached data. Added
`cachedDataProduced` property to `v8.Script` to denote whether the
cached data is produced successfully.
PR-URL: https://github.com/nodejs/node/pull/5343
Reviewed-By: Fedor Indutny <fedor@indutny.com>
diff --git a/src/env.h b/src/env.h
index 5c99f80..c0b6dcd 100644
--- a/src/env.h
+++ b/src/env.h
@@ -54,10 +54,11 @@ namespace node {
V(buffer_string, "buffer") \
V(bytes_string, "bytes") \
V(bytes_parsed_string, "bytesParsed") \
V(bytes_read_string, "bytesRead") \
V(cached_data_string, "cachedData") \
+ V(cached_data_produced_string, "cachedDataProduced") \
V(cached_data_rejected_string, "cachedDataRejected") \
V(callback_string, "callback") \
V(change_string, "change") \
V(oncertcb_string, "oncertcb") \
V(onclose_string, "_onclose") \
diff --git a/src/node_contextify.cc b/src/node_contextify.cc
index 8769b53..4f63c20 100644
--- a/src/node_contextify.cc
+++ b/src/node_contextify.cc
@@ -522,15 +522,21 @@ class ContextifyScript : public BaseObject {
args.This()->Set(
env->cached_data_rejected_string(),
Boolean::New(env->isolate(), source.GetCachedData()->rejected));
} else if (compile_options == ScriptCompiler::kProduceCodeCache) {
const ScriptCompiler::CachedData* cached_data = source.GetCachedData();
- MaybeLocal<Object> buf = Buffer::Copy(
- env,
- reinterpret_cast<const char*>(cached_data->data),
- cached_data->length);
- args.This()->Set(env->cached_data_string(), buf.ToLocalChecked());
+ bool cached_data_produced = cached_data != nullptr;
+ if (cached_data_produced) {
+ MaybeLocal<Object> buf = Buffer::Copy(
+ env,
+ reinterpret_cast<const char*>(cached_data->data),
+ cached_data->length);
+ args.This()->Set(env->cached_data_string(), buf.ToLocalChecked());
+ }
+ args.This()->Set(
+ env->cached_data_produced_string(),
+ Boolean::New(env->isolate(), cached_data_produced));
}
}
static bool InstanceOf(Environment* env, const Local<Value>& value) {

View File

@ -1,211 +0,0 @@
commit b324d0bb99045fcfe80397a978eb2ce29af4990f
Author: igorklopov <igor@klopov.com>
Date: Mon Aug 17 11:31:50 2015 +0400
some older revisions mixed together
diff --git a/src/code-stubs.cc b/src/code-stubs.cc
index 0e68ab8..92aca16 100644
--- node/deps/v8/src/code-stubs.cc
+++ node/deps/v8/src/code-stubs.cc
@@ -252,6 +252,172 @@ void CodeStub::PrintName(OStream& os) const { // NOLINT
}
+void CheckCodeStub(CodeStub* pstub, CodeStub::Major MajorKey, int MinorKey) {
+ if (pstub->MajorKey() != MajorKey) fprintf(stderr, "MajorKey %d != %d in %s\n", pstub->MajorKey(), MajorKey, pstub->MajorName(MajorKey, false));
+ if (pstub->MinorKey() != MinorKey) fprintf(stderr, "MinorKey %d != %d in %s\n", pstub->MinorKey(), MinorKey, pstub->MajorName(MajorKey, false));
+ // if (pstub->MajorKey() == MajorKey) fprintf(stderr, "correct MajorKey in %s\n", pstub->MajorName(MajorKey, false));
+ // if (pstub->MinorKey() == MinorKey) fprintf(stderr, "correct MinorKey in %s\n", pstub->MajorName(MajorKey, false));
+}
+
+
+void CodeStub::Dispatch(Isolate* isolate, uint32_t key, void** value_out,
+ DispatchedCall call) {
+ CodeStub::Major MajorKey = MajorKeyFromKey(key);
+ int MinorKey = MinorKeyFromKey(key);
+ switch (MajorKey) {
+ case CEntry: {
+ // int result = (save_doubles_ == kSaveFPRegs) ? 1 : 0;
+ int result_size = (MinorKey & 0x02) ? 2 : 1;
+ // return result | ((result_size_ == 1) ? 0 : 2);
+ SaveFPRegsMode save_doubles = (MinorKey & 0x01) ? kSaveFPRegs : kDontSaveFPRegs;
+ CEntryStub stub(isolate, result_size, save_doubles);
+ CodeStub* pstub = &stub;
+ CheckCodeStub(pstub, MajorKey, MinorKey);
+ call(pstub, value_out);
+ break;
+ }
+ case CallConstruct: {
+ // int MinorKey() const { return flags_; }
+ CallConstructorFlags flags = (CallConstructorFlags) MinorKey;
+ CallConstructStub stub(isolate, flags);
+ CodeStub* pstub = &stub;
+ CheckCodeStub(pstub, MajorKey, MinorKey);
+ call(pstub, value_out);
+ break;
+ }
+ case FastNewContext: {
+ // int NotMissMinorKey() const V8_OVERRIDE { return slots_; }
+ int slots = MinorKey;
+ FastNewContextStub stub(isolate, slots);
+ CodeStub* pstub = &stub;
+ CheckCodeStub(pstub, MajorKey, MinorKey);
+ call(pstub, value_out);
+ break;
+ }
+ case FastNewClosure: {
+ // class StrictModeBits: public BitField<bool, 0, 1> {};
+ StrictMode strict_mode = (StrictMode) (MinorKey & 0x01);
+ // class IsGeneratorBits: public BitField<bool, 1, 1> {};
+ bool is_generator = MinorKey & 0x02;
+ FastNewClosureStub stub(isolate, strict_mode, is_generator);
+ CodeStub* pstub = &stub;
+ CheckCodeStub(pstub, MajorKey, MinorKey);
+ call(pstub, value_out);
+ break;
+ }
+ case RecordWrite: {
+ #if V8_TARGET_ARCH_IA32
+ // class ObjectBits: public BitField<int, 0, 3> {};
+ Register object = Register::from_code(MinorKey & 0x07);
+ // class ValueBits: public BitField<int, 3, 3> {};
+ Register value = Register::from_code((MinorKey >> 3) & 0x07);
+ // class AddressBits: public BitField<int, 6, 3> {};
+ Register address = Register::from_code((MinorKey >> 6) & 0x07);
+ // class RememberedSetActionBits: public BitField<RememberedSetAction, 9, 1> {};
+ RememberedSetAction remembered_set_action = (RememberedSetAction) ((MinorKey >> 9) & 0x01);
+ // class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 10, 1> {};
+ SaveFPRegsMode fp_mode = (SaveFPRegsMode) ((MinorKey >> 10) & 0x01);
+ RecordWriteStub stub(isolate, object, value, address, remembered_set_action, fp_mode);
+ #endif
+ #if V8_TARGET_ARCH_X64
+ // class ObjectBits: public BitField<int, 0, 4> {};
+ Register object = Register::from_code(MinorKey & 0x0F);
+ // class ValueBits: public BitField<int, 4, 4> {};
+ Register value = Register::from_code((MinorKey >> 4) & 0x0F);
+ // class AddressBits: public BitField<int, 8, 4> {};
+ Register address = Register::from_code((MinorKey >> 8) & 0x0F);
+ // class RememberedSetActionBits: public BitField<RememberedSetAction, 12, 1> {};
+ RememberedSetAction remembered_set_action = (RememberedSetAction) ((MinorKey >> 12) & 0x01);
+ // class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 13, 1> {};
+ SaveFPRegsMode fp_mode = (SaveFPRegsMode) ((MinorKey >> 13) & 0x01);
+ RecordWriteStub stub(isolate, object, value, address, remembered_set_action, fp_mode);
+ #endif
+ CodeStub* pstub = &stub;
+ CheckCodeStub(pstub, MajorKey, MinorKey);
+ call(pstub, value_out);
+ break;
+ }
+ case ToNumber: {
+ ToNumberStub stub(isolate);
+ CodeStub* pstub = &stub;
+ CheckCodeStub(pstub, MajorKey, MinorKey);
+ call(pstub, value_out);
+ break;
+ }
+ case ArgumentsAccess: {
+ // int MinorKey() const { return type_; }
+ ArgumentsAccessStub::Type type = (ArgumentsAccessStub::Type) MinorKey;
+ ArgumentsAccessStub stub(isolate, type);
+ CodeStub* pstub = &stub;
+ CheckCodeStub(pstub, MajorKey, MinorKey);
+ call(pstub, value_out);
+ break;
+ }
+ case FastCloneShallowArray: {
+ // class AllocationSiteModeBits: public BitField<AllocationSiteMode, 0, 1> {};
+ AllocationSiteMode allocation_site_mode = (AllocationSiteMode) (MinorKey & 0x01);
+ FastCloneShallowArrayStub stub(isolate, allocation_site_mode);
+ CodeStub* pstub = &stub;
+ CheckCodeStub(pstub, MajorKey, MinorKey);
+ call(pstub, value_out);
+ break;
+ }
+ case StoreArrayLiteralElement: {
+ StoreArrayLiteralElementStub stub(isolate);
+ CodeStub* pstub = &stub;
+ CheckCodeStub(pstub, MajorKey, MinorKey);
+ call(pstub, value_out);
+ break;
+ }
+ case CallFunction: {
+ // class FlagBits: public BitField<CallFunctionFlags, 0, 2> {};
+ CallFunctionFlags flags = (CallFunctionFlags) (MinorKey & 0x03);
+ // class ArgcBits : public BitField<unsigned, 2, Code::kArgumentsBits> {};
+ unsigned argc = MinorKey >> 2;
+ CallFunctionStub stub(isolate, argc, flags);
+ CodeStub* pstub = &stub;
+ CheckCodeStub(pstub, MajorKey, MinorKey);
+ call(pstub, value_out);
+ break;
+ }
+ case Instanceof: {
+ // int MinorKey() const { return static_cast<int>(flags_); }
+ InstanceofStub::Flags flags = (InstanceofStub::Flags) MinorKey;
+ InstanceofStub stub(isolate, flags);
+ CodeStub* pstub = &stub;
+ CheckCodeStub(pstub, MajorKey, MinorKey);
+ call(pstub, value_out);
+ break;
+ }
+ case NUMBER_OF_IDS:
+ UNREACHABLE();
+ case NoCache:
+ *value_out = NULL;
+ break;
+ default: {
+ fprintf(stderr, "unhandled MajorKey: %s (%d)\n", MajorName(MajorKey, false), MajorKey);
+ UNREACHABLE();
+ }
+ }
+}
+
+
+void CodeStub::GetCodeDispatchCall(CodeStub* stub, void** value_out) {
+ Handle<Code>* code_out = reinterpret_cast<Handle<Code>*>(value_out);
+ // Code stubs with special cache cannot be recreated from stub key.
+ *code_out = stub->UseSpecialCache() ? Handle<Code>() : stub->GetCode();
+}
+
+
+MaybeHandle<Code> CodeStub::GetCode(Isolate* isolate, uint32_t key) {
+ HandleScope scope(isolate);
+ Handle<Code> code;
+ void** value_out = reinterpret_cast<void**>(&code);
+ Dispatch(isolate, key, value_out, &GetCodeDispatchCall);
+ return scope.CloseAndEscape(code);
+}
+
+
// static
void BinaryOpICStub::GenerateAheadOfTime(Isolate* isolate) {
// Generate the uninitialized versions of the stub.
diff --git a/src/code-stubs.h b/src/code-stubs.h
index c1d051b..9cc12df 100644
--- node/deps/v8/src/code-stubs.h
+++ node/deps/v8/src/code-stubs.h
@@ -179,6 +179,8 @@ class CodeStub BASE_EMBEDDED {
// Lookup the code in the (possibly custom) cache.
bool FindCodeInCache(Code** code_out);
+ static MaybeHandle<Code> GetCode(Isolate* isolate, uint32_t key);
+
// Returns information for computing the number key.
virtual Major MajorKey() const = 0;
virtual int MinorKey() const = 0;
@@ -242,6 +244,14 @@ class CodeStub BASE_EMBEDDED {
// If a stub uses a special cache override this.
virtual bool UseSpecialCache() { return false; }
+ // We use this dispatch to statically instantiate the correct code stub for
+ // the given stub key and call the passed function with that code stub.
+ typedef void (*DispatchedCall)(CodeStub* stub, void** value_out);
+ static void Dispatch(Isolate* isolate, uint32_t key, void** value_out,
+ DispatchedCall call);
+
+ static void GetCodeDispatchCall(CodeStub* stub, void** value_out);
+
STATIC_ASSERT(NUMBER_OF_IDS < (1 << kStubMajorKeyBits));
class MajorKeyBits: public BitField<uint32_t, 0, kStubMajorKeyBits> {};
class MinorKeyBits: public BitField<uint32_t,

View File

@ -1,484 +0,0 @@
commit a49ac519c8df83c52ed67e3860c51ccad80e037a
Author: yangguo@chromium.org <yangguo@chromium.org>
Date: Wed Sep 17 12:50:17 2014 +0000
Serialize code stubs using stub key.
Also add some tracing to the code serializer.
R=mvstanton@chromium.org
Review URL: https://codereview.chromium.org/556243005
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24002 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 4208e62..792fda9 100644
--- node/deps/v8/src/flag-definitions.h
+++ node/deps/v8/src/flag-definitions.h
@@ -428,6 +428,7 @@ DEFINE_BOOL(trace_stub_failures, false,
"trace deoptimization of generated code stubs")
DEFINE_BOOL(serialize_toplevel, false, "enable caching of toplevel scripts")
+DEFINE_BOOL(trace_code_serializer, false, "trace code serializer")
// compiler.cc
DEFINE_INT(min_preparse_length, 1024,
diff --git a/src/serialize.cc b/src/serialize.cc
index 1a19ab0..9447fc8 100644
--- node/deps/v8/src/serialize.cc
+++ node/deps/v8/src/serialize.cc
@@ -8,6 +8,7 @@
#include "src/api.h"
#include "src/base/platform/platform.h"
#include "src/bootstrapper.h"
+#include "src/code-stubs.h"
#include "src/deoptimizer.h"
#include "src/execution.h"
#include "src/global-handles.h"
@@ -872,7 +873,7 @@ void Deserializer::ReadChunk(Object** current,
} else if (where == kAttachedReference) { \
DCHECK(deserializing_user_code()); \
int index = source_->GetInt(); \
- new_object = attached_objects_->at(index); \
+ new_object = *attached_objects_->at(index); \
emit_write_barrier = isolate->heap()->InNewSpace(new_object); \
} else { \
DCHECK(where == kBackrefWithSkip); \
@@ -1125,6 +1126,10 @@ void Deserializer::ReadChunk(Object** current,
// the current object.
CASE_STATEMENT(kAttachedReference, kPlain, kStartOfObject, 0)
CASE_BODY(kAttachedReference, kPlain, kStartOfObject, 0)
+ CASE_STATEMENT(kAttachedReference, kPlain, kInnerPointer, 0)
+ CASE_BODY(kAttachedReference, kPlain, kInnerPointer, 0)
+ CASE_STATEMENT(kAttachedReference, kFromCode, kInnerPointer, 0)
+ CASE_BODY(kAttachedReference, kFromCode, kInnerPointer, 0)
#undef CASE_STATEMENT
#undef CASE_BODY
@@ -1311,12 +1316,12 @@ int Serializer::RootIndex(HeapObject* heap_object, HowToCode from) {
// location into a later object. We can encode the location as an offset from
// the start of the deserialized objects or as an offset backwards from the
// current allocation pointer.
-void Serializer::SerializeReferenceToPreviousObject(
- int space,
- int address,
- HowToCode how_to_code,
- WhereToPoint where_to_point,
- int skip) {
+void Serializer::SerializeReferenceToPreviousObject(HeapObject* heap_object,
+ HowToCode how_to_code,
+ WhereToPoint where_to_point,
+ int skip) {
+ int space = SpaceOfObject(heap_object);
+ int address = address_mapper_.MappedTo(heap_object);
int offset = CurrentAllocationAddress(space) - address;
// Shift out the bits that are always 0.
offset >>= kObjectAlignmentBits;
@@ -1347,12 +1352,7 @@ void StartupSerializer::SerializeObject(
}
if (address_mapper_.IsMapped(heap_object)) {
- int space = SpaceOfObject(heap_object);
- int address = address_mapper_.MappedTo(heap_object);
- SerializeReferenceToPreviousObject(space,
- address,
- how_to_code,
- where_to_point,
+ SerializeReferenceToPreviousObject(heap_object, how_to_code, where_to_point,
skip);
} else {
if (skip != 0) {
@@ -1455,12 +1455,7 @@ void PartialSerializer::SerializeObject(
DCHECK(!heap_object->IsInternalizedString());
if (address_mapper_.IsMapped(heap_object)) {
- int space = SpaceOfObject(heap_object);
- int address = address_mapper_.MappedTo(heap_object);
- SerializeReferenceToPreviousObject(space,
- address,
- how_to_code,
- where_to_point,
+ SerializeReferenceToPreviousObject(heap_object, how_to_code, where_to_point,
skip);
} else {
if (skip != 0) {
@@ -1782,17 +1777,32 @@ void Serializer::InitializeCodeAddressMap() {
ScriptData* CodeSerializer::Serialize(Isolate* isolate,
Handle<SharedFunctionInfo> info,
Handle<String> source) {
+ base::ElapsedTimer timer;
+ if (FLAG_profile_deserialization) timer.Start();
+
// Serialize code object.
List<byte> payload;
ListSnapshotSink list_sink(&payload);
- CodeSerializer cs(isolate, &list_sink, *source);
+ DebugSnapshotSink debug_sink(&list_sink);
+ SnapshotByteSink* sink = FLAG_trace_code_serializer
+ ? static_cast<SnapshotByteSink*>(&debug_sink)
+ : static_cast<SnapshotByteSink*>(&list_sink);
+ CodeSerializer cs(isolate, sink, *source);
DisallowHeapAllocation no_gc;
Object** location = Handle<Object>::cast(info).location();
cs.VisitPointer(location);
cs.Pad();
SerializedCodeData data(&payload, &cs);
- return data.GetScriptData();
+ ScriptData* script_data = data.GetScriptData();
+
+ if (FLAG_profile_deserialization) {
+ double ms = timer.Elapsed().InMillisecondsF();
+ int length = script_data->length();
+ PrintF("[Serializing to %d bytes took %0.3f ms]\n", length, ms);
+ }
+
+ return script_data;
}
@@ -1813,16 +1823,13 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code,
return;
}
- // TODO(yangguo) wire up stubs from stub cache.
// TODO(yangguo) wire up global object.
// TODO(yangguo) We cannot deal with different hash seeds yet.
DCHECK(!heap_object->IsHashTable());
if (address_mapper_.IsMapped(heap_object)) {
- int space = SpaceOfObject(heap_object);
- int address = address_mapper_.MappedTo(heap_object);
- SerializeReferenceToPreviousObject(space, address, how_to_code,
- where_to_point, skip);
+ SerializeReferenceToPreviousObject(heap_object, how_to_code, where_to_point,
+ skip);
return;
}
@@ -1832,7 +1839,11 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code,
SerializeBuiltin(code_object, how_to_code, where_to_point, skip);
return;
}
- // TODO(yangguo) figure out whether other code kinds can be handled smarter.
+ if (code_object->IsCodeStubOrIC()) {
+ SerializeCodeStub(code_object, how_to_code, where_to_point, skip);
+ return;
+ }
+ code_object->ClearInlineCaches();
}
if (heap_object == source_) {
@@ -1840,6 +1851,14 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code,
return;
}
+ SerializeHeapObject(heap_object, how_to_code, where_to_point, skip);
+}
+
+
+void CodeSerializer::SerializeHeapObject(HeapObject* heap_object,
+ HowToCode how_to_code,
+ WhereToPoint where_to_point,
+ int skip) {
if (heap_object->IsScript()) {
// The wrapper cache uses a Foreign object to point to a global handle.
// However, the object visitor expects foreign objects to point to external
@@ -1851,6 +1870,13 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code,
sink_->Put(kSkip, "SkipFromSerializeObject");
sink_->PutInt(skip, "SkipDistanceFromSerializeObject");
}
+
+ if (FLAG_trace_code_serializer) {
+ PrintF("Encoding heap object: ");
+ heap_object->ShortPrint();
+ PrintF("\n");
+ }
+
// Object has not yet been serialized. Serialize it here.
ObjectSerializer serializer(this, heap_object, sink_, how_to_code,
where_to_point);
@@ -1870,11 +1896,62 @@ void CodeSerializer::SerializeBuiltin(Code* builtin, HowToCode how_to_code,
int builtin_index = builtin->builtin_index();
DCHECK_LT(builtin_index, Builtins::builtin_count);
DCHECK_LE(0, builtin_index);
+
+ if (FLAG_trace_code_serializer) {
+ PrintF("Encoding builtin: %s\n",
+ isolate()->builtins()->name(builtin_index));
+ }
+
sink_->Put(kBuiltin + how_to_code + where_to_point, "Builtin");
sink_->PutInt(builtin_index, "builtin_index");
}
+void CodeSerializer::SerializeCodeStub(Code* code, HowToCode how_to_code,
+ WhereToPoint where_to_point, int skip) {
+ DCHECK((how_to_code == kPlain && where_to_point == kStartOfObject) ||
+ (how_to_code == kPlain && where_to_point == kInnerPointer) ||
+ (how_to_code == kFromCode && where_to_point == kInnerPointer));
+ uint32_t stub_key = code->stub_key();
+
+ if (CodeStub::MajorKeyFromKey(stub_key) == CodeStub::NoCacheKey()) {
+ if (FLAG_trace_code_serializer) {
+ PrintF("Encoding uncacheable code stub as heap object\n");
+ }
+ SerializeHeapObject(code, how_to_code, where_to_point, skip);
+ return;
+ }
+
+ if (skip != 0) {
+ sink_->Put(kSkip, "SkipFromSerializeCodeStub");
+ sink_->PutInt(skip, "SkipDistanceFromSerializeCodeStub");
+ }
+
+ int index = AddCodeStubKey(stub_key) + kCodeStubsBaseIndex;
+
+ if (FLAG_trace_code_serializer) {
+ PrintF("Encoding code stub %s as %d\n",
+ CodeStub::MajorName(CodeStub::MajorKeyFromKey(stub_key), false),
+ index);
+ }
+
+ sink_->Put(kAttachedReference + how_to_code + where_to_point, "CodeStub");
+ sink_->PutInt(index, "CodeStub key");
+}
+
+
+int CodeSerializer::AddCodeStubKey(uint32_t stub_key) {
+ // TODO(yangguo) Maybe we need a hash table for a faster lookup than O(n^2).
+ int index = 0;
+ while (index < stub_keys_.length()) {
+ if (stub_keys_[index] == stub_key) return index;
+ index++;
+ }
+ stub_keys_.Add(stub_key);
+ return index;
+}
+
+
void CodeSerializer::SerializeSourceObject(HowToCode how_to_code,
WhereToPoint where_to_point,
int skip) {
@@ -1883,6 +1960,10 @@ void CodeSerializer::SerializeSourceObject(HowToCode how_to_code,
sink_->PutInt(skip, "SkipDistanceFromSerializeSourceObject");
}
+ if (FLAG_trace_code_serializer) {
+ PrintF("Encoding source object\n");
+ }
+
DCHECK(how_to_code == kPlain && where_to_point == kStartOfObject);
sink_->Put(kAttachedReference + how_to_code + where_to_point, "Source");
sink_->PutInt(kSourceObjectIndex, "kSourceObjectIndex");
@@ -1894,22 +1975,36 @@ Handle<SharedFunctionInfo> CodeSerializer::Deserialize(Isolate* isolate,
Handle<String> source) {
base::ElapsedTimer timer;
if (FLAG_profile_deserialization) timer.Start();
- SerializedCodeData scd(data, *source);
- SnapshotByteSource payload(scd.Payload(), scd.PayloadLength());
- Deserializer deserializer(&payload);
- STATIC_ASSERT(NEW_SPACE == 0);
- for (int i = NEW_SPACE; i <= PROPERTY_CELL_SPACE; i++) {
- deserializer.set_reservation(i, scd.GetReservation(i));
- }
-
- // Prepare and register list of attached objects.
- Vector<Object*> attached_objects = Vector<Object*>::New(1);
- attached_objects[kSourceObjectIndex] = *source;
- deserializer.SetAttachedObjects(&attached_objects);
Object* root;
- deserializer.DeserializePartial(isolate, &root);
- deserializer.FlushICacheForNewCodeObjects();
+
+ {
+ HandleScope scope(isolate);
+
+ SerializedCodeData scd(data, *source);
+ SnapshotByteSource payload(scd.Payload(), scd.PayloadLength());
+ Deserializer deserializer(&payload);
+ STATIC_ASSERT(NEW_SPACE == 0);
+ for (int i = NEW_SPACE; i <= PROPERTY_CELL_SPACE; i++) {
+ deserializer.set_reservation(i, scd.GetReservation(i));
+ }
+
+ // Prepare and register list of attached objects.
+ Vector<const uint32_t> code_stub_keys = scd.CodeStubKeys();
+ Vector<Handle<Object> > attached_objects = Vector<Handle<Object> >::New(
+ code_stub_keys.length() + kCodeStubsBaseIndex);
+ attached_objects[kSourceObjectIndex] = source;
+ for (int i = 0; i < code_stub_keys.length(); i++) {
+ attached_objects[i + kCodeStubsBaseIndex] =
+ CodeStub::GetCode(isolate, code_stub_keys[i]).ToHandleChecked();
+ }
+ deserializer.SetAttachedObjects(&attached_objects);
+
+ // Deserialize.
+ deserializer.DeserializePartial(isolate, &root);
+ deserializer.FlushICacheForNewCodeObjects();
+ }
+
if (FLAG_profile_deserialization) {
double ms = timer.Elapsed().InMillisecondsF();
int length = data->length();
@@ -1922,18 +2017,35 @@ Handle<SharedFunctionInfo> CodeSerializer::Deserialize(Isolate* isolate,
SerializedCodeData::SerializedCodeData(List<byte>* payload, CodeSerializer* cs)
: owns_script_data_(true) {
DisallowHeapAllocation no_gc;
- int data_length = payload->length() + kHeaderEntries * kIntSize;
+ List<uint32_t>* stub_keys = cs->stub_keys();
+
+ // Calculate sizes.
+ int num_stub_keys = stub_keys->length();
+ int stub_keys_size = stub_keys->length() * kInt32Size;
+ int data_length = kHeaderSize + stub_keys_size + payload->length();
+
+ // Allocate backing store and create result data.
byte* data = NewArray<byte>(data_length);
DCHECK(IsAligned(reinterpret_cast<intptr_t>(data), kPointerAlignment));
- CopyBytes(data + kHeaderEntries * kIntSize, payload->begin(),
- static_cast<size_t>(payload->length()));
script_data_ = new ScriptData(data, data_length);
script_data_->AcquireDataOwnership();
+
+ // Set header values.
SetHeaderValue(kCheckSumOffset, CheckSum(cs->source()));
+ SetHeaderValue(kNumCodeStubKeysOffset, num_stub_keys);
+ SetHeaderValue(kPayloadLengthOffset, payload->length());
STATIC_ASSERT(NEW_SPACE == 0);
for (int i = NEW_SPACE; i <= PROPERTY_CELL_SPACE; i++) {
SetHeaderValue(kReservationsOffset + i, cs->CurrentAllocationAddress(i));
}
+
+ // Copy code stub keys.
+ CopyBytes(data + kHeaderSize, reinterpret_cast<byte*>(stub_keys->begin()),
+ stub_keys_size);
+
+ // Copy serialized data.
+ CopyBytes(data + kHeaderSize + stub_keys_size, payload->begin(),
+ static_cast<size_t>(payload->length()));
}
diff --git a/src/serialize.h b/src/serialize.h
index 066d75f..71b274b 100644
--- node/deps/v8/src/serialize.h
+++ node/deps/v8/src/serialize.h
@@ -257,7 +257,7 @@ class Deserializer: public SerializerDeserializer {
// Serialized user code reference certain objects that are provided in a list
// By calling this method, we assume that we are deserializing user code.
- void SetAttachedObjects(Vector<Object*>* attached_objects) {
+ void SetAttachedObjects(Vector<Handle<Object> >* attached_objects) {
attached_objects_ = attached_objects;
}
@@ -308,7 +308,7 @@ class Deserializer: public SerializerDeserializer {
Isolate* isolate_;
// Objects from the attached object descriptions in the serialized user code.
- Vector<Object*>* attached_objects_;
+ Vector<Handle<Object> >* attached_objects_;
SnapshotByteSource* source_;
// This is the address of the next object that will be allocated in each
@@ -459,12 +459,10 @@ class Serializer : public SerializerDeserializer {
HowToCode how_to_code,
WhereToPoint where_to_point,
int skip) = 0;
- void SerializeReferenceToPreviousObject(
- int space,
- int address,
- HowToCode how_to_code,
- WhereToPoint where_to_point,
- int skip);
+ void SerializeReferenceToPreviousObject(HeapObject* heap_object,
+ HowToCode how_to_code,
+ WhereToPoint where_to_point,
+ int skip);
void InitializeAllocators();
// This will return the space for an object.
static int SpaceOfObject(HeapObject* object);
@@ -594,20 +592,29 @@ class CodeSerializer : public Serializer {
Handle<String> source);
static const int kSourceObjectIndex = 0;
+ static const int kCodeStubsBaseIndex = 1;
String* source() {
DCHECK(!AllowHeapAllocation::IsAllowed());
return source_;
}
+ List<uint32_t>* stub_keys() { return &stub_keys_; }
+
private:
void SerializeBuiltin(Code* builtin, HowToCode how_to_code,
WhereToPoint where_to_point, int skip);
+ void SerializeCodeStub(Code* code, HowToCode how_to_code,
+ WhereToPoint where_to_point, int skip);
void SerializeSourceObject(HowToCode how_to_code, WhereToPoint where_to_point,
int skip);
+ void SerializeHeapObject(HeapObject* heap_object, HowToCode how_to_code,
+ WhereToPoint where_to_point, int skip);
+ int AddCodeStubKey(uint32_t stub_key);
DisallowHeapAllocation no_gc_;
String* source_;
+ List<uint32_t> stub_keys_;
DISALLOW_COPY_AND_ASSIGN(CodeSerializer);
};
@@ -638,12 +645,22 @@ class SerializedCodeData {
return result;
}
+ Vector<const uint32_t> CodeStubKeys() const {
+ return Vector<const uint32_t>(
+ reinterpret_cast<const uint32_t*>(script_data_->data() + kHeaderSize),
+ GetHeaderValue(kNumCodeStubKeysOffset));
+ }
+
const byte* Payload() const {
- return script_data_->data() + kHeaderEntries * kIntSize;
+ int code_stubs_size = GetHeaderValue(kNumCodeStubKeysOffset) * kInt32Size;
+ return script_data_->data() + kHeaderSize + code_stubs_size;
}
int PayloadLength() const {
- return script_data_->length() - kHeaderEntries * kIntSize;
+ int payload_length = GetHeaderValue(kPayloadLengthOffset);
+ DCHECK_EQ(script_data_->data() + script_data_->length(),
+ Payload() + payload_length);
+ return payload_length;
}
int GetReservation(int space) const {
@@ -666,10 +683,21 @@ class SerializedCodeData {
// The data header consists of int-sized entries:
// [0] version hash
- // [1..7] reservation sizes for spaces from NEW_SPACE to PROPERTY_CELL_SPACE.
+ // [1] number of code stub keys
+ // [2] payload length
+ // [3..9] reservation sizes for spaces from NEW_SPACE to PROPERTY_CELL_SPACE.
static const int kCheckSumOffset = 0;
- static const int kReservationsOffset = 1;
- static const int kHeaderEntries = 8;
+ static const int kNumCodeStubKeysOffset = 1;
+ static const int kPayloadLengthOffset = 2;
+ static const int kReservationsOffset = 3;
+
+ static const int kNumSpaces = PROPERTY_CELL_SPACE - NEW_SPACE + 1;
+ static const int kHeaderEntries = kReservationsOffset + kNumSpaces;
+ static const int kHeaderSize = kHeaderEntries * kIntSize;
+
+ // Following the header, we store, in sequential order
+ // - code stub keys
+ // - serialization payload
ScriptData* script_data_;
bool owns_script_data_;

View File

@ -1,739 +0,0 @@
commit 1257f35c21c9aeb054ae57a0087c50d91f625c24
Author: yangguo@chromium.org <yangguo@chromium.org>
Date: Thu Sep 25 07:32:13 2014 +0000
Support large objects in the serializer/deserializer.
R=hpayer@chromium.org, mvstanton@chromium.org
Review URL: https://codereview.chromium.org/581223004
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24204 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/heap/heap.cc b/src/heap/heap.cc
index 3d0c2f0..78c45b0 100644
--- node/deps/v8/src/heap/heap.cc
+++ node/deps/v8/src/heap/heap.cc
@@ -923,9 +923,12 @@ void Heap::ReserveSpace(int* sizes, Address* locations_out) {
static const int kThreshold = 20;
while (gc_performed && counter++ < kThreshold) {
gc_performed = false;
- DCHECK(NEW_SPACE == FIRST_PAGED_SPACE - 1);
- for (int space = NEW_SPACE; space <= LAST_PAGED_SPACE; space++) {
- if (sizes[space] != 0) {
+ for (int space = NEW_SPACE; space < Serializer::kNumberOfSpaces; space++) {
+ if (sizes[space] == 0) continue;
+ bool perform_gc = false;
+ if (space == LO_SPACE) {
+ perform_gc = !lo_space()->CanAllocateSize(sizes[space]);
+ } else {
AllocationResult allocation;
if (space == NEW_SPACE) {
allocation = new_space()->AllocateRaw(sizes[space]);
@@ -933,23 +936,27 @@ void Heap::ReserveSpace(int* sizes, Address* locations_out) {
allocation = paged_space(space)->AllocateRaw(sizes[space]);
}
FreeListNode* node;
- if (!allocation.To(&node)) {
- if (space == NEW_SPACE) {
- Heap::CollectGarbage(NEW_SPACE,
- "failed to reserve space in the new space");
- } else {
- AbortIncrementalMarkingAndCollectGarbage(
- this, static_cast<AllocationSpace>(space),
- "failed to reserve space in paged space");
- }
- gc_performed = true;
- break;
- } else {
+ if (allocation.To(&node)) {
// Mark with a free list node, in case we have a GC before
// deserializing.
node->set_size(this, sizes[space]);
+ DCHECK(space < Serializer::kNumberOfPreallocatedSpaces);
locations_out[space] = node->address();
+ } else {
+ perform_gc = true;
+ }
+ }
+ if (perform_gc) {
+ if (space == NEW_SPACE) {
+ Heap::CollectGarbage(NEW_SPACE,
+ "failed to reserve space in the new space");
+ } else {
+ AbortIncrementalMarkingAndCollectGarbage(
+ this, static_cast<AllocationSpace>(space),
+ "failed to reserve space in paged or large object space");
}
+ gc_performed = true;
+ break; // Abort for-loop over spaces and retry.
}
}
}
diff --git a/src/heap/heap.h b/src/heap/heap.h
index 956b859..87b939a 100644
--- node/deps/v8/src/heap/heap.h
+++ node/deps/v8/src/heap/heap.h
@@ -2021,6 +2021,7 @@ class Heap {
int gc_callbacks_depth_;
friend class AlwaysAllocateScope;
+ friend class Deserializer;
friend class Factory;
friend class GCCallbacksScope;
friend class GCTracer;
diff --git a/src/heap/spaces.cc b/src/heap/spaces.cc
index f8d340f..ae4048f 100644
--- node/deps/v8/src/heap/spaces.cc
+++ node/deps/v8/src/heap/spaces.cc
@@ -2840,9 +2840,7 @@ AllocationResult LargeObjectSpace::AllocateRaw(int object_size,
return AllocationResult::Retry(identity());
}
- if (Size() + object_size > max_capacity_) {
- return AllocationResult::Retry(identity());
- }
+ if (!CanAllocateSize(object_size)) return AllocationResult::Retry(identity());
LargePage* page = heap()->isolate()->memory_allocator()->AllocateLargePage(
object_size, this, executable);
diff --git a/src/heap/spaces.h b/src/heap/spaces.h
index 9ecb3c4..1a89449 100644
--- node/deps/v8/src/heap/spaces.h
+++ node/deps/v8/src/heap/spaces.h
@@ -2728,6 +2728,8 @@ class LargeObjectSpace : public Space {
MUST_USE_RESULT AllocationResult
AllocateRaw(int object_size, Executability executable);
+ bool CanAllocateSize(int size) { return Size() + size <= max_capacity_; }
+
// Available bytes for objects in this space.
inline intptr_t Available();
diff --git a/src/mksnapshot.cc b/src/mksnapshot.cc
index b4a4018..eacd098 100644
--- node/deps/v8/src/mksnapshot.cc
+++ node/deps/v8/src/mksnapshot.cc
@@ -84,10 +84,10 @@ class SnapshotWriter {
i::List<i::byte> startup_blob;
i::ListSnapshotSink sink(&startup_blob);
- int spaces[] = {
- i::NEW_SPACE, i::OLD_POINTER_SPACE, i::OLD_DATA_SPACE, i::CODE_SPACE,
- i::MAP_SPACE, i::CELL_SPACE, i::PROPERTY_CELL_SPACE
- };
+ int spaces[] = {i::NEW_SPACE, i::OLD_POINTER_SPACE,
+ i::OLD_DATA_SPACE, i::CODE_SPACE,
+ i::MAP_SPACE, i::CELL_SPACE,
+ i::PROPERTY_CELL_SPACE, i::LO_SPACE};
i::byte* snapshot_bytes = snapshot_data.begin();
sink.PutBlob(snapshot_bytes, snapshot_data.length(), "snapshot");
@@ -197,6 +197,7 @@ class SnapshotWriter {
WriteSizeVar(ser, prefix, "map", i::MAP_SPACE);
WriteSizeVar(ser, prefix, "cell", i::CELL_SPACE);
WriteSizeVar(ser, prefix, "property_cell", i::PROPERTY_CELL_SPACE);
+ WriteSizeVar(ser, prefix, "lo", i::LO_SPACE);
fprintf(fp_, "\n");
}
diff --git a/src/serialize.cc b/src/serialize.cc
index 843f976..894a1be 100644
--- node/deps/v8/src/serialize.cc
+++ node/deps/v8/src/serialize.cc
@@ -596,8 +596,9 @@ Deserializer::Deserializer(SnapshotByteSource* source)
: isolate_(NULL),
attached_objects_(NULL),
source_(source),
- external_reference_decoder_(NULL) {
- for (int i = 0; i < LAST_SPACE + 1; i++) {
+ external_reference_decoder_(NULL),
+ deserialized_large_objects_(0) {
+ for (int i = 0; i < kNumberOfSpaces; i++) {
reservations_[i] = kUninitializedReservation;
}
}
@@ -615,7 +616,7 @@ void Deserializer::FlushICacheForNewCodeObjects() {
void Deserializer::Deserialize(Isolate* isolate) {
isolate_ = isolate;
DCHECK(isolate_ != NULL);
- isolate_->heap()->ReserveSpace(reservations_, &high_water_[0]);
+ isolate_->heap()->ReserveSpace(reservations_, high_water_);
// No active threads.
DCHECK_EQ(NULL, isolate_->thread_manager()->FirstThreadStateInUse());
// No active handles.
@@ -662,7 +663,8 @@ void Deserializer::DeserializePartial(Isolate* isolate, Object** root) {
for (int i = NEW_SPACE; i < kNumberOfSpaces; i++) {
DCHECK(reservations_[i] != kUninitializedReservation);
}
- isolate_->heap()->ReserveSpace(reservations_, &high_water_[0]);
+ Heap* heap = isolate->heap();
+ heap->ReserveSpace(reservations_, high_water_);
if (external_reference_decoder_ == NULL) {
external_reference_decoder_ = new ExternalReferenceDecoder(isolate);
}
@@ -798,11 +800,40 @@ void Deserializer::ReadObject(int space_number,
*write_back = obj;
#ifdef DEBUG
- bool is_codespace = (space_number == CODE_SPACE);
- DCHECK(obj->IsCode() == is_codespace);
+ if (obj->IsCode()) {
+ DCHECK(space_number == CODE_SPACE || space_number == LO_SPACE);
+ } else {
+ DCHECK(space_number != CODE_SPACE);
+ }
#endif
}
+
+// We know the space requirements before deserialization and can
+// pre-allocate that reserved space. During deserialization, all we need
+// to do is to bump up the pointer for each space in the reserved
+// space. This is also used for fixing back references.
+// Since multiple large objects cannot be folded into one large object
+// space allocation, we have to do an actual allocation when deserializing
+// each large object. Instead of tracking offset for back references, we
+// reference large objects by index.
+Address Deserializer::Allocate(int space_index, int size) {
+ if (space_index == LO_SPACE) {
+ AlwaysAllocateScope scope(isolate_);
+ LargeObjectSpace* lo_space = isolate_->heap()->lo_space();
+ Executability exec = static_cast<Executability>(source_->GetInt());
+ AllocationResult result = lo_space->AllocateRaw(size, exec);
+ HeapObject* obj = HeapObject::cast(result.ToObjectChecked());
+ deserialized_large_objects_.Add(obj);
+ return obj->address();
+ } else {
+ DCHECK(space_index < kNumberOfPreallocatedSpaces);
+ Address address = high_water_[space_index];
+ high_water_[space_index] = address + size;
+ return address;
+ }
+}
+
void Deserializer::ReadChunk(Object** current,
Object** limit,
int source_space,
@@ -925,15 +956,16 @@ void Deserializer::ReadChunk(Object** current,
// This generates a case and a body for the new space (which has to do extra
// write barrier handling) and handles the other spaces with 8 fall-through
// cases and one body.
-#define ALL_SPACES(where, how, within) \
- CASE_STATEMENT(where, how, within, NEW_SPACE) \
- CASE_BODY(where, how, within, NEW_SPACE) \
- CASE_STATEMENT(where, how, within, OLD_DATA_SPACE) \
- CASE_STATEMENT(where, how, within, OLD_POINTER_SPACE) \
- CASE_STATEMENT(where, how, within, CODE_SPACE) \
- CASE_STATEMENT(where, how, within, CELL_SPACE) \
- CASE_STATEMENT(where, how, within, PROPERTY_CELL_SPACE) \
- CASE_STATEMENT(where, how, within, MAP_SPACE) \
+#define ALL_SPACES(where, how, within) \
+ CASE_STATEMENT(where, how, within, NEW_SPACE) \
+ CASE_BODY(where, how, within, NEW_SPACE) \
+ CASE_STATEMENT(where, how, within, OLD_DATA_SPACE) \
+ CASE_STATEMENT(where, how, within, OLD_POINTER_SPACE) \
+ CASE_STATEMENT(where, how, within, CODE_SPACE) \
+ CASE_STATEMENT(where, how, within, MAP_SPACE) \
+ CASE_STATEMENT(where, how, within, CELL_SPACE) \
+ CASE_STATEMENT(where, how, within, PROPERTY_CELL_SPACE) \
+ CASE_STATEMENT(where, how, within, LO_SPACE) \
CASE_BODY(where, how, within, kAnyOldSpace)
#define FOUR_CASES(byte_code) \
@@ -1184,12 +1216,11 @@ Serializer::Serializer(Isolate* isolate, SnapshotByteSink* sink)
sink_(sink),
external_reference_encoder_(new ExternalReferenceEncoder(isolate)),
root_index_wave_front_(0),
- code_address_map_(NULL) {
+ code_address_map_(NULL),
+ seen_large_objects_index_(0) {
// The serializer is meant to be used only to generate initial heap images
// from a context in which there is only one isolate.
- for (int i = 0; i <= LAST_SPACE; i++) {
- fullness_[i] = 0;
- }
+ for (int i = 0; i < kNumberOfSpaces; i++) fullness_[i] = 0;
}
@@ -1324,10 +1355,7 @@ void Serializer::SerializeReferenceToPreviousObject(HeapObject* heap_object,
WhereToPoint where_to_point,
int skip) {
int space = SpaceOfObject(heap_object);
- int address = address_mapper_.MappedTo(heap_object);
- int offset = CurrentAllocationAddress(space) - address;
- // Shift out the bits that are always 0.
- offset >>= kObjectAlignmentBits;
+
if (skip == 0) {
sink_->Put(kBackref + how_to_code + where_to_point + space, "BackRefSer");
} else {
@@ -1335,7 +1363,17 @@ void Serializer::SerializeReferenceToPreviousObject(HeapObject* heap_object,
"BackRefSerWithSkip");
sink_->PutInt(skip, "BackRefSkipDistance");
}
- sink_->PutInt(offset, "offset");
+
+ if (space == LO_SPACE) {
+ int index = address_mapper_.MappedTo(heap_object);
+ sink_->PutInt(index, "large object index");
+ } else {
+ int address = address_mapper_.MappedTo(heap_object);
+ int offset = CurrentAllocationAddress(space) - address;
+ // Shift out the bits that are always 0.
+ offset >>= kObjectAlignmentBits;
+ sink_->PutInt(offset, "offset");
+ }
}
@@ -1494,8 +1532,18 @@ void Serializer::ObjectSerializer::Serialize() {
}
// Mark this object as already serialized.
- int offset = serializer_->Allocate(space, size);
- serializer_->address_mapper()->AddMapping(object_, offset);
+ if (space == LO_SPACE) {
+ if (object_->IsCode()) {
+ sink_->PutInt(EXECUTABLE, "executable large object");
+ } else {
+ sink_->PutInt(NOT_EXECUTABLE, "not executable large object");
+ }
+ int index = serializer_->AllocateLargeObject(size);
+ serializer_->address_mapper()->AddMapping(object_, index);
+ } else {
+ int offset = serializer_->Allocate(space, size);
+ serializer_->address_mapper()->AddMapping(object_, offset);
+ }
// Serialize the map (first word of the object).
serializer_->SerializeObject(object_->map(), kPlain, kStartOfObject, 0);
@@ -1747,8 +1795,14 @@ int Serializer::SpaceOfObject(HeapObject* object) {
}
+int Serializer::AllocateLargeObject(int size) {
+ fullness_[LO_SPACE] += size;
+ return seen_large_objects_index_++;
+}
+
+
int Serializer::Allocate(int space, int size) {
- CHECK(space >= 0 && space < kNumberOfSpaces);
+ CHECK(space >= 0 && space < kNumberOfPreallocatedSpaces);
int allocation_address = fullness_[space];
fullness_[space] = allocation_address + size;
return allocation_address;
@@ -1840,11 +1894,11 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code,
if (heap_object->IsCode()) {
Code* code_object = Code::cast(heap_object);
+ DCHECK(!code_object->is_optimized_code());
if (code_object->kind() == Code::BUILTIN) {
SerializeBuiltin(code_object, how_to_code, where_to_point, skip);
return;
- }
- if (code_object->IsCodeStubOrIC()) {
+ } else if (code_object->IsCodeStubOrIC()) {
SerializeCodeStub(code_object, how_to_code, where_to_point, skip);
return;
}
@@ -1991,7 +2045,7 @@ Handle<SharedFunctionInfo> CodeSerializer::Deserialize(Isolate* isolate,
SnapshotByteSource payload(scd.Payload(), scd.PayloadLength());
Deserializer deserializer(&payload);
STATIC_ASSERT(NEW_SPACE == 0);
- for (int i = NEW_SPACE; i <= PROPERTY_CELL_SPACE; i++) {
+ for (int i = NEW_SPACE; i < kNumberOfSpaces; i++) {
deserializer.set_reservation(i, scd.GetReservation(i));
}
@@ -2041,7 +2095,7 @@ SerializedCodeData::SerializedCodeData(List<byte>* payload, CodeSerializer* cs)
SetHeaderValue(kNumCodeStubKeysOffset, num_stub_keys);
SetHeaderValue(kPayloadLengthOffset, payload->length());
STATIC_ASSERT(NEW_SPACE == 0);
- for (int i = NEW_SPACE; i <= PROPERTY_CELL_SPACE; i++) {
+ for (int i = 0; i < SerializerDeserializer::kNumberOfSpaces; i++) {
SetHeaderValue(kReservationsOffset + i, cs->CurrentAllocationAddress(i));
}
diff --git a/src/serialize.h b/src/serialize.h
index 71b274b..7831536 100644
--- node/deps/v8/src/serialize.h
+++ node/deps/v8/src/serialize.h
@@ -148,11 +148,15 @@ class SerializerDeserializer: public ObjectVisitor {
static int nop() { return kNop; }
+ // No reservation for large object space necessary.
+ static const int kNumberOfPreallocatedSpaces = LO_SPACE;
+ static const int kNumberOfSpaces = INVALID_SPACE;
+
protected:
// Where the pointed-to object can be found:
enum Where {
kNewObject = 0, // Object is next in snapshot.
- // 1-6 One per space.
+ // 1-7 One per space.
kRootArray = 0x9, // Object is found in root array.
kPartialSnapshotCache = 0xa, // Object is in the cache.
kExternalReference = 0xb, // Pointer to an external reference.
@@ -161,9 +165,9 @@ class SerializerDeserializer: public ObjectVisitor {
kAttachedReference = 0xe, // Object is described in an attached list.
kNop = 0xf, // Does nothing, used to pad.
kBackref = 0x10, // Object is described relative to end.
- // 0x11-0x16 One per space.
+ // 0x11-0x17 One per space.
kBackrefWithSkip = 0x18, // Object is described relative to end.
- // 0x19-0x1e One per space.
+ // 0x19-0x1f One per space.
// 0x20-0x3f Used by misc. tags below.
kPointedToMask = 0x3f
};
@@ -225,11 +229,11 @@ class SerializerDeserializer: public ObjectVisitor {
return byte_code & 0x1f;
}
- static const int kNumberOfSpaces = LO_SPACE;
static const int kAnyOldSpace = -1;
// A bitmask for getting the space out of an instruction.
static const int kSpaceMask = 7;
+ STATIC_ASSERT(kNumberOfSpaces <= kSpaceMask + 1);
};
@@ -249,7 +253,7 @@ class Deserializer: public SerializerDeserializer {
void set_reservation(int space_number, int reservation) {
DCHECK(space_number >= 0);
- DCHECK(space_number <= LAST_SPACE);
+ DCHECK(space_number < kNumberOfSpaces);
reservations_[space_number] = reservation;
}
@@ -282,24 +286,18 @@ class Deserializer: public SerializerDeserializer {
void ReadChunk(
Object** start, Object** end, int space, Address object_address);
void ReadObject(int space_number, Object** write_back);
+ Address Allocate(int space_index, int size);
// Special handling for serialized code like hooking up internalized strings.
HeapObject* ProcessNewObjectFromSerializedCode(HeapObject* obj);
Object* ProcessBackRefInSerializedCode(Object* obj);
- // This routine both allocates a new object, and also keeps
- // track of where objects have been allocated so that we can
- // fix back references when deserializing.
- Address Allocate(int space_index, int size) {
- Address address = high_water_[space_index];
- high_water_[space_index] = address + size;
- return address;
- }
-
// This returns the address of an object that has been described in the
// snapshot as being offset bytes back in a particular space.
HeapObject* GetAddressFromEnd(int space) {
int offset = source_->GetInt();
+ if (space == LO_SPACE) return deserialized_large_objects_[offset];
+ DCHECK(space < kNumberOfPreallocatedSpaces);
offset <<= kObjectAlignmentBits;
return HeapObject::FromAddress(high_water_[space] - offset);
}
@@ -313,13 +311,15 @@ class Deserializer: public SerializerDeserializer {
SnapshotByteSource* source_;
// This is the address of the next object that will be allocated in each
// space. It is used to calculate the addresses of back-references.
- Address high_water_[LAST_SPACE + 1];
+ Address high_water_[kNumberOfPreallocatedSpaces];
- int reservations_[LAST_SPACE + 1];
+ int reservations_[kNumberOfSpaces];
static const intptr_t kUninitializedReservation = -1;
ExternalReferenceDecoder* external_reference_decoder_;
+ List<HeapObject*> deserialized_large_objects_;
+
DISALLOW_COPY_AND_ASSIGN(Deserializer);
};
@@ -466,6 +466,7 @@ class Serializer : public SerializerDeserializer {
void InitializeAllocators();
// This will return the space for an object.
static int SpaceOfObject(HeapObject* object);
+ int AllocateLargeObject(int size);
int Allocate(int space, int size);
int EncodeExternalReference(Address addr) {
return external_reference_encoder_->Encode(addr);
@@ -480,7 +481,7 @@ class Serializer : public SerializerDeserializer {
Isolate* isolate_;
// Keep track of the fullness of each space in order to generate
// relative addresses for back references.
- int fullness_[LAST_SPACE + 1];
+ int fullness_[kNumberOfSpaces];
SnapshotByteSink* sink_;
ExternalReferenceEncoder* external_reference_encoder_;
@@ -497,6 +498,8 @@ class Serializer : public SerializerDeserializer {
private:
CodeAddressMap* code_address_map_;
+ // We map serialized large objects to indexes for back-referencing.
+ int seen_large_objects_index_;
DISALLOW_COPY_AND_ASSIGN(Serializer);
};
@@ -691,8 +694,8 @@ class SerializedCodeData {
static const int kPayloadLengthOffset = 2;
static const int kReservationsOffset = 3;
- static const int kNumSpaces = PROPERTY_CELL_SPACE - NEW_SPACE + 1;
- static const int kHeaderEntries = kReservationsOffset + kNumSpaces;
+ static const int kHeaderEntries =
+ kReservationsOffset + SerializerDeserializer::kNumberOfSpaces;
static const int kHeaderSize = kHeaderEntries * kIntSize;
// Following the header, we store, in sequential order
diff --git a/src/snapshot-common.cc b/src/snapshot-common.cc
index a2d5213..4e90ce1 100644
--- node/deps/v8/src/snapshot-common.cc
+++ node/deps/v8/src/snapshot-common.cc
@@ -21,8 +21,8 @@ void Snapshot::ReserveSpaceForLinkedInSnapshot(Deserializer* deserializer) {
deserializer->set_reservation(CODE_SPACE, code_space_used_);
deserializer->set_reservation(MAP_SPACE, map_space_used_);
deserializer->set_reservation(CELL_SPACE, cell_space_used_);
- deserializer->set_reservation(PROPERTY_CELL_SPACE,
- property_cell_space_used_);
+ deserializer->set_reservation(PROPERTY_CELL_SPACE, property_cell_space_used_);
+ deserializer->set_reservation(LO_SPACE, lo_space_used_);
}
@@ -67,6 +67,7 @@ Handle<Context> Snapshot::NewContextFromSnapshot(Isolate* isolate) {
deserializer.set_reservation(CELL_SPACE, context_cell_space_used_);
deserializer.set_reservation(PROPERTY_CELL_SPACE,
context_property_cell_space_used_);
+ deserializer.set_reservation(LO_SPACE, context_lo_space_used_);
deserializer.DeserializePartial(isolate, &root);
CHECK(root->IsContext());
return Handle<Context>(Context::cast(root));
diff --git a/src/snapshot-empty.cc b/src/snapshot-empty.cc
index 65207bf..e8673e5 100644
--- node/deps/v8/src/snapshot-empty.cc
+++ node/deps/v8/src/snapshot-empty.cc
@@ -27,6 +27,7 @@ const int Snapshot::code_space_used_ = 0;
const int Snapshot::map_space_used_ = 0;
const int Snapshot::cell_space_used_ = 0;
const int Snapshot::property_cell_space_used_ = 0;
+const int Snapshot::lo_space_used_ = 0;
const int Snapshot::context_new_space_used_ = 0;
const int Snapshot::context_pointer_space_used_ = 0;
@@ -35,5 +36,5 @@ const int Snapshot::context_code_space_used_ = 0;
const int Snapshot::context_map_space_used_ = 0;
const int Snapshot::context_cell_space_used_ = 0;
const int Snapshot::context_property_cell_space_used_ = 0;
-
+const int Snapshot::context_lo_space_used_ = 0;
} } // namespace v8::internal
diff --git a/src/snapshot-external.cc b/src/snapshot-external.cc
index ee1a8f4..9b8bc1b 100644
--- node/deps/v8/src/snapshot-external.cc
+++ node/deps/v8/src/snapshot-external.cc
@@ -25,6 +25,7 @@ struct SnapshotImpl {
int map_space_used;
int cell_space_used;
int property_cell_space_used;
+ int lo_space_used;
const byte* context_data;
int context_size;
@@ -35,6 +36,7 @@ struct SnapshotImpl {
int context_map_space_used;
int context_cell_space_used;
int context_property_cell_space_used;
+ int context_lo_space_used;
};
@@ -66,6 +68,7 @@ bool Snapshot::Initialize(Isolate* isolate) {
deserializer.set_reservation(CELL_SPACE, snapshot_impl_->cell_space_used);
deserializer.set_reservation(PROPERTY_CELL_SPACE,
snapshot_impl_->property_cell_space_used);
+ deserializer.set_reservation(LO_SPACE, snapshot_impl_->lo_space_used);
bool success = V8::Initialize(&deserializer);
if (FLAG_profile_deserialization) {
double ms = timer.Elapsed().InMillisecondsF();
@@ -97,6 +100,7 @@ Handle<Context> Snapshot::NewContextFromSnapshot(Isolate* isolate) {
deserializer.set_reservation(PROPERTY_CELL_SPACE,
snapshot_impl_->
context_property_cell_space_used);
+ deserializer.set_reservation(LO_SPACE, snapshot_impl_->context_lo_space_used);
Object* root;
deserializer.DeserializePartial(isolate, &root);
CHECK(root->IsContext());
@@ -123,6 +127,7 @@ void SetSnapshotFromFile(StartupData* snapshot_blob) {
snapshot_impl_->map_space_used = source.GetInt();
snapshot_impl_->cell_space_used = source.GetInt();
snapshot_impl_->property_cell_space_used = source.GetInt();
+ snapshot_impl_->lo_space_used = source.GetInt();
success &= source.GetBlob(&snapshot_impl_->context_data,
&snapshot_impl_->context_size);
diff --git a/src/snapshot-source-sink.cc b/src/snapshot-source-sink.cc
index 44f8706..29bad33 100644
--- node/deps/v8/src/snapshot-source-sink.cc
+++ node/deps/v8/src/snapshot-source-sink.cc
@@ -39,15 +39,17 @@ void SnapshotByteSource::CopyRaw(byte* to, int number_of_bytes) {
void SnapshotByteSink::PutInt(uintptr_t integer, const char* description) {
- DCHECK(integer < 1 << 22);
+ DCHECK(integer < 1 << 30);
integer <<= 2;
int bytes = 1;
if (integer > 0xff) bytes = 2;
if (integer > 0xffff) bytes = 3;
- integer |= bytes;
+ if (integer > 0xffffff) bytes = 4;
+ integer |= (bytes - 1);
Put(static_cast<int>(integer & 0xff), "IntPart1");
if (bytes > 1) Put(static_cast<int>((integer >> 8) & 0xff), "IntPart2");
if (bytes > 2) Put(static_cast<int>((integer >> 16) & 0xff), "IntPart3");
+ if (bytes > 3) Put(static_cast<int>((integer >> 24) & 0xff), "IntPart4");
}
void SnapshotByteSink::PutRaw(byte* data, int number_of_bytes,
diff --git a/src/snapshot-source-sink.h b/src/snapshot-source-sink.h
index 3c64bca..c1a31b5 100644
--- node/deps/v8/src/snapshot-source-sink.h
+++ node/deps/v8/src/snapshot-source-sink.h
@@ -39,7 +39,7 @@ class SnapshotByteSource FINAL {
// This way of variable-length encoding integers does not suffer from branch
// mispredictions.
uint32_t answer = GetUnalignedInt();
- int bytes = answer & 3;
+ int bytes = (answer & 3) + 1;
Advance(bytes);
uint32_t mask = 0xffffffffu;
mask >>= 32 - (bytes << 3);
diff --git a/src/snapshot.h b/src/snapshot.h
index 3d752a7..590ecf1 100644
--- node/deps/v8/src/snapshot.h
+++ node/deps/v8/src/snapshot.h
@@ -48,6 +48,7 @@ class Snapshot {
static const int map_space_used_;
static const int cell_space_used_;
static const int property_cell_space_used_;
+ static const int lo_space_used_;
static const int context_new_space_used_;
static const int context_pointer_space_used_;
static const int context_data_space_used_;
@@ -55,6 +56,7 @@ class Snapshot {
static const int context_map_space_used_;
static const int context_cell_space_used_;
static const int context_property_cell_space_used_;
+ static const int context_lo_space_used_;
static const int size_;
static const int raw_size_;
static const int context_size_;
diff --git a/test/cctest/test-serialize.cc b/test/cctest/test-serialize.cc
index c277011..ed9419d 100644
--- node/deps/v8/test/cctest/test-serialize.cc
+++ node/deps/v8/test/cctest/test-serialize.cc
@@ -137,14 +137,10 @@ class FileByteSink : public SnapshotByteSink {
virtual int Position() {
return ftell(fp_);
}
- void WriteSpaceUsed(
- int new_space_used,
- int pointer_space_used,
- int data_space_used,
- int code_space_used,
- int map_space_used,
- int cell_space_used,
- int property_cell_space_used);
+ void WriteSpaceUsed(int new_space_used, int pointer_space_used,
+ int data_space_used, int code_space_used,
+ int map_space_used, int cell_space_used,
+ int property_cell_space_used, int lo_space_used);
private:
FILE* fp_;
@@ -152,14 +148,11 @@ class FileByteSink : public SnapshotByteSink {
};
-void FileByteSink::WriteSpaceUsed(
- int new_space_used,
- int pointer_space_used,
- int data_space_used,
- int code_space_used,
- int map_space_used,
- int cell_space_used,
- int property_cell_space_used) {
+void FileByteSink::WriteSpaceUsed(int new_space_used, int pointer_space_used,
+ int data_space_used, int code_space_used,
+ int map_space_used, int cell_space_used,
+ int property_cell_space_used,
+ int lo_space_used) {
int file_name_length = StrLength(file_name_) + 10;
Vector<char> name = Vector<char>::New(file_name_length + 1);
SNPrintF(name, "%s.size", file_name_);
@@ -172,6 +165,7 @@ void FileByteSink::WriteSpaceUsed(
fprintf(fp, "map %d\n", map_space_used);
fprintf(fp, "cell %d\n", cell_space_used);
fprintf(fp, "property cell %d\n", property_cell_space_used);
+ fprintf(fp, "lo %d\n", lo_space_used);
fclose(fp);
}
@@ -181,14 +175,14 @@ static bool WriteToFile(Isolate* isolate, const char* snapshot_file) {
StartupSerializer ser(isolate, &file);
ser.Serialize();
- file.WriteSpaceUsed(
- ser.CurrentAllocationAddress(NEW_SPACE),
- ser.CurrentAllocationAddress(OLD_POINTER_SPACE),
- ser.CurrentAllocationAddress(OLD_DATA_SPACE),
- ser.CurrentAllocationAddress(CODE_SPACE),
- ser.CurrentAllocationAddress(MAP_SPACE),
- ser.CurrentAllocationAddress(CELL_SPACE),
- ser.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
+ file.WriteSpaceUsed(ser.CurrentAllocationAddress(NEW_SPACE),
+ ser.CurrentAllocationAddress(OLD_POINTER_SPACE),
+ ser.CurrentAllocationAddress(OLD_DATA_SPACE),
+ ser.CurrentAllocationAddress(CODE_SPACE),
+ ser.CurrentAllocationAddress(MAP_SPACE),
+ ser.CurrentAllocationAddress(CELL_SPACE),
+ ser.CurrentAllocationAddress(PROPERTY_CELL_SPACE),
+ ser.CurrentAllocationAddress(LO_SPACE));
return true;
}
@@ -246,7 +240,7 @@ static void ReserveSpaceForSnapshot(Deserializer* deserializer,
FILE* fp = v8::base::OS::FOpen(name.start(), "r");
name.Dispose();
int new_size, pointer_size, data_size, code_size, map_size, cell_size,
- property_cell_size;
+ property_cell_size, lo_size;
#ifdef _MSC_VER
// Avoid warning about unsafe fscanf from MSVC.
// Please note that this is only fine if %c and %s are not being used.
@@ -259,6 +253,7 @@ static void ReserveSpaceForSnapshot(Deserializer* deserializer,
CHECK_EQ(1, fscanf(fp, "map %d\n", &map_size));
CHECK_EQ(1, fscanf(fp, "cell %d\n", &cell_size));
CHECK_EQ(1, fscanf(fp, "property cell %d\n", &property_cell_size));
+ CHECK_EQ(1, fscanf(fp, "lo %d\n", &lo_size));
#ifdef _MSC_VER
#undef fscanf
#endif
@@ -270,6 +265,7 @@ static void ReserveSpaceForSnapshot(Deserializer* deserializer,
deserializer->set_reservation(MAP_SPACE, map_size);
deserializer->set_reservation(CELL_SPACE, cell_size);
deserializer->set_reservation(PROPERTY_CELL_SPACE, property_cell_size);
+ deserializer->set_reservation(LO_SPACE, lo_size);
}

View File

@ -1,88 +0,0 @@
commit 667f15a1047eeadf4cbadbb50dafe6541745cdc3
Author: yangguo@chromium.org <yangguo@chromium.org>
Date: Mon Sep 29 07:14:05 2014 +0000
Fix serializing ICs.
R=mvstanton@chromium.org
Review URL: https://codereview.chromium.org/587213002
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24262 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/serialize.cc b/src/serialize.cc
index 894a1be..a2dde9b 100644
--- node/deps/v8/src/serialize.cc
+++ node/deps/v8/src/serialize.cc
@@ -1894,15 +1894,26 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code,
if (heap_object->IsCode()) {
Code* code_object = Code::cast(heap_object);
- DCHECK(!code_object->is_optimized_code());
- if (code_object->kind() == Code::BUILTIN) {
- SerializeBuiltin(code_object, how_to_code, where_to_point, skip);
- return;
- } else if (code_object->IsCodeStubOrIC()) {
- SerializeCodeStub(code_object, how_to_code, where_to_point, skip);
- return;
+ switch (code_object->kind()) {
+ case Code::OPTIMIZED_FUNCTION: // No optimized code compiled yet.
+ case Code::HANDLER: // No handlers patched in yet.
+ case Code::REGEXP: // No regexp literals initialized yet.
+ case Code::NUMBER_OF_KINDS: // Pseudo enum value.
+ CHECK(false);
+ case Code::BUILTIN:
+ SerializeBuiltin(code_object, how_to_code, where_to_point, skip);
+ return;
+ case Code::STUB:
+ SerializeCodeStub(code_object, how_to_code, where_to_point, skip);
+ return;
+#define IC_KIND_CASE(KIND) case Code::KIND:
+ IC_KIND_LIST(IC_KIND_CASE)
+#undef IC_KIND_CASE
+ // TODO(yangguo): add special handling to canonicalize ICs.
+ case Code::FUNCTION:
+ SerializeHeapObject(code_object, how_to_code, where_to_point, skip);
+ return;
}
- code_object->ClearInlineCaches();
}
if (heap_object == source_) {
@@ -1967,20 +1978,13 @@ void CodeSerializer::SerializeBuiltin(Code* builtin, HowToCode how_to_code,
}
-void CodeSerializer::SerializeCodeStub(Code* code, HowToCode how_to_code,
+void CodeSerializer::SerializeCodeStub(Code* stub, HowToCode how_to_code,
WhereToPoint where_to_point, int skip) {
DCHECK((how_to_code == kPlain && where_to_point == kStartOfObject) ||
(how_to_code == kPlain && where_to_point == kInnerPointer) ||
(how_to_code == kFromCode && where_to_point == kInnerPointer));
- uint32_t stub_key = code->stub_key();
-
- if (CodeStub::MajorKeyFromKey(stub_key) == CodeStub::NoCacheKey()) {
- if (FLAG_trace_code_serializer) {
- PrintF("Encoding uncacheable code stub as heap object\n");
- }
- SerializeHeapObject(code, how_to_code, where_to_point, skip);
- return;
- }
+ uint32_t stub_key = stub->stub_key();
+ DCHECK(CodeStub::MajorKeyFromKey(stub_key) != CodeStub::NoCache);
if (skip != 0) {
sink_->Put(kSkip, "SkipFromSerializeCodeStub");
diff --git a/src/serialize.h b/src/serialize.h
index 7831536..b6ad82c 100644
--- node/deps/v8/src/serialize.h
+++ node/deps/v8/src/serialize.h
@@ -607,7 +607,7 @@ class CodeSerializer : public Serializer {
private:
void SerializeBuiltin(Code* builtin, HowToCode how_to_code,
WhereToPoint where_to_point, int skip);
- void SerializeCodeStub(Code* code, HowToCode how_to_code,
+ void SerializeCodeStub(Code* stub, HowToCode how_to_code,
WhereToPoint where_to_point, int skip);
void SerializeSourceObject(HowToCode how_to_code, WhereToPoint where_to_point,
int skip);

View File

@ -1,238 +0,0 @@
commit ad24cdae728fc34b23e74a22543702de3ae477d1
Author: yangguo@chromium.org <yangguo@chromium.org>
Date: Mon Sep 29 07:53:22 2014 +0000
Do not serialize non-lazy compiled function literals.
... and some small refactorings.
R=mvstanton@chromium.org
Review URL: https://codereview.chromium.org/594513002
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24266 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/serialize.cc b/src/serialize.cc
index a2dde9b..9d59b6f 100644
--- node/deps/v8/src/serialize.cc
+++ node/deps/v8/src/serialize.cc
@@ -1846,7 +1846,7 @@ ScriptData* CodeSerializer::Serialize(Isolate* isolate,
SnapshotByteSink* sink = FLAG_trace_code_serializer
? static_cast<SnapshotByteSink*>(&debug_sink)
: static_cast<SnapshotByteSink*>(&list_sink);
- CodeSerializer cs(isolate, sink, *source);
+ CodeSerializer cs(isolate, sink, *source, info->code());
DisallowHeapAllocation no_gc;
Object** location = Handle<Object>::cast(info).location();
cs.VisitPointer(location);
@@ -1867,31 +1867,25 @@ ScriptData* CodeSerializer::Serialize(Isolate* isolate,
void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code,
WhereToPoint where_to_point, int skip) {
- CHECK(o->IsHeapObject());
HeapObject* heap_object = HeapObject::cast(o);
- // The code-caches link to context-specific code objects, which
- // the startup and context serializes cannot currently handle.
- DCHECK(!heap_object->IsMap() ||
- Map::cast(heap_object)->code_cache() ==
- heap_object->GetHeap()->empty_fixed_array());
-
int root_index;
if ((root_index = RootIndex(heap_object, how_to_code)) != kInvalidRootIndex) {
PutRoot(root_index, heap_object, how_to_code, where_to_point, skip);
return;
}
- // TODO(yangguo) wire up global object.
- // TODO(yangguo) We cannot deal with different hash seeds yet.
- DCHECK(!heap_object->IsHashTable());
-
if (address_mapper_.IsMapped(heap_object)) {
SerializeReferenceToPreviousObject(heap_object, how_to_code, where_to_point,
skip);
return;
}
+ if (skip != 0) {
+ sink_->Put(kSkip, "SkipFromSerializeObject");
+ sink_->PutInt(skip, "SkipDistanceFromSerializeObject");
+ }
+
if (heap_object->IsCode()) {
Code* code_object = Code::cast(heap_object);
switch (code_object->kind()) {
@@ -1901,34 +1895,42 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code,
case Code::NUMBER_OF_KINDS: // Pseudo enum value.
CHECK(false);
case Code::BUILTIN:
- SerializeBuiltin(code_object, how_to_code, where_to_point, skip);
+ SerializeBuiltin(code_object, how_to_code, where_to_point);
return;
case Code::STUB:
- SerializeCodeStub(code_object, how_to_code, where_to_point, skip);
+ SerializeCodeStub(code_object, how_to_code, where_to_point);
return;
#define IC_KIND_CASE(KIND) case Code::KIND:
IC_KIND_LIST(IC_KIND_CASE)
#undef IC_KIND_CASE
+ SerializeHeapObject(code_object, how_to_code, where_to_point);
+ return;
// TODO(yangguo): add special handling to canonicalize ICs.
case Code::FUNCTION:
- SerializeHeapObject(code_object, how_to_code, where_to_point, skip);
+ SerializeHeapObject(code_object, how_to_code, where_to_point);
return;
}
}
if (heap_object == source_) {
- SerializeSourceObject(how_to_code, where_to_point, skip);
+ SerializeSourceObject(how_to_code, where_to_point);
return;
}
- SerializeHeapObject(heap_object, how_to_code, where_to_point, skip);
+ // Past this point we should not see any (context-specific) maps anymore.
+ CHECK(!heap_object->IsMap());
+ // There should be no references to the global object embedded.
+ CHECK(!heap_object->IsJSGlobalProxy() && !heap_object->IsGlobalObject());
+ // There should be no hash table embedded. They would require rehashing.
+ CHECK(!heap_object->IsHashTable());
+
+ SerializeHeapObject(heap_object, how_to_code, where_to_point);
}
void CodeSerializer::SerializeHeapObject(HeapObject* heap_object,
HowToCode how_to_code,
- WhereToPoint where_to_point,
- int skip) {
+ WhereToPoint where_to_point) {
if (heap_object->IsScript()) {
// The wrapper cache uses a Foreign object to point to a global handle.
// However, the object visitor expects foreign objects to point to external
@@ -1936,11 +1946,6 @@ void CodeSerializer::SerializeHeapObject(HeapObject* heap_object,
Script::cast(heap_object)->ClearWrapperCache();
}
- if (skip != 0) {
- sink_->Put(kSkip, "SkipFromSerializeObject");
- sink_->PutInt(skip, "SkipDistanceFromSerializeObject");
- }
-
if (FLAG_trace_code_serializer) {
PrintF("Encoding heap object: ");
heap_object->ShortPrint();
@@ -1955,12 +1960,7 @@ void CodeSerializer::SerializeHeapObject(HeapObject* heap_object,
void CodeSerializer::SerializeBuiltin(Code* builtin, HowToCode how_to_code,
- WhereToPoint where_to_point, int skip) {
- if (skip != 0) {
- sink_->Put(kSkip, "SkipFromSerializeBuiltin");
- sink_->PutInt(skip, "SkipDistanceFromSerializeBuiltin");
- }
-
+ WhereToPoint where_to_point) {
DCHECK((how_to_code == kPlain && where_to_point == kStartOfObject) ||
(how_to_code == kPlain && where_to_point == kInnerPointer) ||
(how_to_code == kFromCode && where_to_point == kInnerPointer));
@@ -1979,18 +1979,13 @@ void CodeSerializer::SerializeBuiltin(Code* builtin, HowToCode how_to_code,
void CodeSerializer::SerializeCodeStub(Code* stub, HowToCode how_to_code,
- WhereToPoint where_to_point, int skip) {
+ WhereToPoint where_to_point) {
DCHECK((how_to_code == kPlain && where_to_point == kStartOfObject) ||
(how_to_code == kPlain && where_to_point == kInnerPointer) ||
(how_to_code == kFromCode && where_to_point == kInnerPointer));
uint32_t stub_key = stub->stub_key();
DCHECK(CodeStub::MajorKeyFromKey(stub_key) != CodeStub::NoCache);
- if (skip != 0) {
- sink_->Put(kSkip, "SkipFromSerializeCodeStub");
- sink_->PutInt(skip, "SkipDistanceFromSerializeCodeStub");
- }
-
int index = AddCodeStubKey(stub_key) + kCodeStubsBaseIndex;
if (FLAG_trace_code_serializer) {
@@ -2017,16 +2012,8 @@ int CodeSerializer::AddCodeStubKey(uint32_t stub_key) {
void CodeSerializer::SerializeSourceObject(HowToCode how_to_code,
- WhereToPoint where_to_point,
- int skip) {
- if (skip != 0) {
- sink_->Put(kSkip, "SkipFromSerializeSourceObject");
- sink_->PutInt(skip, "SkipDistanceFromSerializeSourceObject");
- }
-
- if (FLAG_trace_code_serializer) {
- PrintF("Encoding source object\n");
- }
+ WhereToPoint where_to_point) {
+ if (FLAG_trace_code_serializer) PrintF("Encoding source object\n");
DCHECK(how_to_code == kPlain && where_to_point == kStartOfObject);
sink_->Put(kAttachedReference + how_to_code + where_to_point, "Source");
diff --git a/src/serialize.h b/src/serialize.h
index b6ad82c..616f8f1 100644
--- node/deps/v8/src/serialize.h
+++ node/deps/v8/src/serialize.h
@@ -577,19 +577,10 @@ class StartupSerializer : public Serializer {
class CodeSerializer : public Serializer {
public:
- CodeSerializer(Isolate* isolate, SnapshotByteSink* sink, String* source)
- : Serializer(isolate, sink), source_(source) {
- set_root_index_wave_front(Heap::kStrongRootListLength);
- InitializeCodeAddressMap();
- }
-
static ScriptData* Serialize(Isolate* isolate,
Handle<SharedFunctionInfo> info,
Handle<String> source);
- virtual void SerializeObject(Object* o, HowToCode how_to_code,
- WhereToPoint where_to_point, int skip);
-
static Handle<SharedFunctionInfo> Deserialize(Isolate* isolate,
ScriptData* data,
Handle<String> source);
@@ -605,18 +596,29 @@ class CodeSerializer : public Serializer {
List<uint32_t>* stub_keys() { return &stub_keys_; }
private:
+ CodeSerializer(Isolate* isolate, SnapshotByteSink* sink, String* source,
+ Code* main_code)
+ : Serializer(isolate, sink), source_(source), main_code_(main_code) {
+ set_root_index_wave_front(Heap::kStrongRootListLength);
+ InitializeCodeAddressMap();
+ }
+
+ virtual void SerializeObject(Object* o, HowToCode how_to_code,
+ WhereToPoint where_to_point, int skip);
+
void SerializeBuiltin(Code* builtin, HowToCode how_to_code,
- WhereToPoint where_to_point, int skip);
+ WhereToPoint where_to_point);
void SerializeCodeStub(Code* stub, HowToCode how_to_code,
- WhereToPoint where_to_point, int skip);
- void SerializeSourceObject(HowToCode how_to_code, WhereToPoint where_to_point,
- int skip);
+ WhereToPoint where_to_point);
+ void SerializeSourceObject(HowToCode how_to_code,
+ WhereToPoint where_to_point);
void SerializeHeapObject(HeapObject* heap_object, HowToCode how_to_code,
- WhereToPoint where_to_point, int skip);
+ WhereToPoint where_to_point);
int AddCodeStubKey(uint32_t stub_key);
DisallowHeapAllocation no_gc_;
String* source_;
+ Code* main_code_;
List<uint32_t> stub_keys_;
DISALLOW_COPY_AND_ASSIGN(CodeSerializer);
};

View File

@ -1,53 +0,0 @@
commit 6ca8f782aac4df7530d9fd460ec0fabd46628e1d
Author: yangguo@chromium.org <yangguo@chromium.org>
Date: Fri Oct 10 10:51:34 2014 +0000
Reset code age when serializing code objects.
R=mvstanton@chromium.org
Review URL: https://codereview.chromium.org/642283002
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24523 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/objects.cc b/src/objects.cc
index 9f25145..3eedfe9 100644
--- node/deps/v8/src/objects.cc
+++ node/deps/v8/src/objects.cc
@@ -10463,6 +10463,12 @@ static Code::Age EffectiveAge(Code::Age age) {
}
+void Code::MakeYoung() {
+ byte* sequence = FindCodeAgeSequence();
+ if (sequence != NULL) MakeCodeAgeSequenceYoung(sequence, GetIsolate());
+}
+
+
void Code::MakeOlder(MarkingParity current_parity) {
byte* sequence = FindCodeAgeSequence();
if (sequence != NULL) {
diff --git a/src/objects.h b/src/objects.h
index bcbea12..1faae86 100644
--- node/deps/v8/src/objects.h
+++ node/deps/v8/src/objects.h
@@ -5310,6 +5310,7 @@ class Code: public HeapObject {
// compilation stub.
static void MakeCodeAgeSequenceYoung(byte* sequence, Isolate* isolate);
static void MarkCodeAsExecuted(byte* sequence, Isolate* isolate);
+ void MakeYoung();
void MakeOlder(MarkingParity);
static bool IsYoungSequence(Isolate* isolate, byte* sequence);
bool IsOld();
diff --git a/src/serialize.cc b/src/serialize.cc
index 0cc629d..c287219 100644
--- node/deps/v8/src/serialize.cc
+++ node/deps/v8/src/serialize.cc
@@ -1991,6 +1991,7 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code,
return;
// TODO(yangguo): add special handling to canonicalize ICs.
case Code::FUNCTION:
+ code_object->MakeYoung();
SerializeHeapObject(code_object, how_to_code, where_to_point);
return;
}

View File

@ -1,38 +0,0 @@
commit 33dc53f9cc709862de641d32c9a412cf7cfce953
Author: yangguo@chromium.org <yangguo@chromium.org>
Date: Mon Oct 13 07:50:21 2014 +0000
Always include full reloc info to stubs for serialization.
R=mvstanton@chromium.org
Review URL: https://codereview.chromium.org/641643006
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24543 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc
index 80fff3f..63488dc 100644
--- node/deps/v8/src/code-stubs-hydrogen.cc
+++ node/deps/v8/src/code-stubs-hydrogen.cc
@@ -233,6 +233,8 @@ Handle<Code> HydrogenCodeStub::GenerateLightweightMissCode(
// Generate the code for the stub.
masm.set_generating_stub(true);
+ // TODO(yangguo): remove this once we can serialize IC stubs.
+ masm.enable_serializer();
NoCurrentFrameScope scope(&masm);
GenerateLightweightMiss(&masm, miss);
}
diff --git a/src/code-stubs.cc b/src/code-stubs.cc
index 357324b..9832650 100644
--- node/deps/v8/src/code-stubs.cc
+++ node/deps/v8/src/code-stubs.cc
@@ -111,6 +111,8 @@ Handle<Code> PlatformCodeStub::GenerateCode() {
// Generate the code for the stub.
masm.set_generating_stub(true);
+ // TODO(yangguo): remove this once we can serialize IC stubs.
+ masm.enable_serializer();
NoCurrentFrameScope scope(&masm);
Generate(&masm);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,25 +0,0 @@
commit d7acb9148b6407526c257eceaec16c358655a3d5
Author: jkummerow@chromium.org <jkummerow@chromium.org>
Date: Wed Oct 15 14:27:26 2014 +0000
Fix compilation after r24639
TBR=yangguo@chromium.org
Review URL: https://codereview.chromium.org/661473002
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24642 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/serialize.cc b/src/serialize.cc
index 4c9675e..b980940 100644
--- node/deps/v8/src/serialize.cc
+++ node/deps/v8/src/serialize.cc
@@ -1918,7 +1918,7 @@ uint32_t Serializer::Allocate(int space, int size) {
DCHECK(size > 0 && size < Page::kMaxRegularHeapObjectSize);
uint32_t new_chunk_size = pending_chunk_[space] + size;
uint32_t allocation;
- if (new_chunk_size > Page::kMaxRegularHeapObjectSize) {
+ if (new_chunk_size > static_cast<uint32_t>(Page::kMaxRegularHeapObjectSize)) {
// The new chunk size would not fit onto a single page. Complete the
// current chunk and start a new one.
completed_chunks_[space].Add(pending_chunk_[space]);

View File

@ -1,26 +0,0 @@
commit 2577d6c261da26d6fbc97669a3ef8f4b61027c7e
Author: sigurds@chromium.org <sigurds@chromium.org>
Date: Wed Oct 15 14:42:32 2014 +0000
Fix compilation after r24639
TBR=yangguo@chromium.org
Review URL: https://codereview.chromium.org/653353003
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24643 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/serialize.h b/src/serialize.h
index 6e1f651..482bc34 100644
--- node/deps/v8/src/serialize.h
+++ node/deps/v8/src/serialize.h
@@ -263,7 +263,8 @@ class Deserializer: public SerializerDeserializer {
void AddReservation(int space, uint32_t chunk) {
DCHECK(space >= 0);
DCHECK(space < kNumberOfSpaces);
- DCHECK(space == LO_SPACE || chunk < Page::kMaxRegularHeapObjectSize);
+ DCHECK(space == LO_SPACE ||
+ chunk < static_cast<uint32_t>(Page::kMaxRegularHeapObjectSize));
Heap::Chunk c = { chunk, NULL, NULL }; reservations_[space].Add(c);
}

View File

@ -1,29 +0,0 @@
commit 8949d5f58002c5d058064e9047a6247119e725bf
Author: jkummerow@chromium.org <jkummerow@chromium.org>
Date: Wed Oct 15 15:04:09 2014 +0000
Fix compilation some more after r24639
Third time's a charm...
TBR=yangguo@chromium.org
Review URL: https://codereview.chromium.org/655223003
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24644 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/serialize.cc b/src/serialize.cc
index b980940..4933a19 100644
--- node/deps/v8/src/serialize.cc
+++ node/deps/v8/src/serialize.cc
@@ -2213,7 +2213,9 @@ SerializedCodeData::SerializedCodeData(List<byte>* payload, CodeSerializer* cs)
for (int i = 0; i < SerializerDeserializer::kNumberOfSpaces; i++) {
Vector<const uint32_t> chunks = cs->FinalAllocationChunks(i);
for (int j = 0; j < chunks.length(); j++) {
- DCHECK(i == LO_SPACE || chunks[j] < Page::kMaxRegularHeapObjectSize);
+ DCHECK(i == LO_SPACE ||
+ chunks[j] <
+ static_cast<uint32_t>(Page::kMaxRegularHeapObjectSize));
uint32_t chunk = ChunkSizeBits::encode(chunks[j]) |
IsLastChunkBits::encode(j == chunks.length() - 1);
reservations.Add(chunk);

View File

@ -1,177 +0,0 @@
commit 7753ace1354ac231374da0446a5057b6b40780db
Author: yangguo@chromium.org <yangguo@chromium.org>
Date: Thu Oct 23 08:25:42 2014 +0000
Small fixes for the code serializer.
- assertions regarding max heap object size.
- ensure string table capacity upfront.
R=mvstanton@chromium.org
Review URL: https://codereview.chromium.org/671843003
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24824 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/objects.cc b/src/objects.cc
index 2685a5c..371931c 100644
--- node/deps/v8/src/objects.cc
+++ node/deps/v8/src/objects.cc
@@ -14769,6 +14769,16 @@ MaybeHandle<String> StringTable::LookupTwoCharsStringIfExists(
}
+void StringTable::EnsureCapacityForDeserialization(Isolate* isolate,
+ int expected) {
+ Handle<StringTable> table = isolate->factory()->string_table();
+ // We need a key instance for the virtual hash function.
+ InternalizedStringKey dummy_key(Handle<String>::null());
+ table = StringTable::EnsureCapacity(table, expected, &dummy_key);
+ isolate->factory()->set_string_table(table);
+}
+
+
Handle<String> StringTable::LookupString(Isolate* isolate,
Handle<String> string) {
InternalizedStringKey key(string);
diff --git a/src/objects.h b/src/objects.h
index 7e509e7..b2b64c2 100644
--- node/deps/v8/src/objects.h
+++ node/deps/v8/src/objects.h
@@ -3446,6 +3446,8 @@ class StringTable: public HashTable<StringTable,
uint16_t c1,
uint16_t c2);
+ static void EnsureCapacityForDeserialization(Isolate* isolate, int expected);
+
DECLARE_CAST(StringTable)
private:
diff --git a/src/serialize.cc b/src/serialize.cc
index 5e6de03..95336fb 100644
--- node/deps/v8/src/serialize.cc
+++ node/deps/v8/src/serialize.cc
@@ -1910,7 +1913,7 @@ uint32_t Serializer::AllocateLargeObject(int size) {
uint32_t Serializer::Allocate(int space, int size) {
CHECK(space >= 0 && space < kNumberOfPreallocatedSpaces);
- DCHECK(size > 0 && size < Page::kMaxRegularHeapObjectSize);
+ DCHECK(size > 0 && size <= Page::kMaxRegularHeapObjectSize);
uint32_t new_chunk_size = pending_chunk_[space] + size;
uint32_t allocation;
if (new_chunk_size > static_cast<uint32_t>(Page::kMaxRegularHeapObjectSize)) {
@@ -2081,6 +2084,8 @@ void CodeSerializer::SerializeHeapObject(HeapObject* heap_object,
PrintF("\n");
}
+ if (heap_object->IsInternalizedString()) num_internalized_strings_++;
+
// Object has not yet been serialized. Serialize it here.
ObjectSerializer serializer(this, heap_object, sink_, how_to_code,
where_to_point);
@@ -2201,6 +2206,11 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
SnapshotByteSource payload(scd.Payload(), scd.PayloadLength());
Deserializer deserializer(&payload);
+ // Eagerly expand string table to avoid allocations during deserialization.
+ StringTable::EnsureCapacityForDeserialization(isolate,
+ scd.NumInternalizedStrings());
+
+ // Set reservations.
STATIC_ASSERT(NEW_SPACE == 0);
int current_space = NEW_SPACE;
Vector<const SerializedCodeData::Reservation> res = scd.Reservations();
@@ -2254,7 +2264,7 @@ SerializedCodeData::SerializedCodeData(List<byte>* payload, CodeSerializer* cs)
Vector<const uint32_t> chunks = cs->FinalAllocationChunks(i);
for (int j = 0; j < chunks.length(); j++) {
DCHECK(i == LO_SPACE ||
- chunks[j] <
+ chunks[j] <=
static_cast<uint32_t>(Page::kMaxRegularHeapObjectSize));
uint32_t chunk = ChunkSizeBits::encode(chunks[j]) |
IsLastChunkBits::encode(j == chunks.length() - 1);
@@ -2277,6 +2287,7 @@ SerializedCodeData::SerializedCodeData(List<byte>* payload, CodeSerializer* cs)
// Set header values.
SetHeaderValue(kCheckSumOffset, CheckSum(cs->source()));
+ SetHeaderValue(kNumInternalizedStringsOffset, cs->num_internalized_strings());
SetHeaderValue(kReservationsOffset, reservations.length());
SetHeaderValue(kNumCodeStubKeysOffset, num_stub_keys);
SetHeaderValue(kPayloadLengthOffset, payload->length());
diff --git a/src/serialize.h b/src/serialize.h
index 47a244f..df6723c 100644
--- node/deps/v8/src/serialize.h
+++ node/deps/v8/src/serialize.h
@@ -264,7 +264,7 @@ class Deserializer: public SerializerDeserializer {
DCHECK(space >= 0);
DCHECK(space < kNumberOfSpaces);
DCHECK(space == LO_SPACE ||
- chunk < static_cast<uint32_t>(Page::kMaxRegularHeapObjectSize));
+ chunk <= static_cast<uint32_t>(Page::kMaxRegularHeapObjectSize));
Heap::Chunk c = { chunk, NULL, NULL }; reservations_[space].Add(c);
}
@@ -619,17 +619,21 @@ class CodeSerializer : public Serializer {
static const int kSourceObjectIndex = 0;
static const int kCodeStubsBaseIndex = 1;
- String* source() {
+ String* source() const {
DCHECK(!AllowHeapAllocation::IsAllowed());
return source_;
}
List<uint32_t>* stub_keys() { return &stub_keys_; }
+ int num_internalized_strings() const { return num_internalized_strings_; }
private:
CodeSerializer(Isolate* isolate, SnapshotByteSink* sink, String* source,
Code* main_code)
- : Serializer(isolate, sink), source_(source), main_code_(main_code) {
+ : Serializer(isolate, sink),
+ source_(source),
+ main_code_(main_code),
+ num_internalized_strings_(0) {
set_root_index_wave_front(Heap::kStrongRootListLength);
InitializeCodeAddressMap();
}
@@ -652,6 +656,7 @@ class CodeSerializer : public Serializer {
DisallowHeapAllocation no_gc_;
String* source_;
Code* main_code_;
+ int num_internalized_strings_;
List<uint32_t> stub_keys_;
DISALLOW_COPY_AND_ASSIGN(CodeSerializer);
};
@@ -694,6 +699,10 @@ class SerializedCodeData {
DISALLOW_COPY_AND_ASSIGN(Reservation);
};
+ int NumInternalizedStrings() const {
+ return GetHeaderValue(kNumInternalizedStringsOffset);
+ }
+
Vector<const Reservation> Reservations() const {
return Vector<const Reservation>(reinterpret_cast<const Reservation*>(
script_data_->data() + kHeaderSize),
@@ -737,13 +746,15 @@ class SerializedCodeData {
// The data header consists of int-sized entries:
// [0] version hash
- // [1] number of code stub keys
- // [2] payload length
- // [3..9] reservation sizes for spaces from NEW_SPACE to PROPERTY_CELL_SPACE.
+ // [1] number of internalized strings
+ // [2] number of code stub keys
+ // [3] payload length
+ // [4..10] reservation sizes for spaces from NEW_SPACE to PROPERTY_CELL_SPACE.
static const int kCheckSumOffset = 0;
- static const int kReservationsOffset = 1;
- static const int kNumCodeStubKeysOffset = 2;
- static const int kPayloadLengthOffset = 3;
+ static const int kNumInternalizedStringsOffset = 1;
+ static const int kReservationsOffset = 2;
+ static const int kNumCodeStubKeysOffset = 3;
+ static const int kPayloadLengthOffset = 4;
static const int kHeaderSize = (kPayloadLengthOffset + 1) * kIntSize;
class ChunkSizeBits : public BitField<uint32_t, 0, 31> {};

View File

@ -1,217 +0,0 @@
commit 3a3d5e741a4329641fa45f7293220e8dfd7a8f15
Author: yangguo@chromium.org <yangguo@chromium.org>
Date: Fri Oct 31 14:43:21 2014 +0000
Break allocations in the code serializer into correct chunk sizes.
This change has been inspired by Slava Chigrin <vchigrin@yandex-team.ru> (https://codereview.chromium.org/689663002/)
R=mvstanton@chromium.org, vchigrin@yandex-team.ru
Review URL: https://codereview.chromium.org/686103004
Cr-Commit-Position: refs/heads/master@{#25039}
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@25039 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/heap/heap.cc b/src/heap/heap.cc
index 94c8937..93e00d2 100644
--- node/deps/v8/src/heap/heap.cc
+++ node/deps/v8/src/heap/heap.cc
@@ -939,6 +939,8 @@ bool Heap::ReserveSpace(Reservation* reservations) {
for (auto& chunk : *reservation) {
AllocationResult allocation;
int size = chunk.size;
+ DCHECK_LE(size, MemoryAllocator::PageAreaSize(
+ static_cast<AllocationSpace>(space)));
if (space == NEW_SPACE) {
allocation = new_space()->AllocateRaw(size);
} else {
diff --git a/src/heap/spaces.cc b/src/heap/spaces.cc
index 85281aa..430f31d 100644
--- node/deps/v8/src/heap/spaces.cc
+++ node/deps/v8/src/heap/spaces.cc
@@ -892,19 +892,15 @@ void MemoryChunk::IncrementLiveBytesFromMutator(Address address, int by) {
// -----------------------------------------------------------------------------
// PagedSpace implementation
-PagedSpace::PagedSpace(Heap* heap, intptr_t max_capacity, AllocationSpace id,
+PagedSpace::PagedSpace(Heap* heap, intptr_t max_capacity, AllocationSpace space,
Executability executable)
- : Space(heap, id, executable),
+ : Space(heap, space, executable),
free_list_(this),
swept_precisely_(true),
unswept_free_bytes_(0),
end_of_unswept_pages_(NULL),
emergency_memory_(NULL) {
- if (id == CODE_SPACE) {
- area_size_ = heap->isolate()->memory_allocator()->CodePageAreaSize();
- } else {
- area_size_ = Page::kPageSize - Page::kObjectStartOffset;
- }
+ area_size_ = MemoryAllocator::PageAreaSize(space);
max_capacity_ =
(RoundDown(max_capacity, Page::kPageSize) / Page::kPageSize) * AreaSize();
accounting_stats_.Clear();
diff --git a/src/heap/spaces.h b/src/heap/spaces.h
index 5be9c3a..1944464 100644
--- node/deps/v8/src/heap/spaces.h
+++ node/deps/v8/src/heap/spaces.h
@@ -1104,6 +1104,12 @@ class MemoryAllocator {
return CodePageAreaEndOffset() - CodePageAreaStartOffset();
}
+ static int PageAreaSize(AllocationSpace space) {
+ DCHECK_NE(LO_SPACE, space);
+ return (space == CODE_SPACE) ? CodePageAreaSize()
+ : Page::kMaxRegularHeapObjectSize;
+ }
+
MUST_USE_RESULT bool CommitExecutableMemory(base::VirtualMemory* vm,
Address start, size_t commit_size,
size_t reserved_size);
diff --git a/src/serialize.cc b/src/serialize.cc
index 86045d3..df62adb 100644
--- node/deps/v8/src/serialize.cc
+++ node/deps/v8/src/serialize.cc
@@ -1258,10 +1258,15 @@ Serializer::Serializer(Isolate* isolate, SnapshotByteSink* sink)
external_reference_encoder_(new ExternalReferenceEncoder(isolate)),
root_index_map_(isolate),
code_address_map_(NULL),
+ large_objects_total_size_(0),
seen_large_objects_index_(0) {
// The serializer is meant to be used only to generate initial heap images
// from a context in which there is only one isolate.
- for (int i = 0; i < kNumberOfSpaces; i++) pending_chunk_[i] = 0;
+ for (int i = 0; i < kNumberOfPreallocatedSpaces; i++) {
+ pending_chunk_[i] = 0;
+ max_chunk_size_[i] = static_cast<uint32_t>(
+ MemoryAllocator::PageAreaSize(static_cast<AllocationSpace>(i)));
+ }
}
@@ -1336,8 +1341,7 @@ void Serializer::VisitPointers(Object** start, Object** end) {
void Serializer::FinalizeAllocation() {
- DCHECK_EQ(0, completed_chunks_[LO_SPACE].length()); // Not yet finalized.
- for (int i = 0; i < kNumberOfSpaces; i++) {
+ for (int i = 0; i < kNumberOfPreallocatedSpaces; i++) {
// Complete the last pending chunk and if there are no completed chunks,
// make sure there is at least one empty chunk.
if (pending_chunk_[i] > 0 || completed_chunks_[i].length() == 0) {
@@ -1906,17 +1910,17 @@ AllocationSpace Serializer::SpaceOfObject(HeapObject* object) {
uint32_t Serializer::AllocateLargeObject(int size) {
// Large objects are allocated one-by-one when deserializing. We do not
// have to keep track of multiple chunks.
- pending_chunk_[LO_SPACE] += size;
+ large_objects_total_size_ += size;
return seen_large_objects_index_++;
}
uint32_t Serializer::Allocate(int space, int size) {
CHECK(space >= 0 && space < kNumberOfPreallocatedSpaces);
- DCHECK(size > 0 && size <= Page::kMaxRegularHeapObjectSize);
+ DCHECK(size > 0 && size <= static_cast<int>(max_chunk_size(space)));
uint32_t new_chunk_size = pending_chunk_[space] + size;
uint32_t allocation;
- if (new_chunk_size > static_cast<uint32_t>(Page::kMaxRegularHeapObjectSize)) {
+ if (new_chunk_size > max_chunk_size(space)) {
// The new chunk size would not fit onto a single page. Complete the
// current chunk and start a new one.
completed_chunks_[space].Add(pending_chunk_[space]);
@@ -1929,15 +1933,6 @@ BackReference Serializer::Allocate(AllocationSpace space, int size) {
}
-int Serializer::SpaceAreaSize(int space) {
- if (space == CODE_SPACE) {
- return isolate_->memory_allocator()->CodePageAreaSize();
- } else {
- return Page::kPageSize - Page::kObjectStartOffset;
- }
-}
-
-
void Serializer::Pad() {
// The non-branching GetInt will read up to 3 bytes too far, so we need
// to pad the snapshot to make sure we don't read over the end.
@@ -2273,9 +2268,6 @@ SerializedCodeData::SerializedCodeData(const List<byte>& payload,
for (int i = 0; i < SerializerDeserializer::kNumberOfSpaces; i++) {
Vector<const uint32_t> chunks = cs->FinalAllocationChunks(i);
for (int j = 0; j < chunks.length(); j++) {
- DCHECK(i == LO_SPACE ||
- chunks[j] <=
- static_cast<uint32_t>(Page::kMaxRegularHeapObjectSize));
uint32_t chunk = ChunkSizeBits::encode(chunks[j]) |
IsLastChunkBits::encode(j == chunks.length() - 1);
reservations.Add(chunk);
diff --git a/src/serialize.h b/src/serialize.h
index 2aa55ea..9c56118 100644
--- node/deps/v8/src/serialize.h
+++ node/deps/v8/src/serialize.h
@@ -404,8 +404,6 @@ class Deserializer: public SerializerDeserializer {
void AddReservation(int space, uint32_t chunk) {
DCHECK(space >= 0);
DCHECK(space < kNumberOfSpaces);
- DCHECK(space == LO_SPACE ||
- chunk <= static_cast<uint32_t>(Page::kMaxRegularHeapObjectSize));
Heap::Chunk c = { chunk, NULL, NULL }; reservations_[space].Add(c);
}
@@ -498,9 +496,12 @@ class Serializer : public SerializerDeserializer {
void FinalizeAllocation();
Vector<const uint32_t> FinalAllocationChunks(int space) const {
- DCHECK_EQ(1, completed_chunks_[LO_SPACE].length()); // Already finalized.
- DCHECK_EQ(0, pending_chunk_[space]); // No pending chunks.
- return completed_chunks_[space].ToConstVector();
+ if (space == LO_SPACE) {
+ return Vector<const uint32_t>(&large_objects_total_size_, 1);
+ } else {
+ DCHECK_EQ(0, pending_chunk_[space]); // No pending chunks.
+ return completed_chunks_[space].ToConstVector();
+ }
}
Isolate* isolate() const { return isolate_; }
@@ -496,20 +496,25 @@
return external_reference_encoder_->Encode(addr);
}
- int SpaceAreaSize(int space);
-
// Some roots should not be serialized, because their actual value depends on
// absolute addresses and they are reset after deserialization, anyway.
bool ShouldBeSkipped(Object** current);
+ uint32_t max_chunk_size(int space) const {
+ DCHECK_LE(0, space);
+ DCHECK_LT(space, kNumberOfSpaces);
+ return max_chunk_size_[space];
+ }
+
Isolate* isolate_;
// Objects from the same space are put into chunks for bulk-allocation
// when deserializing. We have to make sure that each chunk fits into a
// page. So we track the chunk size in pending_chunk_ of a space, but
// when it exceeds a page, we complete the current chunk and start a new one.
- uint32_t pending_chunk_[kNumberOfSpaces];
- List<uint32_t> completed_chunks_[kNumberOfSpaces];
+ uint32_t pending_chunk_[kNumberOfPreallocatedSpaces];
+ List<uint32_t> completed_chunks_[kNumberOfPreallocatedSpaces];
+ uint32_t max_chunk_size_[kNumberOfPreallocatedSpaces];
SnapshotByteSink* sink_;
ExternalReferenceEncoder* external_reference_encoder_;
@@ -529,6 +534,7 @@
CodeAddressMap* code_address_map_;
// We map serialized large objects to indexes for back-referencing.
uint32_t seen_large_objects_index_;
+ uint32_t large_objects_total_size_;
DISALLOW_COPY_AND_ASSIGN(Serializer);
};

View File

@ -1,117 +0,0 @@
commit c64b47f55237a78b6d74baa1503e7218b94811e4
Author: yangguo <yangguo@chromium.org>
Date: Thu Nov 20 08:20:48 2014 -0800
When optimizing deserialized code, make sure IC state is preserved.
R=jkummerow@chromium.org
Review URL: https://codereview.chromium.org/737373003
Cr-Commit-Position: refs/heads/master@{#25444}
diff --git a/src/compiler.cc b/src/compiler.cc
index 3b612c1..33d88d7 100644
--- node/deps/v8/src/compiler.cc
+++ node/deps/v8/src/compiler.cc
@@ -384,13 +384,21 @@
if (FLAG_hydrogen_stats) {
timer.Start();
}
- CompilationInfoWithZone unoptimized(info()->shared_info());
+ Handle<SharedFunctionInfo> shared = info()->shared_info();
+ CompilationInfoWithZone unoptimized(shared);
// Note that we use the same AST that we will use for generating the
// optimized code.
unoptimized.SetFunction(info()->function());
unoptimized.PrepareForCompilation(info()->scope());
unoptimized.SetContext(info()->context());
if (should_recompile) unoptimized.EnableDeoptimizationSupport();
+ // If the current code has reloc info for serialization, also include
+ // reloc info for serialization for the new code, so that deopt support
+ // can be added without losing IC state.
+ if (shared->code()->kind() == Code::FUNCTION &&
+ shared->code()->has_reloc_info_for_serialization()) {
+ unoptimized.PrepareForSerializing();
+ }
bool succeeded = FullCodeGenerator::MakeCode(&unoptimized);
if (should_recompile) {
if (!succeeded) return SetLastStatus(FAILED);
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 535dcd2..0d7363e 100644
--- node/deps/v8/src/flag-definitions.h
+++ node/deps/v8/src/flag-definitions.h
@@ -427,7 +427,8 @@
DEFINE_BOOL(trace_stub_failures, false,
"trace deoptimization of generated code stubs")
-DEFINE_BOOL(serialize_toplevel, false, "enable caching of toplevel scripts")
+DEFINE_BOOL(serialize_toplevel, true, "enable caching of toplevel scripts")
+DEFINE_BOOL(serialize_inner, true, "enable caching of inner functions")
DEFINE_BOOL(trace_code_serializer, false, "trace code serializer")
// compiler.cc
diff --git a/src/full-codegen.cc b/src/full-codegen.cc
index e32c59f..cb8f4aa 100644
--- node/deps/v8/src/full-codegen.cc
+++ node/deps/v8/src/full-codegen.cc
@@ -321,6 +321,7 @@
cgen.PopulateDeoptimizationData(code);
cgen.PopulateTypeFeedbackInfo(code);
code->set_has_deoptimization_support(info->HasDeoptimizationSupport());
+ code->set_has_reloc_info_for_serialization(info->will_serialize());
code->set_handler_table(*cgen.handler_table());
code->set_compiled_optimizable(info->IsOptimizable());
code->set_allow_osr_at_loop_nesting_level(0);
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 3dd6fed..108f9f6 100644
--- node/deps/v8/src/objects-inl.h
+++ node/deps/v8/src/objects-inl.h
@@ -4794,6 +4794,21 @@
}
+bool Code::has_reloc_info_for_serialization() {
+ DCHECK_EQ(FUNCTION, kind());
+ byte flags = READ_BYTE_FIELD(this, kFullCodeFlags);
+ return FullCodeFlagsHasRelocInfoForSerialization::decode(flags);
+}
+
+
+void Code::set_has_reloc_info_for_serialization(bool value) {
+ DCHECK_EQ(FUNCTION, kind());
+ byte flags = READ_BYTE_FIELD(this, kFullCodeFlags);
+ flags = FullCodeFlagsHasRelocInfoForSerialization::update(flags, value);
+ WRITE_BYTE_FIELD(this, kFullCodeFlags, flags);
+}
+
+
int Code::allow_osr_at_loop_nesting_level() {
DCHECK_EQ(FUNCTION, kind());
int fields = READ_UINT32_FIELD(this, kKindSpecificFlags2Offset);
diff --git a/src/objects.h b/src/objects.h
index 678dcb2..9569de9 100644
--- node/deps/v8/src/objects.h
+++ node/deps/v8/src/objects.h
@@ -5597,6 +5597,12 @@
inline bool is_compiled_optimizable();
inline void set_compiled_optimizable(bool value);
+ // [has_reloc_info_for_serialization]: For FUNCTION kind, tells if its
+ // reloc info includes runtime and external references to support
+ // serialization/deserialization.
+ inline bool has_reloc_info_for_serialization();
+ inline void set_has_reloc_info_for_serialization(bool value);
+
// [allow_osr_at_loop_nesting_level]: For FUNCTION kind, tells for
// how long the function has been marked for OSR and therefore which
// level of loop nesting we are willing to do on-stack replacement
@@ -5873,6 +5879,8 @@
public BitField<bool, 0, 1> {}; // NOLINT
class FullCodeFlagsHasDebugBreakSlotsField: public BitField<bool, 1, 1> {};
class FullCodeFlagsIsCompiledOptimizable: public BitField<bool, 2, 1> {};
+ class FullCodeFlagsHasRelocInfoForSerialization
+ : public BitField<bool, 3, 1> {};
static const int kProfilerTicksOffset = kFullCodeFlags + 1;

View File

@ -1,272 +0,0 @@
commit eb67f85439dcc273501e9fba5a9e883585505aa8
Author: adamk <adamk@chromium.org>
Date: Thu Dec 10 11:18:54 2015 -0800
Fix FuncNameInferrer usage in ParseAssignmentExpression
Without this fix, AssignmentExpressions that happen to be arrow functions
would lead to unbalanced Enter/Leave calls on the fni_, causing thrashing
while trying to infer function names. Symptoms include slow parsing
or OOM (when we create too many AstConsStrings).
To try to keep this from happening in the future, added an RAII helper
class to handle Entering/Leaving FNI state.
The included regression test crashes on my workstation without the patch.
Note that it's too slow in debug mode (as well as under TurboFan),
so I've skipped it there.
BUG=v8:4595
LOG=y
Review URL: https://codereview.chromium.org/1507283003
Cr-Commit-Position: refs/heads/master@{#32768}
diff --git a/src/func-name-inferrer.h b/src/func-name-inferrer.h
index 8b077f9..1be6332 100644
--- node/deps/v8/src/func-name-inferrer.h
+++ node/deps/v8/src/func-name-inferrer.h
@@ -28,21 +28,33 @@ class FunctionLiteral;
// a name.
class FuncNameInferrer : public ZoneObject {
public:
FuncNameInferrer(AstValueFactory* ast_value_factory, Zone* zone);
+ // To enter function name inference state, put a FuncNameInferrer::State
+ // on the stack.
+ class State {
+ public:
+ explicit State(FuncNameInferrer* fni) : fni_(fni) {
+ if (fni_ != nullptr) fni_->Enter();
+ }
+ ~State() {
+ if (fni_ != nullptr) fni_->Leave();
+ }
+
+ private:
+ FuncNameInferrer* fni_;
+
+ DISALLOW_COPY_AND_ASSIGN(State);
+ };
+
// Returns whether we have entered name collection state.
bool IsOpen() const { return !entries_stack_.is_empty(); }
// Pushes an enclosing the name of enclosing function onto names stack.
void PushEnclosingName(const AstRawString* name);
- // Enters name collection state.
- void Enter() {
- entries_stack_.Add(names_stack_.length(), zone());
- }
-
// Pushes an encountered name onto names stack when in collection state.
void PushLiteralName(const AstRawString* name);
void PushVariableName(const AstRawString* name);
@@ -65,18 +77,10 @@ class FuncNameInferrer : public ZoneObject {
if (!funcs_to_infer_.is_empty()) {
InferFunctionsNames();
}
}
- // Leaves names collection state.
- void Leave() {
- DCHECK(IsOpen());
- names_stack_.Rewind(entries_stack_.RemoveLast());
- if (entries_stack_.is_empty())
- funcs_to_infer_.Clear();
- }
-
private:
enum NameType {
kEnclosingConstructorName,
kLiteralName,
kVariableName
@@ -85,10 +89,18 @@ class FuncNameInferrer : public ZoneObject {
Name(const AstRawString* name, NameType type) : name(name), type(type) {}
const AstRawString* name;
NameType type;
};
+ void Enter() { entries_stack_.Add(names_stack_.length(), zone()); }
+
+ void Leave() {
+ DCHECK(IsOpen());
+ names_stack_.Rewind(entries_stack_.RemoveLast());
+ if (entries_stack_.is_empty()) funcs_to_infer_.Clear();
+ }
+
Zone* zone() const { return zone_; }
// Constructs a full name in dotted notation from gathered names.
const AstString* MakeNameFromStack();
diff --git a/src/parser.cc b/src/parser.cc
index aa0ec10..b09286b 100644
--- node/deps/v8/src/parser.cc
+++ node/deps/v8/src/parser.cc
@@ -2466,11 +2466,11 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
bool first_declaration = true;
int bindings_start = peek_position();
bool is_for_iteration_variable;
do {
- if (fni_ != NULL) fni_->Enter();
+ FuncNameInferrer::State fni_state(fni_);
// Parse name.
if (!first_declaration) Consume(Token::COMMA);
Expression* pattern;
@@ -2541,11 +2541,10 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
// Make sure that 'const x' and 'let x' initialize 'x' to undefined.
if (value == NULL && parsing_result->descriptor.needs_init) {
value = GetLiteralUndefined(position());
}
- if (single_name && fni_ != NULL) fni_->Leave();
parsing_result->declarations.Add(DeclarationParsingResult::Declaration(
pattern, initializer_position, value));
first_declaration = false;
} while (peek() == Token::COMMA);
@@ -4504,11 +4503,11 @@ ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name,
Expect(Token::LBRACE, CHECK_OK);
const bool has_extends = extends != nullptr;
while (peek() != Token::RBRACE) {
if (Check(Token::SEMICOLON)) continue;
- if (fni_ != NULL) fni_->Enter();
+ FuncNameInferrer::State fni_state(fni_);
const bool in_class = true;
const bool is_static = false;
bool is_computed_name = false; // Classes do not care about computed
// property names here.
ExpressionClassifier classifier;
@@ -4522,14 +4521,11 @@ ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name,
DCHECK_NOT_NULL(constructor);
} else {
properties->Add(property, zone());
}
- if (fni_ != NULL) {
- fni_->Infer();
- fni_->Leave();
- }
+ if (fni_ != NULL) fni_->Infer();
}
Expect(Token::RBRACE, CHECK_OK);
int end_pos = scanner()->location().end_pos;
diff --git a/src/preparser.h b/src/preparser.h
index d9ef1ea..4141cd6 100644
--- node/deps/v8/src/preparser.h
+++ node/deps/v8/src/preparser.h
@@ -2646,11 +2646,11 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral(
ObjectLiteralChecker checker(this);
Expect(Token::LBRACE, CHECK_OK);
while (peek() != Token::RBRACE) {
- if (fni_ != nullptr) fni_->Enter();
+ FuncNameInferrer::State fni_state(fni_);
const bool in_class = false;
const bool is_static = false;
const bool has_extends = false;
bool is_computed_name = false;
@@ -2677,14 +2677,11 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral(
if (peek() != Token::RBRACE) {
// Need {} because of the CHECK_OK macro.
Expect(Token::COMMA, CHECK_OK);
}
- if (fni_ != nullptr) {
- fni_->Infer();
- fni_->Leave();
- }
+ if (fni_ != nullptr) fni_->Infer();
}
Expect(Token::RBRACE, CHECK_OK);
// Computation of literal_index must happen before pre parse bailout.
int literal_index = function_state_->NextMaterializedLiteralIndex();
@@ -2781,11 +2778,11 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
if (peek() == Token::YIELD && is_generator()) {
return this->ParseYieldExpression(classifier, ok);
}
- if (fni_ != NULL) fni_->Enter();
+ FuncNameInferrer::State fni_state(fni_);
ParserBase<Traits>::Checkpoint checkpoint(this);
ExpressionClassifier arrow_formals_classifier(classifier->duplicate_finder());
bool parenthesized_formals = peek() == Token::LPAREN;
if (!parenthesized_formals) {
ArrowFormalParametersUnexpectedToken(&arrow_formals_classifier);
@@ -2811,21 +2808,23 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
arrow_formals_classifier.RecordDuplicateFormalParameterError(
duplicate_loc);
}
expression = this->ParseArrowFunctionLiteral(
parsing_state, arrow_formals_classifier, CHECK_OK);
+
+ if (fni_ != nullptr) fni_->Infer();
+
return expression;
}
// "expression" was not itself an arrow function parameter list, but it might
// form part of one. Propagate speculative formal parameter error locations.
classifier->Accumulate(arrow_formals_classifier,
ExpressionClassifier::StandardProductions |
ExpressionClassifier::FormalParametersProductions);
if (!Token::IsAssignmentOp(peek())) {
- if (fni_ != NULL) fni_->Leave();
// Parsed conditional expression only (no assignment).
return expression;
}
if (!allow_harmony_destructuring()) {
@@ -2871,11 +2870,10 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
&& (!right->IsCall() && !right->IsCallNew())) {
fni_->Infer();
} else {
fni_->RemoveLastFunction();
}
- fni_->Leave();
}
return factory()->NewAssignment(op, expression, right, pos);
}
@@ -3324,11 +3322,11 @@ ParserBase<Traits>::ParseStrongInitializationExpression(
ExpressionClassifier* classifier, bool* ok) {
// InitializationExpression :: (strong mode)
// 'this' '.' IdentifierName '=' AssignmentExpression
// 'this' '[' Expression ']' '=' AssignmentExpression
- if (fni_ != NULL) fni_->Enter();
+ FuncNameInferrer::State fni_state(fni_);
Consume(Token::THIS);
int pos = position();
function_state_->set_this_location(scanner()->location());
ExpressionT this_expr = this->ThisExpression(scope_, factory(), pos);
@@ -3383,11 +3381,10 @@ ParserBase<Traits>::ParseStrongInitializationExpression(
if (!right->IsCall() && !right->IsCallNew()) {
fni_->Infer();
} else {
fni_->RemoveLastFunction();
}
- fni_->Leave();
}
if (function_state_->return_location().IsValid()) {
ReportMessageAt(function_state_->return_location(),
MessageTemplate::kStrongConstructorReturnMisplaced);

View File

@ -1,408 +0,0 @@
--- node/deps/v8/include/v8.h
+++ node/deps/v8/include/v8.h
@@ -4826,10 +4826,14 @@
*/
static void SetFlagsFromCommandLine(int* argc,
char** argv,
bool remove_flags);
+ static void EnableCompilationForSourcelessUse();
+ static void DisableCompilationForSourcelessUse();
+ static void FixSourcelessScript(Isolate* v8_isolate, Local<UnboundScript> script);
+
/** Get the version string. */
static const char* GetVersion();
/** Callback function for reporting failed access checks.*/
static void SetFailedAccessCheckCallbackFunction(FailedAccessCheckCallback);
--- node/deps/v8/src/api.cc
+++ node/deps/v8/src/api.cc
@@ -391,10 +391,46 @@
void V8::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags) {
i::FlagList::SetFlagsFromCommandLine(argc, argv, remove_flags);
}
+bool save_lazy;
+bool save_predictable;
+bool save_serialize_toplevel;
+
+
+void V8::EnableCompilationForSourcelessUse() {
+ save_lazy = i::FLAG_lazy;
+ i::FLAG_lazy = false;
+ save_predictable = i::FLAG_predictable;
+ i::FLAG_predictable = true;
+ save_serialize_toplevel = i::FLAG_serialize_toplevel;
+ i::FLAG_serialize_toplevel = true;
+ i::CpuFeatures::Reinitialize();
+ i::CpuFeatures::Probe(true);
+}
+
+
+void V8::DisableCompilationForSourcelessUse() {
+ i::FLAG_lazy = save_lazy;
+ i::FLAG_predictable = save_predictable;
+ i::FLAG_serialize_toplevel = save_serialize_toplevel;
+ i::CpuFeatures::Reinitialize();
+ i::CpuFeatures::Probe(false);
+}
+
+
+void V8::FixSourcelessScript(Isolate* v8_isolate, Local<UnboundScript> script) {
+ i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
+ i::Handle<i::HeapObject> object = i::Handle<i::HeapObject>::cast(Utils::OpenHandle(*script));
+ i::Handle<i::SharedFunctionInfo> function_info(
+ i::SharedFunctionInfo::cast(*object), object->GetIsolate());
+ i::Script* s = reinterpret_cast<i::Script*>(function_info->script());
+ s->set_source(isolate->heap()->undefined_value());
+}
+
+
RegisteredExtension* RegisteredExtension::first_extension_ = NULL;
RegisteredExtension::RegisteredExtension(Extension* extension)
: extension_(extension) { }
--- node/deps/v8/src/assembler.h
+++ node/deps/v8/src/assembler.h
@@ -196,10 +196,15 @@
static void PrintFeatures();
// Flush instruction cache.
static void FlushICache(void* start, size_t size);
+ static void Reinitialize() {
+ supported_ = 0;
+ initialized_ = false;
+ }
+
private:
// Platform-dependent implementation.
static void ProbeImpl(bool cross_compile);
static unsigned supported_;
--- node/deps/v8/src/parser.cc
+++ node/deps/v8/src/parser.cc
@@ -4838,10 +4838,11 @@
return !parser.failed();
}
bool Parser::Parse() {
+ if (info()->script()->source()->IsUndefined()) return false;
DCHECK(info()->function() == NULL);
FunctionLiteral* result = NULL;
ast_value_factory_ = info()->ast_value_factory();
if (ast_value_factory_ == NULL) {
ast_value_factory_ =
--- node/deps/v8/src/serialize.cc
+++ node/deps/v8/src/serialize.cc
@@ -2167,11 +2167,11 @@
payload->begin(), static_cast<size_t>(payload->length()));
}
bool SerializedCodeData::IsSane(String* source) {
- return GetHeaderValue(kCheckSumOffset) == CheckSum(source) &&
+ return true &&
PayloadLength() >= SharedFunctionInfo::kSize;
}
int SerializedCodeData::CheckSum(String* string) {
--- node/lib/child_process.js
+++ node/lib/child_process.js
@@ -579,11 +579,11 @@
options.stdio = options.silent ? ['pipe', 'pipe', 'pipe', 'ipc'] :
[0, 1, 2, 'ipc'];
options.execPath = options.execPath || process.execPath;
- return spawn(options.execPath, args, options);
+ return exports.spawn(options.execPath, args, options);
};
exports._forkChild = function(fd) {
// set process.send()
--- node/src/env.h
+++ node/src/env.h
@@ -202,10 +202,11 @@
V(signal_string, "signal") \
V(size_string, "size") \
V(smalloc_p_string, "_smalloc_p") \
V(sni_context_err_string, "Invalid SNI context") \
V(sni_context_string, "sni_context") \
+ V(sourceless_string, "sourceless") \
V(speed_string, "speed") \
V(stack_string, "stack") \
V(status_code_string, "statusCode") \
V(status_message_string, "statusMessage") \
V(status_string, "status") \
--- node/src/node.cc
+++ node/src/node.cc
@@ -2957,10 +2957,11 @@
}
static void PrintHelp();
static bool ParseDebugOpt(const char* arg) {
+ return false;
const char* port = NULL;
if (!strcmp(arg, "--debug")) {
use_debug_agent = true;
} else if (!strncmp(arg, "--debug=", sizeof("--debug=") - 1)) {
@@ -3575,14 +3576,10 @@
// Ignore SIGPIPE
RegisterSignalHandler(SIGPIPE, SIG_IGN);
RegisterSignalHandler(SIGINT, SignalExit, true);
RegisterSignalHandler(SIGTERM, SignalExit, true);
#endif // __POSIX__
-
- if (!use_debug_agent) {
- RegisterDebugSignalHandler();
- }
}
struct AtExitCallback {
AtExitCallback* next_;
@@ -3761,15 +3758,10 @@
const char* replaceInvalid = getenv("NODE_INVALID_UTF8");
if (replaceInvalid == NULL)
WRITE_UTF8_FLAGS |= String::REPLACE_INVALID_UTF8;
-#if !defined(_WIN32)
- // Try hard not to lose SIGUSR1 signals during the bootstrap process.
- InstallEarlyDebugSignalHandler();
-#endif
-
assert(argc > 0);
// Hack around with the argv pointer. Used for process.title = "blah".
argv = uv_setup_args(argc, argv);
--- node/src/node.js
+++ node/src/node.js
@@ -65,10 +65,46 @@
// There are various modes that Node can run in. The most common two
// are running from a script and running the REPL - but there are a few
// others like the debugger or running --eval arguments. Here we decide
// which mode we run in.
+ (function () {
+ var fs = NativeModule.require('fs');
+ var vm = NativeModule.require('vm');
+ function readPrelude (fd) {
+ var PAYLOAD_POSITION = '// PAYLOAD_POSITION //' | 0;
+ var PAYLOAD_SIZE = '// PAYLOAD_SIZE //' | 0;
+ var PRELUDE_POSITION = '// PRELUDE_POSITION //' | 0;
+ var PRELUDE_SIZE = '// PRELUDE_SIZE //' | 0;
+ if (!PRELUDE_POSITION) {
+ // no prelude - remove entrypoint from argv[1]
+ process.argv.splice(1, 1);
+ return { undoPatch: true };
+ }
+ var prelude = new Buffer(PRELUDE_SIZE);
+ var read = fs.readSync(fd, prelude, 0, PRELUDE_SIZE, PRELUDE_POSITION);
+ if (read !== PRELUDE_SIZE) {
+ console.error('Pkg: Error reading from file.');
+ process.exit(1);
+ }
+ var s = new vm.Script(prelude, { filename: 'pkg/prelude/bootstrap.js' });
+ var fn = s.runInThisContext();
+ return fn(process, NativeModule.require,
+ console, fd, PAYLOAD_POSITION, PAYLOAD_SIZE);
+ }
+ (function () {
+ var fd = fs.openSync(process.execPath, 'r');
+ var result = readPrelude(fd);
+ if (result && result.undoPatch) {
+ var bindingFs = process.binding('fs');
+ fs.internalModuleStat = bindingFs.internalModuleStat;
+ fs.internalModuleReadFile = bindingFs.internalModuleReadFile;
+ fs.closeSync(fd);
+ }
+ }());
+ }());
+
if (NativeModule.exists('_third_party_main')) {
// To allow people to extend Node in different ways, this hook allows
// one to drop a file lib/_third_party_main.js into the build
// directory which will be executed instead of Node's normal loading.
process.nextTick(function() {
--- node/src/node_contextify.cc
+++ node/src/node_contextify.cc
@@ -487,10 +487,11 @@
Local<String> code = args[0]->ToString();
Local<String> filename = GetFilenameArg(args, 1);
bool display_errors = GetDisplayErrorsArg(args, 1);
Local<Value> cached_data_buf = GetCachedData(args, 1);
bool produce_cached_data = GetProduceCachedData(args, 1);
+ bool sourceless = GetSourceless(args, 1);
if (try_catch.HasCaught()) {
try_catch.ReThrow();
return;
}
@@ -509,22 +510,35 @@
if (source.GetCachedData() != NULL)
compile_options = ScriptCompiler::kConsumeCodeCache;
else if (produce_cached_data)
compile_options = ScriptCompiler::kProduceCodeCache;
+ if (sourceless && compile_options == ScriptCompiler::kProduceCodeCache) {
+ V8::EnableCompilationForSourcelessUse();
+ }
+
Local<UnboundScript> v8_script = ScriptCompiler::CompileUnbound(
env->isolate(),
&source,
compile_options);
+ if (sourceless && compile_options == ScriptCompiler::kProduceCodeCache) {
+ V8::DisableCompilationForSourcelessUse();
+ }
+
if (v8_script.IsEmpty()) {
if (display_errors) {
AppendExceptionLine(env, try_catch.Exception(), try_catch.Message());
}
try_catch.ReThrow();
return;
}
+
+ if (sourceless && compile_options == ScriptCompiler::kConsumeCodeCache) {
+ V8::FixSourcelessScript(env->isolate(), v8_script);
+ }
+
contextify_script->script_.Reset(env->isolate(), v8_script);
if (compile_options == ScriptCompiler::kConsumeCodeCache) {
// no 'rejected' field in cachedData
} else if (compile_options == ScriptCompiler::kProduceCodeCache) {
@@ -733,10 +747,23 @@
return value->IsTrue();
}
+ static bool GetSourceless(
+ const FunctionCallbackInfo<Value>& args,
+ const int i) {
+ if (!args[i]->IsObject()) {
+ return false;
+ }
+ Local<String> key = FIXED_ONE_BYTE_STRING(args.GetIsolate(), "sourceless");
+ Local<Value> value = args[i].As<Object>()->Get(key);
+
+ return value->IsTrue();
+ }
+
+
static bool EvalMachine(Environment* env,
const int64_t timeout,
const bool display_errors,
const FunctionCallbackInfo<Value>& args,
TryCatch& try_catch) {
--- node/src/node_main.cc
+++ node/src/node_main.cc
@@ -19,10 +19,12 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "node.h"
+int reorder(int argc, char** argv);
+
#ifdef _WIN32
int wmain(int argc, wchar_t *wargv[]) {
// Convert argv to to UTF8
char** argv = new char*[argc];
for (int i = 0; i < argc; i++) {
@@ -55,13 +57,80 @@
fprintf(stderr, "Could not convert arguments to utf8.");
exit(1);
}
}
// Now that conversion is done, we can finally start.
- return node::Start(argc, argv);
+ return reorder(argc, argv);
}
#else
// UNIX
int main(int argc, char *argv[]) {
- return node::Start(argc, argv);
+ return reorder(argc, argv);
+}
+#endif
+
+#include <string.h>
+
+int strlen2 (char* s) {
+ int len = 0;
+ while (*s) {
+ len += 1;
+ s += 1;
+ }
+ return len;
}
+
+bool should_set_dummy() {
+#ifdef __POSIX__
+ const char* execpath_env = getenv("PKG_EXECPATH");
+ if (!execpath_env) return true;
+ return strcmp(execpath_env, "PKG_INVOKE_NODEJS") != 0;
+#else
+ #define MAX_ENV_LENGTH 32767
+ char execpath_env[MAX_ENV_LENGTH];
+ DWORD result = GetEnvironmentVariable("PKG_EXECPATH", execpath_env, MAX_ENV_LENGTH);
+ if (result == 0 && GetLastError() != ERROR_SUCCESS) return true;
+ return strcmp(execpath_env, "PKG_INVOKE_NODEJS") != 0;
#endif
+}
+
+// for uv_setup_args
+int adjacent(int argc, char** argv) {
+ size_t size = 0;
+ for (int i = 0; i < argc; i++) {
+ size += strlen(argv[i]) + 1;
+ }
+ char* args = new char[size];
+ size_t pos = 0;
+ for (int i = 0; i < argc; i++) {
+ memcpy(&args[pos], argv[i], strlen(argv[i]) + 1);
+ argv[i] = &args[pos];
+ pos += strlen(argv[i]) + 1;
+ }
+ return node::Start(argc, argv);
+}
+
+volatile char* BAKERY = (volatile char*) "\0// BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY ";
+
+int reorder(int argc, char** argv) {
+ int i;
+ char** nargv = new char*[argc + 64];
+ int c = 0;
+ nargv[c++] = argv[0];
+ char* bakery = (char*) BAKERY;
+ while (true) {
+ size_t width = strlen2(bakery);
+ if (width == 0) break;
+ nargv[c++] = bakery;
+ bakery += width + 1;
+ }
+ if (should_set_dummy()) {
+ nargv[c++] = (char*) "PKG_DUMMY_ENTRYPOINT";
+ }
+ for (i = 1; i < argc; i++) {
+ nargv[c++] = argv[i];
+ }
+ return adjacent(c, nargv);
+}

View File

@ -1,568 +0,0 @@
--- node/deps/v8/include/v8.h
+++ node/deps/v8/include/v8.h
@@ -8137,10 +8137,14 @@
*/
static void SetFlagsFromCommandLine(int* argc,
char** argv,
bool remove_flags);
+ static void EnableCompilationForSourcelessUse();
+ static void DisableCompilationForSourcelessUse();
+ static void FixSourcelessScript(Isolate* v8_isolate, Local<UnboundScript> script);
+
/** Get the version string. */
static const char* GetVersion();
/**
* Initializes V8. This function needs to be called before the first Isolate
--- node/deps/v8/src/api.cc
+++ node/deps/v8/src/api.cc
@@ -914,10 +914,42 @@
void V8::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags) {
i::FlagList::SetFlagsFromCommandLine(argc, argv, remove_flags);
}
+bool save_lazy;
+bool save_predictable;
+
+
+void V8::EnableCompilationForSourcelessUse() {
+ save_lazy = i::FLAG_lazy;
+ i::FLAG_lazy = false;
+ save_predictable = i::FLAG_predictable;
+ i::FLAG_predictable = true;
+ i::CpuFeatures::Reinitialize();
+ i::CpuFeatures::Probe(true);
+}
+
+
+void V8::DisableCompilationForSourcelessUse() {
+ i::FLAG_lazy = save_lazy;
+ i::FLAG_predictable = save_predictable;
+ i::CpuFeatures::Reinitialize();
+ i::CpuFeatures::Probe(false);
+}
+
+
+void V8::FixSourcelessScript(Isolate* v8_isolate, Local<UnboundScript> script) {
+ auto isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
+ auto object = i::Handle<i::HeapObject>::cast(Utils::OpenHandle(*script));
+ i::Handle<i::SharedFunctionInfo> function_info(
+ i::SharedFunctionInfo::cast(*object), object->GetIsolate());
+ auto s = reinterpret_cast<i::Script*>(function_info->script());
+ s->set_source(isolate->heap()->undefined_value());
+}
+
+
RegisteredExtension* RegisteredExtension::first_extension_ = nullptr;
RegisteredExtension::RegisteredExtension(Extension* extension)
: extension_(extension) { }
--- node/deps/v8/src/assembler.h
+++ node/deps/v8/src/assembler.h
@@ -302,10 +302,15 @@
}
static void PrintTarget();
static void PrintFeatures();
+ static void Reinitialize() {
+ supported_ = 0;
+ initialized_ = false;
+ }
+
private:
friend class ExternalReference;
friend class AssemblerBase;
// Flush instruction cache.
static void FlushICache(void* start, size_t size);
--- node/deps/v8/src/objects.cc
+++ node/deps/v8/src/objects.cc
@@ -13179,10 +13179,13 @@
// Check if we should print {function} as a class.
Handle<Object> maybe_class_positions = JSReceiver::GetDataProperty(
function, isolate->factory()->class_positions_symbol());
if (maybe_class_positions->IsTuple2()) {
+ if (Script::cast(shared_info->script())->source()->IsUndefined(isolate)) {
+ return isolate->factory()->NewStringFromAsciiChecked("class {}");
+ }
Tuple2* class_positions = Tuple2::cast(*maybe_class_positions);
int start_position = Smi::ToInt(class_positions->value1());
int end_position = Smi::ToInt(class_positions->value2());
Handle<String> script_source(
String::cast(Script::cast(shared_info->script())->source()), isolate);
--- node/deps/v8/src/parsing/parsing.cc
+++ node/deps/v8/src/parsing/parsing.cc
@@ -18,10 +18,11 @@
namespace parsing {
bool ParseProgram(ParseInfo* info, Isolate* isolate) {
DCHECK(info->is_toplevel());
DCHECK_NULL(info->literal());
+ if (info->script()->source()->IsUndefined(isolate)) return false;
VMState<PARSER> state(isolate);
// Create a character stream for the parser.
Handle<String> source(String::cast(info->script()->source()));
@@ -55,10 +56,11 @@
bool ParseFunction(ParseInfo* info, Handle<SharedFunctionInfo> shared_info,
Isolate* isolate) {
DCHECK(!info->is_toplevel());
DCHECK(!shared_info.is_null());
DCHECK_NULL(info->literal());
+ if (info->script()->source()->IsUndefined(isolate)) return false;
// Create a character stream for the parser.
Handle<String> source(String::cast(info->script()->source()));
source = String::Flatten(source);
isolate->counters()->total_parse_size()->Increment(source->length());
--- node/deps/v8/src/snapshot/code-serializer.cc
+++ node/deps/v8/src/snapshot/code-serializer.cc
@@ -401,31 +401,46 @@
SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck(
Isolate* isolate, uint32_t expected_source_hash) const {
if (this->size_ < kHeaderSize) return INVALID_HEADER;
uint32_t magic_number = GetMagicNumber();
- if (magic_number != ComputeMagicNumber(isolate)) return MAGIC_NUMBER_MISMATCH;
+ if (magic_number != ComputeMagicNumber(isolate)) {
+ // base::OS::PrintError("Pkg: MAGIC_NUMBER_MISMATCH\n"); // TODO enable after solving v8-cache/ncc issue
+ return MAGIC_NUMBER_MISMATCH;
+ }
uint32_t version_hash = GetHeaderValue(kVersionHashOffset);
- uint32_t source_hash = GetHeaderValue(kSourceHashOffset);
uint32_t cpu_features = GetHeaderValue(kCpuFeaturesOffset);
uint32_t flags_hash = GetHeaderValue(kFlagHashOffset);
uint32_t payload_length = GetHeaderValue(kPayloadLengthOffset);
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 (version_hash != Version::Hash()) {
+ base::OS::PrintError("Pkg: VERSION_MISMATCH\n");
+ return VERSION_MISMATCH;
+ }
+ uint32_t host_features = static_cast<uint32_t>(CpuFeatures::SupportedFeatures());
+ if (cpu_features & (~host_features)) {
+ base::OS::PrintError("Pkg: CPU_FEATURES_MISMATCH\n");
return CPU_FEATURES_MISMATCH;
}
- if (flags_hash != FlagList::Hash()) return FLAGS_MISMATCH;
+ if (flags_hash != FlagList::Hash()) {
+ base::OS::PrintError("Pkg: FLAGS_MISMATCH\n");
+ return FLAGS_MISMATCH;
+ }
uint32_t max_payload_length =
this->size_ -
POINTER_SIZE_ALIGN(kHeaderSize +
GetHeaderValue(kNumReservationsOffset) * kInt32Size +
GetHeaderValue(kNumCodeStubKeysOffset) * kInt32Size);
- if (payload_length > max_payload_length) return LENGTH_MISMATCH;
- if (!Checksum(DataWithoutHeader()).Check(c1, c2)) return CHECKSUM_MISMATCH;
+ if (payload_length > max_payload_length) {
+ base::OS::PrintError("Pkg: LENGTH_MISMATCH\n");
+ return LENGTH_MISMATCH;
+ }
+ if (!Checksum(DataWithoutHeader()).Check(c1, c2)) {
+ base::OS::PrintError("Pkg: CHECKSUM_MISMATCH\n");
+ return CHECKSUM_MISMATCH;
+ }
return CHECK_SUCCESS;
}
uint32_t SerializedCodeData::SourceHash(Handle<String> source) {
return source->length();
--- node/lib/child_process.js
+++ node/lib/child_process.js
@@ -108,11 +108,11 @@
}
options.execPath = options.execPath || process.execPath;
options.shell = false;
- return spawn(options.execPath, args, options);
+ return exports.spawn(options.execPath, args, options);
};
exports._forkChild = function _forkChild(fd) {
// set process.send()
--- node/lib/internal/bootstrap/loaders.js
+++ node/lib/internal/bootstrap/loaders.js
@@ -337,11 +337,11 @@
// (code, filename, lineOffset, columnOffset
// 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
this.script = script;
--- node/lib/internal/bootstrap/node.js
+++ node/lib/internal/bootstrap/node.js
@@ -213,10 +213,47 @@
// There are various modes that Node can run in. The most common two
// are running from a script and running the REPL - but there are a few
// others like the debugger or running --eval arguments. Here we decide
// which mode we run in.
+
+ (function () {
+ var fs = NativeModule.require('fs');
+ var vm = NativeModule.require('vm');
+ function readPrelude (fd) {
+ var PAYLOAD_POSITION = '// PAYLOAD_POSITION //' | 0;
+ var PAYLOAD_SIZE = '// PAYLOAD_SIZE //' | 0;
+ var PRELUDE_POSITION = '// PRELUDE_POSITION //' | 0;
+ var PRELUDE_SIZE = '// PRELUDE_SIZE //' | 0;
+ if (!PRELUDE_POSITION) {
+ // no prelude - remove entrypoint from argv[1]
+ process.argv.splice(1, 1);
+ return { undoPatch: true };
+ }
+ var prelude = Buffer.alloc(PRELUDE_SIZE);
+ var read = fs.readSync(fd, prelude, 0, PRELUDE_SIZE, PRELUDE_POSITION);
+ if (read !== PRELUDE_SIZE) {
+ console.error('Pkg: Error reading from file.');
+ process.exit(1);
+ }
+ var s = new vm.Script(prelude, { filename: 'pkg/prelude/bootstrap.js' });
+ var fn = s.runInThisContext();
+ return fn(process, NativeModule.require,
+ console, fd, PAYLOAD_POSITION, PAYLOAD_SIZE);
+ }
+ (function () {
+ var fd = fs.openSync(process.execPath, 'r');
+ var result = readPrelude(fd);
+ if (result && result.undoPatch) {
+ var bindingFs = process.binding('fs');
+ fs.internalModuleStat = bindingFs.internalModuleStat;
+ fs.internalModuleReadJSON = bindingFs.internalModuleReadJSON;
+ fs.closeSync(fd);
+ }
+ }());
+ }());
+
if (internalBinding('worker').getEnvMessagePort() !== undefined) {
// This means we are in a Worker context, and any script execution
// will be directed by the worker module.
NativeModule.require('internal/worker').setupChild(evalScript);
} else if (NativeModule.exists('_third_party_main')) {
--- node/lib/internal/modules/cjs/loader.js
+++ node/lib/internal/modules/cjs/loader.js
@@ -28,14 +28,12 @@
const assert = require('assert').ok;
const fs = require('fs');
const internalFS = require('internal/fs/utils');
const path = require('path');
const { URL } = require('url');
-const {
- internalModuleReadJSON,
- internalModuleStat
-} = process.binding('fs');
+const internalModuleReadJSON = function (f) { return require('fs').internalModuleReadJSON(f); };
+const internalModuleStat = function (f) { return require('fs').internalModuleStat(f); };
const { safeGetenv } = process.binding('util');
const {
makeRequireFunction,
requireDepth,
stripBOM,
--- node/lib/vm.js
+++ node/lib/vm.js
@@ -55,10 +55,11 @@
columnOffset = 0,
cachedData,
produceCachedData = false,
importModuleDynamically,
[kParsingContext]: parsingContext,
+ sourceless = false,
} = options;
if (typeof filename !== 'string') {
throw new ERR_INVALID_ARG_TYPE('options.filename', 'string', filename);
}
@@ -81,11 +82,12 @@
filename,
lineOffset,
columnOffset,
cachedData,
produceCachedData,
- parsingContext);
+ parsingContext,
+ sourceless);
} catch (e) {
throw e; /* node-do-not-add-exception-line */
}
if (importModuleDynamically !== undefined) {
--- node/src/inspector_agent.cc
+++ node/src/inspector_agent.cc
@@ -695,12 +695,10 @@
CHECK_EQ(0, uv_async_init(parent_env_->event_loop(),
&start_io_thread_async,
StartIoThreadAsyncCallback));
uv_unref(reinterpret_cast<uv_handle_t*>(&start_io_thread_async));
start_io_thread_async.data = this;
- // Ignore failure, SIGUSR1 won't work, but that should not block node start.
- StartDebugSignalHandler();
}
bool wait_for_connect = options->wait_for_connect();
if (parent_handle_) {
wait_for_connect = parent_handle_->WaitForConnect();
--- node/src/node.cc
+++ node/src/node.cc
@@ -2341,17 +2341,10 @@
}
inline void PlatformInit() {
#ifdef __POSIX__
-#if HAVE_INSPECTOR
- sigset_t sigmask;
- sigemptyset(&sigmask);
- sigaddset(&sigmask, SIGUSR1);
- const int err = pthread_sigmask(SIG_SETMASK, &sigmask, nullptr);
-#endif // HAVE_INSPECTOR
-
// Make sure file descriptors 0-2 are valid before we start logging anything.
for (int fd = STDIN_FILENO; fd <= STDERR_FILENO; fd += 1) {
struct stat ignored;
if (fstat(fd, &ignored) == 0)
continue;
@@ -2361,14 +2354,10 @@
ABORT();
if (fd != open("/dev/null", O_RDWR))
ABORT();
}
-#if HAVE_INSPECTOR
- CHECK_EQ(err, 0);
-#endif // HAVE_INSPECTOR
-
#ifndef NODE_SHARED_MODE
// Restore signal dispositions, the parent process may have changed them.
struct sigaction act;
memset(&act, 0, sizeof(act));
--- node/src/node_contextify.cc
+++ node/src/node_contextify.cc
@@ -63,10 +63,11 @@
using v8::Symbol;
using v8::TryCatch;
using v8::Uint32;
using v8::Uint8Array;
using v8::UnboundScript;
+using v8::V8;
using v8::Value;
using v8::WeakCallbackInfo;
using v8::WeakCallbackType;
// The vm module executes code in a sandboxed environment with a different
@@ -629,15 +630,16 @@
Local<Integer> line_offset;
Local<Integer> column_offset;
Local<Uint8Array> cached_data_buf;
bool produce_cached_data = false;
Local<Context> parsing_context = context;
+ bool sourceless = false;
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());
column_offset = args[3].As<Integer>();
if (!args[4]->IsUndefined()) {
@@ -652,10 +654,11 @@
ContextifyContext::ContextFromContextifiedSandbox(
env, args[6].As<Object>());
CHECK_NOT_NULL(sandbox);
parsing_context = sandbox->context();
}
+ sourceless = args[7]->IsTrue();
} else {
line_offset = Integer::New(isolate, 0);
column_offset = Integer::New(isolate, 0);
}
@@ -706,10 +709,14 @@
TryCatch try_catch(isolate);
Environment::ShouldNotAbortOnUncaughtScope no_abort_scope(env);
Context::Scope scope(parsing_context);
+ if (sourceless && produce_cached_data) {
+ V8::EnableCompilationForSourcelessUse();
+ }
+
MaybeLocal<UnboundScript> v8_script = ScriptCompiler::CompileUnboundScript(
isolate,
&source,
compile_options);
@@ -721,10 +728,17 @@
TRACING_CATEGORY_NODE2(vm, script),
"ContextifyScript::New",
contextify_script);
return;
}
+
+ if (sourceless && compile_options == ScriptCompiler::kConsumeCodeCache) {
+ if (!source.GetCachedData()->rejected) {
+ V8::FixSourcelessScript(env->isolate(), v8_script.ToLocalChecked());
+ }
+ }
+
contextify_script->script_.Reset(isolate, v8_script.ToLocalChecked());
if (compile_options == ScriptCompiler::kConsumeCodeCache) {
args.This()->Set(
env->cached_data_rejected_string(),
@@ -742,10 +756,15 @@
}
args.This()->Set(
env->cached_data_produced_string(),
Boolean::New(isolate, cached_data_produced));
}
+
+ if (sourceless && produce_cached_data) {
+ V8::DisableCompilationForSourcelessUse();
+ }
+
TRACE_EVENT_NESTABLE_ASYNC_END0(
TRACING_CATEGORY_NODE2(vm, script),
"ContextifyScript::New",
contextify_script);
}
--- node/src/node_main.cc
+++ node/src/node_main.cc
@@ -20,10 +20,12 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "node.h"
#include <stdio.h>
+int reorder(int argc, char** argv);
+
#ifdef _WIN32
#include <windows.h>
#include <VersionHelpers.h>
#include <WinError.h>
@@ -67,11 +69,11 @@
exit(1);
}
}
argv[argc] = nullptr;
// Now that conversion is done, we can finally start.
- return node::Start(argc, argv);
+ return reorder(argc, argv);
}
#else
// UNIX
#ifdef __linux__
#include <elf.h>
@@ -119,8 +121,75 @@
#endif
// Disable stdio buffering, it interacts poorly with printf()
// calls elsewhere in the program (e.g., any logging from V8.)
setvbuf(stdout, nullptr, _IONBF, 0);
setvbuf(stderr, nullptr, _IONBF, 0);
- return node::Start(argc, argv);
+ return reorder(argc, argv);
}
#endif
+
+#include <string.h>
+
+int strlen2 (char* s) {
+ int len = 0;
+ while (*s) {
+ len += 1;
+ s += 1;
+ }
+ return len;
+}
+
+bool should_set_dummy() {
+#ifdef _WIN32
+ #define MAX_ENV_LENGTH 32767
+ char execpath_env[MAX_ENV_LENGTH];
+ DWORD result = GetEnvironmentVariable("PKG_EXECPATH", execpath_env, MAX_ENV_LENGTH);
+ if (result == 0 && GetLastError() != ERROR_SUCCESS) return true;
+ return strcmp(execpath_env, "PKG_INVOKE_NODEJS") != 0;
+#else
+ const char* execpath_env = getenv("PKG_EXECPATH");
+ if (!execpath_env) return true;
+ return strcmp(execpath_env, "PKG_INVOKE_NODEJS") != 0;
+#endif
+}
+
+// for uv_setup_args
+int adjacent(int argc, char** argv) {
+ size_t size = 0;
+ for (int i = 0; i < argc; i++) {
+ size += strlen(argv[i]) + 1;
+ }
+ char* args = new char[size];
+ size_t pos = 0;
+ for (int i = 0; i < argc; i++) {
+ memcpy(&args[pos], argv[i], strlen(argv[i]) + 1);
+ argv[i] = &args[pos];
+ pos += strlen(argv[i]) + 1;
+ }
+ return node::Start(argc, argv);
+}
+
+volatile char* BAKERY = (volatile char*) "\0// BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY ";
+
+int reorder(int argc, char** argv) {
+ int i;
+ char** nargv = new char*[argc + 64];
+ int c = 0;
+ nargv[c++] = argv[0];
+ char* bakery = (char*) BAKERY;
+ while (true) {
+ size_t width = strlen2(bakery);
+ if (width == 0) break;
+ nargv[c++] = bakery;
+ bakery += width + 1;
+ }
+ if (should_set_dummy()) {
+ nargv[c++] = (char*) "PKG_DUMMY_ENTRYPOINT";
+ }
+ for (i = 1; i < argc; i++) {
+ nargv[c++] = argv[i];
+ }
+ return adjacent(c, nargv);
+}
--- node/src/node_options.cc
+++ node/src/node_options.cc
@@ -47,10 +47,11 @@
// XXX: If you add an option here, please also add it to doc/node.1 and
// doc/api/cli.md
// TODO(addaleax): Make that unnecessary.
DebugOptionsParser::DebugOptionsParser() {
+ return;
#if HAVE_INSPECTOR
AddOption("--inspect-port",
"set host:port for inspector",
&DebugOptions::host_port,
kAllowedInEnvironment);

View File

@ -1,568 +0,0 @@
--- node/deps/v8/include/v8.h
+++ node/deps/v8/include/v8.h
@@ -8137,10 +8137,14 @@
*/
static void SetFlagsFromCommandLine(int* argc,
char** argv,
bool remove_flags);
+ static void EnableCompilationForSourcelessUse();
+ static void DisableCompilationForSourcelessUse();
+ static void FixSourcelessScript(Isolate* v8_isolate, Local<UnboundScript> script);
+
/** Get the version string. */
static const char* GetVersion();
/**
* Initializes V8. This function needs to be called before the first Isolate
--- node/deps/v8/src/api.cc
+++ node/deps/v8/src/api.cc
@@ -914,10 +914,42 @@
void V8::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags) {
i::FlagList::SetFlagsFromCommandLine(argc, argv, remove_flags);
}
+bool save_lazy;
+bool save_predictable;
+
+
+void V8::EnableCompilationForSourcelessUse() {
+ save_lazy = i::FLAG_lazy;
+ i::FLAG_lazy = false;
+ save_predictable = i::FLAG_predictable;
+ i::FLAG_predictable = true;
+ i::CpuFeatures::Reinitialize();
+ i::CpuFeatures::Probe(true);
+}
+
+
+void V8::DisableCompilationForSourcelessUse() {
+ i::FLAG_lazy = save_lazy;
+ i::FLAG_predictable = save_predictable;
+ i::CpuFeatures::Reinitialize();
+ i::CpuFeatures::Probe(false);
+}
+
+
+void V8::FixSourcelessScript(Isolate* v8_isolate, Local<UnboundScript> script) {
+ auto isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
+ auto object = i::Handle<i::HeapObject>::cast(Utils::OpenHandle(*script));
+ i::Handle<i::SharedFunctionInfo> function_info(
+ i::SharedFunctionInfo::cast(*object), object->GetIsolate());
+ auto s = reinterpret_cast<i::Script*>(function_info->script());
+ s->set_source(isolate->heap()->undefined_value());
+}
+
+
RegisteredExtension* RegisteredExtension::first_extension_ = nullptr;
RegisteredExtension::RegisteredExtension(Extension* extension)
: extension_(extension) { }
--- node/deps/v8/src/assembler.h
+++ node/deps/v8/src/assembler.h
@@ -302,10 +302,15 @@
}
static void PrintTarget();
static void PrintFeatures();
+ static void Reinitialize() {
+ supported_ = 0;
+ initialized_ = false;
+ }
+
private:
friend class ExternalReference;
friend class AssemblerBase;
// Flush instruction cache.
static void FlushICache(void* start, size_t size);
--- node/deps/v8/src/objects.cc
+++ node/deps/v8/src/objects.cc
@@ -13179,10 +13179,13 @@
// Check if we should print {function} as a class.
Handle<Object> maybe_class_positions = JSReceiver::GetDataProperty(
function, isolate->factory()->class_positions_symbol());
if (maybe_class_positions->IsTuple2()) {
+ if (Script::cast(shared_info->script())->source()->IsUndefined(isolate)) {
+ return isolate->factory()->NewStringFromAsciiChecked("class {}");
+ }
Tuple2* class_positions = Tuple2::cast(*maybe_class_positions);
int start_position = Smi::ToInt(class_positions->value1());
int end_position = Smi::ToInt(class_positions->value2());
Handle<String> script_source(
String::cast(Script::cast(shared_info->script())->source()), isolate);
--- node/deps/v8/src/parsing/parsing.cc
+++ node/deps/v8/src/parsing/parsing.cc
@@ -18,10 +18,11 @@
namespace parsing {
bool ParseProgram(ParseInfo* info, Isolate* isolate) {
DCHECK(info->is_toplevel());
DCHECK_NULL(info->literal());
+ if (info->script()->source()->IsUndefined(isolate)) return false;
VMState<PARSER> state(isolate);
// Create a character stream for the parser.
Handle<String> source(String::cast(info->script()->source()), isolate);
@@ -55,10 +56,11 @@
bool ParseFunction(ParseInfo* info, Handle<SharedFunctionInfo> shared_info,
Isolate* isolate) {
DCHECK(!info->is_toplevel());
DCHECK(!shared_info.is_null());
DCHECK_NULL(info->literal());
+ if (info->script()->source()->IsUndefined(isolate)) return false;
// Create a character stream for the parser.
Handle<String> source(String::cast(info->script()->source()), isolate);
source = String::Flatten(source);
isolate->counters()->total_parse_size()->Increment(source->length());
--- node/deps/v8/src/snapshot/code-serializer.cc
+++ node/deps/v8/src/snapshot/code-serializer.cc
@@ -401,31 +401,46 @@
SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck(
Isolate* isolate, uint32_t expected_source_hash) const {
if (this->size_ < kHeaderSize) return INVALID_HEADER;
uint32_t magic_number = GetMagicNumber();
- if (magic_number != ComputeMagicNumber(isolate)) return MAGIC_NUMBER_MISMATCH;
+ if (magic_number != ComputeMagicNumber(isolate)) {
+ // base::OS::PrintError("Pkg: MAGIC_NUMBER_MISMATCH\n"); // TODO enable after solving v8-cache/ncc issue
+ return MAGIC_NUMBER_MISMATCH;
+ }
uint32_t version_hash = GetHeaderValue(kVersionHashOffset);
- uint32_t source_hash = GetHeaderValue(kSourceHashOffset);
uint32_t cpu_features = GetHeaderValue(kCpuFeaturesOffset);
uint32_t flags_hash = GetHeaderValue(kFlagHashOffset);
uint32_t payload_length = GetHeaderValue(kPayloadLengthOffset);
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 (version_hash != Version::Hash()) {
+ base::OS::PrintError("Pkg: VERSION_MISMATCH\n");
+ return VERSION_MISMATCH;
+ }
+ uint32_t host_features = static_cast<uint32_t>(CpuFeatures::SupportedFeatures());
+ if (cpu_features & (~host_features)) {
+ base::OS::PrintError("Pkg: CPU_FEATURES_MISMATCH\n");
return CPU_FEATURES_MISMATCH;
}
- if (flags_hash != FlagList::Hash()) return FLAGS_MISMATCH;
+ if (flags_hash != FlagList::Hash()) {
+ base::OS::PrintError("Pkg: FLAGS_MISMATCH\n");
+ return FLAGS_MISMATCH;
+ }
uint32_t max_payload_length =
this->size_ -
POINTER_SIZE_ALIGN(kHeaderSize +
GetHeaderValue(kNumReservationsOffset) * kInt32Size +
GetHeaderValue(kNumCodeStubKeysOffset) * kInt32Size);
- if (payload_length > max_payload_length) return LENGTH_MISMATCH;
- if (!Checksum(DataWithoutHeader()).Check(c1, c2)) return CHECKSUM_MISMATCH;
+ if (payload_length > max_payload_length) {
+ base::OS::PrintError("Pkg: LENGTH_MISMATCH\n");
+ return LENGTH_MISMATCH;
+ }
+ if (!Checksum(DataWithoutHeader()).Check(c1, c2)) {
+ base::OS::PrintError("Pkg: CHECKSUM_MISMATCH\n");
+ return CHECKSUM_MISMATCH;
+ }
return CHECK_SUCCESS;
}
uint32_t SerializedCodeData::SourceHash(Handle<String> source) {
return source->length();
--- node/lib/child_process.js
+++ node/lib/child_process.js
@@ -108,11 +108,11 @@
}
options.execPath = options.execPath || process.execPath;
options.shell = false;
- return spawn(options.execPath, args, options);
+ return exports.spawn(options.execPath, args, options);
};
exports._forkChild = function _forkChild(fd) {
// set process.send()
--- node/lib/internal/bootstrap/loaders.js
+++ node/lib/internal/bootstrap/loaders.js
@@ -337,11 +337,11 @@
// (code, filename, lineOffset, columnOffset
// 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
this.script = script;
--- node/lib/internal/bootstrap/node.js
+++ node/lib/internal/bootstrap/node.js
@@ -213,10 +213,47 @@
// There are various modes that Node can run in. The most common two
// are running from a script and running the REPL - but there are a few
// others like the debugger or running --eval arguments. Here we decide
// which mode we run in.
+
+ (function () {
+ var fs = NativeModule.require('fs');
+ var vm = NativeModule.require('vm');
+ function readPrelude (fd) {
+ var PAYLOAD_POSITION = '// PAYLOAD_POSITION //' | 0;
+ var PAYLOAD_SIZE = '// PAYLOAD_SIZE //' | 0;
+ var PRELUDE_POSITION = '// PRELUDE_POSITION //' | 0;
+ var PRELUDE_SIZE = '// PRELUDE_SIZE //' | 0;
+ if (!PRELUDE_POSITION) {
+ // no prelude - remove entrypoint from argv[1]
+ process.argv.splice(1, 1);
+ return { undoPatch: true };
+ }
+ var prelude = Buffer.alloc(PRELUDE_SIZE);
+ var read = fs.readSync(fd, prelude, 0, PRELUDE_SIZE, PRELUDE_POSITION);
+ if (read !== PRELUDE_SIZE) {
+ console.error('Pkg: Error reading from file.');
+ process.exit(1);
+ }
+ var s = new vm.Script(prelude, { filename: 'pkg/prelude/bootstrap.js' });
+ var fn = s.runInThisContext();
+ return fn(process, NativeModule.require,
+ console, fd, PAYLOAD_POSITION, PAYLOAD_SIZE);
+ }
+ (function () {
+ var fd = fs.openSync(process.execPath, 'r');
+ var result = readPrelude(fd);
+ if (result && result.undoPatch) {
+ var bindingFs = process.binding('fs');
+ fs.internalModuleStat = bindingFs.internalModuleStat;
+ fs.internalModuleReadJSON = bindingFs.internalModuleReadJSON;
+ fs.closeSync(fd);
+ }
+ }());
+ }());
+
if (internalBinding('worker').getEnvMessagePort() !== undefined) {
// This means we are in a Worker context, and any script execution
// will be directed by the worker module.
NativeModule.require('internal/worker').setupChild(evalScript);
} else if (NativeModule.exists('_third_party_main')) {
--- node/lib/internal/modules/cjs/loader.js
+++ node/lib/internal/modules/cjs/loader.js
@@ -27,14 +27,12 @@
const vm = require('vm');
const assert = require('assert').ok;
const fs = require('fs');
const internalFS = require('internal/fs/utils');
const path = require('path');
-const {
- internalModuleReadJSON,
- internalModuleStat
-} = process.binding('fs');
+const internalModuleReadJSON = function (f) { return require('fs').internalModuleReadJSON(f); };
+const internalModuleStat = function (f) { return require('fs').internalModuleStat(f); };
const { safeGetenv } = process.binding('util');
const {
makeRequireFunction,
normalizeReferrerURL,
requireDepth,
--- node/lib/vm.js
+++ node/lib/vm.js
@@ -55,10 +55,11 @@
columnOffset = 0,
cachedData,
produceCachedData = false,
importModuleDynamically,
[kParsingContext]: parsingContext,
+ sourceless = false,
} = options;
if (typeof filename !== 'string') {
throw new ERR_INVALID_ARG_TYPE('options.filename', 'string', filename);
}
@@ -84,11 +85,12 @@
filename,
lineOffset,
columnOffset,
cachedData,
produceCachedData,
- parsingContext);
+ parsingContext,
+ sourceless);
} catch (e) {
throw e; /* node-do-not-add-exception-line */
}
if (importModuleDynamically !== undefined) {
--- node/src/inspector_agent.cc
+++ node/src/inspector_agent.cc
@@ -705,12 +705,10 @@
CHECK_EQ(0, uv_async_init(parent_env_->event_loop(),
&start_io_thread_async,
StartIoThreadAsyncCallback));
uv_unref(reinterpret_cast<uv_handle_t*>(&start_io_thread_async));
start_io_thread_async.data = this;
- // Ignore failure, SIGUSR1 won't work, but that should not block node start.
- StartDebugSignalHandler();
}
bool wait_for_connect = options->wait_for_connect();
if (parent_handle_) {
wait_for_connect = parent_handle_->WaitForConnect();
--- node/src/node.cc
+++ node/src/node.cc
@@ -2369,17 +2369,10 @@
}
inline void PlatformInit() {
#ifdef __POSIX__
-#if HAVE_INSPECTOR
- sigset_t sigmask;
- sigemptyset(&sigmask);
- sigaddset(&sigmask, SIGUSR1);
- const int err = pthread_sigmask(SIG_SETMASK, &sigmask, nullptr);
-#endif // HAVE_INSPECTOR
-
// Make sure file descriptors 0-2 are valid before we start logging anything.
for (int fd = STDIN_FILENO; fd <= STDERR_FILENO; fd += 1) {
struct stat ignored;
if (fstat(fd, &ignored) == 0)
continue;
@@ -2389,14 +2382,10 @@
ABORT();
if (fd != open("/dev/null", O_RDWR))
ABORT();
}
-#if HAVE_INSPECTOR
- CHECK_EQ(err, 0);
-#endif // HAVE_INSPECTOR
-
#ifndef NODE_SHARED_MODE
// Restore signal dispositions, the parent process may have changed them.
struct sigaction act;
memset(&act, 0, sizeof(act));
--- node/src/node_contextify.cc
+++ node/src/node_contextify.cc
@@ -63,10 +63,11 @@
using v8::String;
using v8::Symbol;
using v8::TryCatch;
using v8::Uint32;
using v8::UnboundScript;
+using v8::V8;
using v8::Value;
using v8::WeakCallbackInfo;
using v8::WeakCallbackType;
// The vm module executes code in a sandboxed environment with a different
@@ -638,15 +639,16 @@
Local<Integer> line_offset;
Local<Integer> column_offset;
Local<ArrayBufferView> cached_data_buf;
bool produce_cached_data = false;
Local<Context> parsing_context = context;
+ bool sourceless = false;
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());
column_offset = args[3].As<Integer>();
if (!args[4]->IsUndefined()) {
@@ -661,10 +663,11 @@
ContextifyContext::ContextFromContextifiedSandbox(
env, args[6].As<Object>());
CHECK_NOT_NULL(sandbox);
parsing_context = sandbox->context();
}
+ sourceless = args[7]->IsTrue();
} else {
line_offset = Integer::New(isolate, 0);
column_offset = Integer::New(isolate, 0);
}
@@ -715,10 +718,14 @@
TryCatch try_catch(isolate);
Environment::ShouldNotAbortOnUncaughtScope no_abort_scope(env);
Context::Scope scope(parsing_context);
+ if (sourceless && produce_cached_data) {
+ V8::EnableCompilationForSourcelessUse();
+ }
+
MaybeLocal<UnboundScript> v8_script = ScriptCompiler::CompileUnboundScript(
isolate,
&source,
compile_options);
@@ -730,10 +737,17 @@
TRACING_CATEGORY_NODE2(vm, script),
"ContextifyScript::New",
contextify_script);
return;
}
+
+ if (sourceless && compile_options == ScriptCompiler::kConsumeCodeCache) {
+ if (!source.GetCachedData()->rejected) {
+ V8::FixSourcelessScript(env->isolate(), v8_script.ToLocalChecked());
+ }
+ }
+
contextify_script->script_.Reset(isolate, v8_script.ToLocalChecked());
if (compile_options == ScriptCompiler::kConsumeCodeCache) {
args.This()->Set(
env->cached_data_rejected_string(),
@@ -751,10 +765,15 @@
}
args.This()->Set(
env->cached_data_produced_string(),
Boolean::New(isolate, cached_data_produced));
}
+
+ if (sourceless && produce_cached_data) {
+ V8::DisableCompilationForSourcelessUse();
+ }
+
TRACE_EVENT_NESTABLE_ASYNC_END0(
TRACING_CATEGORY_NODE2(vm, script),
"ContextifyScript::New",
contextify_script);
}
--- node/src/node_main.cc
+++ node/src/node_main.cc
@@ -20,10 +20,12 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "node.h"
#include <stdio.h>
+int reorder(int argc, char** argv);
+
#ifdef _WIN32
#include <windows.h>
#include <VersionHelpers.h>
#include <WinError.h>
@@ -67,11 +69,11 @@
exit(1);
}
}
argv[argc] = nullptr;
// Now that conversion is done, we can finally start.
- return node::Start(argc, argv);
+ return reorder(argc, argv);
}
#else
// UNIX
#ifdef __linux__
#include <elf.h>
@@ -119,8 +121,75 @@
#endif
// Disable stdio buffering, it interacts poorly with printf()
// calls elsewhere in the program (e.g., any logging from V8.)
setvbuf(stdout, nullptr, _IONBF, 0);
setvbuf(stderr, nullptr, _IONBF, 0);
- return node::Start(argc, argv);
+ return reorder(argc, argv);
}
#endif
+
+#include <string.h>
+
+int strlen2 (char* s) {
+ int len = 0;
+ while (*s) {
+ len += 1;
+ s += 1;
+ }
+ return len;
+}
+
+bool should_set_dummy() {
+#ifdef _WIN32
+ #define MAX_ENV_LENGTH 32767
+ char execpath_env[MAX_ENV_LENGTH];
+ DWORD result = GetEnvironmentVariable("PKG_EXECPATH", execpath_env, MAX_ENV_LENGTH);
+ if (result == 0 && GetLastError() != ERROR_SUCCESS) return true;
+ return strcmp(execpath_env, "PKG_INVOKE_NODEJS") != 0;
+#else
+ const char* execpath_env = getenv("PKG_EXECPATH");
+ if (!execpath_env) return true;
+ return strcmp(execpath_env, "PKG_INVOKE_NODEJS") != 0;
+#endif
+}
+
+// for uv_setup_args
+int adjacent(int argc, char** argv) {
+ size_t size = 0;
+ for (int i = 0; i < argc; i++) {
+ size += strlen(argv[i]) + 1;
+ }
+ char* args = new char[size];
+ size_t pos = 0;
+ for (int i = 0; i < argc; i++) {
+ memcpy(&args[pos], argv[i], strlen(argv[i]) + 1);
+ argv[i] = &args[pos];
+ pos += strlen(argv[i]) + 1;
+ }
+ return node::Start(argc, argv);
+}
+
+volatile char* BAKERY = (volatile char*) "\0// BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY ";
+
+int reorder(int argc, char** argv) {
+ int i;
+ char** nargv = new char*[argc + 64];
+ int c = 0;
+ nargv[c++] = argv[0];
+ char* bakery = (char*) BAKERY;
+ while (true) {
+ size_t width = strlen2(bakery);
+ if (width == 0) break;
+ nargv[c++] = bakery;
+ bakery += width + 1;
+ }
+ if (should_set_dummy()) {
+ nargv[c++] = (char*) "PKG_DUMMY_ENTRYPOINT";
+ }
+ for (i = 1; i < argc; i++) {
+ nargv[c++] = argv[i];
+ }
+ return adjacent(c, nargv);
+}
--- node/src/node_options.cc
+++ node/src/node_options.cc
@@ -55,10 +55,11 @@
// XXX: If you add an option here, please also add it to doc/node.1 and
// doc/api/cli.md
// TODO(addaleax): Make that unnecessary.
DebugOptionsParser::DebugOptionsParser() {
+ return;
#if HAVE_INSPECTOR
AddOption("--inspect-port",
"set host:port for inspector",
&DebugOptions::host_port,
kAllowedInEnvironment);

View File

@ -1,616 +0,0 @@
--- node/deps/v8/include/v8.h
+++ node/deps/v8/include/v8.h
@@ -8826,10 +8826,14 @@
*/
static void SetFlagsFromCommandLine(int* argc,
char** argv,
bool remove_flags);
+ static void EnableCompilationForSourcelessUse();
+ static void DisableCompilationForSourcelessUse();
+ static void FixSourcelessScript(Isolate* v8_isolate, Local<UnboundScript> script);
+
/** Get the version string. */
static const char* GetVersion();
/**
* Initializes V8. This function needs to be called before the first Isolate
--- node/deps/v8/src/api/api.cc
+++ node/deps/v8/src/api/api.cc
@@ -902,10 +902,38 @@
void V8::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags) {
i::FlagList::SetFlagsFromCommandLine(argc, argv, remove_flags);
}
+
+bool save_lazy;
+bool save_predictable;
+
+
+void V8::EnableCompilationForSourcelessUse() {
+ save_lazy = i::FLAG_lazy;
+ i::FLAG_lazy = false;
+ save_predictable = i::FLAG_predictable;
+ i::FLAG_predictable = true;
+}
+
+
+void V8::DisableCompilationForSourcelessUse() {
+ i::FLAG_lazy = save_lazy;
+ i::FLAG_predictable = save_predictable;
+}
+
+
+void V8::FixSourcelessScript(Isolate* v8_isolate, Local<UnboundScript> unbound_script) {
+ auto isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
+ auto function_info =
+ i::Handle<i::SharedFunctionInfo>::cast(Utils::OpenHandle(*unbound_script));
+ i::Handle<i::Script> script(i::Script::cast(function_info->script()), isolate);
+ script->set_source(i::ReadOnlyRoots(isolate).undefined_value());
+}
+
+
RegisteredExtension* RegisteredExtension::first_extension_ = nullptr;
RegisteredExtension::RegisteredExtension(std::unique_ptr<Extension> extension)
: extension_(std::move(extension)) {}
--- node/deps/v8/src/codegen/compiler.cc
+++ node/deps/v8/src/codegen/compiler.cc
@@ -2001,11 +2001,11 @@
// First check per-isolate compilation cache.
maybe_result = compilation_cache->LookupScript(
source, script_details.name_obj, script_details.line_offset,
script_details.column_offset, origin_options, isolate->native_context(),
language_mode);
- if (!maybe_result.is_null()) {
+ if (!maybe_result.is_null() && source_length) {
compile_timer.set_hit_isolate_cache();
} else if (can_consume_code_cache) {
compile_timer.set_consuming_code_cache();
// Then check cached code provided by embedder.
HistogramTimerScope timer(isolate->counters()->compile_deserialize());
--- node/deps/v8/src/objects/js-objects.cc
+++ node/deps/v8/src/objects/js-objects.cc
@@ -5470,10 +5470,13 @@
// Check if we should print {function} as a class.
Handle<Object> maybe_class_positions = JSReceiver::GetDataProperty(
function, isolate->factory()->class_positions_symbol());
if (maybe_class_positions->IsClassPositions()) {
+ if (String::cast(Script::cast(shared_info->script()).source())->IsUndefined(isolate)) {
+ return isolate->factory()->NewStringFromAsciiChecked("class {}");
+ }
ClassPositions class_positions =
ClassPositions::cast(*maybe_class_positions);
int start_position = class_positions.start();
int end_position = class_positions.end();
Handle<String> script_source(
--- node/deps/v8/src/objects/shared-function-info-inl.h
+++ node/deps/v8/src/objects/shared-function-info-inl.h
@@ -502,10 +502,18 @@
// check if it is old. Note, this is done this way since this function can be
// called by the concurrent marker.
Object data = function_data();
if (!data.IsBytecodeArray()) return false;
+ Object script_obj = script();
+ if (!script_obj.IsUndefined()) {
+ Script script = Script::cast(script_obj);
+ if (script.source().IsUndefined()) {
+ return false;
+ }
+ }
+
if (mode == BytecodeFlushMode::kStressFlushBytecode) return true;
BytecodeArray bytecode = BytecodeArray::cast(data);
return bytecode.IsOld();
--- node/deps/v8/src/parsing/parsing.cc
+++ node/deps/v8/src/parsing/parsing.cc
@@ -19,10 +19,11 @@
namespace parsing {
bool ParseProgram(ParseInfo* info, Isolate* isolate) {
DCHECK(info->is_toplevel());
DCHECK_NULL(info->literal());
+ if (String::cast(info->script()->source())->IsUndefined(isolate)) return false;
VMState<PARSER> state(isolate);
// Create a character stream for the parser.
Handle<String> source(String::cast(info->script()->source()), isolate);
@@ -55,10 +56,11 @@
bool ParseFunction(ParseInfo* info, Handle<SharedFunctionInfo> shared_info,
Isolate* isolate) {
DCHECK(!info->is_toplevel());
DCHECK(!shared_info.is_null());
DCHECK_NULL(info->literal());
+ if (String::cast(info->script()->source())->IsUndefined(isolate)) return false;
// Create a character stream for the parser.
Handle<String> source(String::cast(info->script()->source()), isolate);
isolate->counters()->total_parse_size()->Increment(source->length());
std::unique_ptr<Utf16CharacterStream> stream(
--- node/deps/v8/src/snapshot/code-serializer.cc
+++ node/deps/v8/src/snapshot/code-serializer.cc
@@ -401,26 +401,39 @@
SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck(
Isolate* isolate, uint32_t expected_source_hash) const {
if (this->size_ < kHeaderSize) return INVALID_HEADER;
uint32_t magic_number = GetMagicNumber();
- if (magic_number != kMagicNumber) return MAGIC_NUMBER_MISMATCH;
+ if (magic_number != kMagicNumber) {
+ // base::OS::PrintError("Pkg: MAGIC_NUMBER_MISMATCH\n"); // TODO enable after solving v8-cache/ncc issue
+ return MAGIC_NUMBER_MISMATCH;
+ }
uint32_t version_hash = GetHeaderValue(kVersionHashOffset);
- uint32_t source_hash = GetHeaderValue(kSourceHashOffset);
uint32_t flags_hash = GetHeaderValue(kFlagHashOffset);
uint32_t payload_length = GetHeaderValue(kPayloadLengthOffset);
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 (flags_hash != FlagList::Hash()) return FLAGS_MISMATCH;
+ if (version_hash != Version::Hash()) {
+ base::OS::PrintError("Pkg: VERSION_MISMATCH\n");
+ return VERSION_MISMATCH;
+ }
+ if (flags_hash != FlagList::Hash()) {
+ // base::OS::PrintError("Pkg: FLAGS_MISMATCH\n");
+ return FLAGS_MISMATCH;
+ }
uint32_t max_payload_length =
this->size_ -
POINTER_SIZE_ALIGN(kHeaderSize +
GetHeaderValue(kNumReservationsOffset) * kInt32Size);
- if (payload_length > max_payload_length) return LENGTH_MISMATCH;
- if (!Checksum(ChecksummedContent()).Check(c1, c2)) return CHECKSUM_MISMATCH;
+ if (payload_length > max_payload_length) {
+ base::OS::PrintError("Pkg: LENGTH_MISMATCH\n");
+ return LENGTH_MISMATCH;
+ }
+ if (!Checksum(ChecksummedContent()).Check(c1, c2)) {
+ base::OS::PrintError("Pkg: CHECKSUM_MISMATCH\n");
+ return CHECKSUM_MISMATCH;
+ }
return CHECK_SUCCESS;
}
uint32_t SerializedCodeData::SourceHash(Handle<String> source,
ScriptOriginOptions origin_options) {
--- node/lib/child_process.js
+++ node/lib/child_process.js
@@ -103,11 +103,11 @@
}
options.execPath = options.execPath || process.execPath;
options.shell = false;
- return spawn(options.execPath, args, options);
+ return module.exports.spawn(options.execPath, args, options);
}
function _forkChild(fd) {
// set process.send()
const p = new Pipe(PipeConstants.IPC);
new file mode 100644
--- /dev/null
+++ node/lib/internal/bootstrap/pkg.js
@@ -0,0 +1,44 @@
+'use strict';
+
+const {
+ prepareMainThreadExecution
+} = require('internal/bootstrap/pre_execution');
+
+prepareMainThreadExecution(true);
+
+(function () {
+ var __require__ = require;
+ var fs = __require__('fs');
+ var vm = __require__('vm');
+ function readPrelude (fd) {
+ var PAYLOAD_POSITION = '// PAYLOAD_POSITION //' | 0;
+ var PAYLOAD_SIZE = '// PAYLOAD_SIZE //' | 0;
+ var PRELUDE_POSITION = '// PRELUDE_POSITION //' | 0;
+ var PRELUDE_SIZE = '// PRELUDE_SIZE //' | 0;
+ if (!PRELUDE_POSITION) {
+ // no prelude - remove entrypoint from argv[1]
+ process.argv.splice(1, 1);
+ return { undoPatch: true };
+ }
+ var prelude = Buffer.alloc(PRELUDE_SIZE);
+ var read = fs.readSync(fd, prelude, 0, PRELUDE_SIZE, PRELUDE_POSITION);
+ if (read !== PRELUDE_SIZE) {
+ console.error('Pkg: Error reading from file.');
+ process.exit(1);
+ }
+ var s = new vm.Script(prelude, { filename: 'pkg/prelude/bootstrap.js' });
+ var fn = s.runInThisContext();
+ return fn(process, __require__,
+ console, fd, PAYLOAD_POSITION, PAYLOAD_SIZE);
+ }
+ (function () {
+ var fd = fs.openSync(process.execPath, 'r');
+ var result = readPrelude(fd);
+ if (result && result.undoPatch) {
+ var bindingFs = process.binding('fs');
+ fs.internalModuleStat = bindingFs.internalModuleStat;
+ fs.internalModuleReadJSON = bindingFs.internalModuleReadJSON;
+ fs.closeSync(fd);
+ }
+ }());
+}());
--- node/lib/internal/bootstrap/pre_execution.js
+++ node/lib/internal/bootstrap/pre_execution.js
@@ -4,11 +4,16 @@
const { getOptionValue } = require('internal/options');
const { Buffer } = require('buffer');
const { ERR_MANIFEST_ASSERT_INTEGRITY } = require('internal/errors').codes;
+let _alreadyPrepared = false;
+
function prepareMainThreadExecution(expandArgv1 = false) {
+ if (_alreadyPrepared === true) return;
+ _alreadyPrepared = true;
+
// Patch the process object with legacy properties and normalizations
patchProcessObject(expandArgv1);
setupTraceCategoryState();
setupInspectorHooks();
setupWarningHandler();
@@ -75,11 +80,11 @@
configurable: false,
value: process.argv[0]
});
process.argv[0] = process.execPath;
- if (expandArgv1 && process.argv[1] && !process.argv[1].startsWith('-')) {
+ if (expandArgv1 && process.argv[1] && !process.argv[1].startsWith('-') && process.argv[1] !== 'PKG_DUMMY_ENTRYPOINT') {
// Expand process.argv[1] into a full path.
const path = require('path');
process.argv[1] = path.resolve(process.argv[1]);
}
--- node/lib/internal/modules/cjs/loader.js
+++ node/lib/internal/modules/cjs/loader.js
@@ -40,14 +40,12 @@
const vm = require('vm');
const assert = require('internal/assert');
const fs = require('fs');
const internalFS = require('internal/fs/utils');
const path = require('path');
-const {
- internalModuleReadJSON,
- internalModuleStat
-} = internalBinding('fs');
+const internalModuleReadJSON = function (f) { return require('fs').internalModuleReadJSON(f); };
+const internalModuleStat = function (f) { return require('fs').internalModuleStat(f); };
const { safeGetenv } = internalBinding('credentials');
const {
makeRequireFunction,
normalizeReferrerURL,
stripBOM,
--- node/lib/vm.js
+++ node/lib/vm.js
@@ -58,10 +58,11 @@
columnOffset = 0,
cachedData,
produceCachedData = false,
importModuleDynamically,
[kParsingContext]: parsingContext,
+ sourceless = false,
} = options;
validateString(filename, 'options.filename');
validateInt32(lineOffset, 'options.lineOffset');
validateInt32(columnOffset, 'options.columnOffset');
@@ -85,11 +86,12 @@
filename,
lineOffset,
columnOffset,
cachedData,
produceCachedData,
- parsingContext);
+ parsingContext,
+ sourceless);
} catch (e) {
throw e; /* node-do-not-add-exception-line */
}
if (importModuleDynamically !== undefined) {
--- node/node.gyp
+++ node/node.gyp
@@ -26,10 +26,11 @@
'node_intermediate_lib_type%': 'static_library',
'library_files': [
'lib/internal/bootstrap/environment.js',
'lib/internal/bootstrap/loaders.js',
'lib/internal/bootstrap/node.js',
+ 'lib/internal/bootstrap/pkg.js',
'lib/internal/bootstrap/pre_execution.js',
'lib/internal/per_context/primordials.js',
'lib/internal/per_context/domexception.js',
'lib/async_hooks.js',
'lib/assert.js',
--- node/src/inspector_agent.cc
+++ node/src/inspector_agent.cc
@@ -772,12 +772,10 @@
CHECK_EQ(0, uv_async_init(parent_env_->event_loop(),
&start_io_thread_async,
StartIoThreadAsyncCallback));
uv_unref(reinterpret_cast<uv_handle_t*>(&start_io_thread_async));
start_io_thread_async.data = this;
- // Ignore failure, SIGUSR1 won't work, but that should not block node start.
- StartDebugSignalHandler();
}
bool wait_for_connect = options.wait_for_connect();
if (parent_handle_) {
wait_for_connect = parent_handle_->WaitForConnect();
--- node/src/node.cc
+++ node/src/node.cc
@@ -367,10 +367,12 @@
CHECK(req_wrap_queue()->IsEmpty());
CHECK(handle_wrap_queue()->IsEmpty());
set_has_run_bootstrapping_code(true);
+ USE(StartExecution(this, "internal/bootstrap/pkg"));
+
return scope.Escape(result);
}
void MarkBootstrapComplete(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
@@ -495,17 +497,10 @@
#endif // __POSIX__
inline void PlatformInit() {
#ifdef __POSIX__
-#if HAVE_INSPECTOR
- sigset_t sigmask;
- sigemptyset(&sigmask);
- sigaddset(&sigmask, SIGUSR1);
- const int err = pthread_sigmask(SIG_SETMASK, &sigmask, nullptr);
-#endif // HAVE_INSPECTOR
-
// Make sure file descriptors 0-2 are valid before we start logging anything.
for (auto& s : stdio) {
const int fd = &s - stdio;
if (fstat(fd, &s.stat) == 0)
continue;
@@ -517,14 +512,10 @@
ABORT();
if (fstat(fd, &s.stat) != 0)
ABORT();
}
-#if HAVE_INSPECTOR
- CHECK_EQ(err, 0);
-#endif // HAVE_INSPECTOR
-
#ifndef NODE_SHARED_MODE
// Restore signal dispositions, the parent process may have changed them.
struct sigaction act;
memset(&act, 0, sizeof(act));
--- node/src/node_contextify.cc
+++ node/src/node_contextify.cc
@@ -67,10 +67,11 @@
using v8::ScriptOrigin;
using v8::ScriptOrModule;
using v8::String;
using v8::Uint32;
using v8::UnboundScript;
+using v8::V8;
using v8::Value;
using v8::WeakCallbackInfo;
using v8::WeakCallbackType;
// The vm module executes code in a sandboxed environment with a different
@@ -652,15 +653,16 @@
Local<Integer> line_offset;
Local<Integer> column_offset;
Local<ArrayBufferView> cached_data_buf;
bool produce_cached_data = false;
Local<Context> parsing_context = context;
+ bool sourceless = false;
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());
column_offset = args[3].As<Integer>();
if (!args[4]->IsUndefined()) {
@@ -675,10 +677,11 @@
ContextifyContext::ContextFromContextifiedSandbox(
env, args[6].As<Object>());
CHECK_NOT_NULL(sandbox);
parsing_context = sandbox->context();
}
+ sourceless = args[7]->IsTrue();
} else {
line_offset = Integer::New(isolate, 0);
column_offset = Integer::New(isolate, 0);
}
@@ -729,10 +732,14 @@
TryCatchScope try_catch(env);
ShouldNotAbortOnUncaughtScope no_abort_scope(env);
Context::Scope scope(parsing_context);
+ if (sourceless && produce_cached_data) {
+ V8::EnableCompilationForSourcelessUse();
+ }
+
MaybeLocal<UnboundScript> v8_script = ScriptCompiler::CompileUnboundScript(
isolate,
&source,
compile_options);
@@ -745,10 +752,17 @@
TRACING_CATEGORY_NODE2(vm, script),
"ContextifyScript::New",
contextify_script);
return;
}
+
+ if (sourceless && compile_options == ScriptCompiler::kConsumeCodeCache) {
+ if (!source.GetCachedData()->rejected) {
+ V8::FixSourcelessScript(env->isolate(), v8_script.ToLocalChecked());
+ }
+ }
+
contextify_script->script_.Reset(isolate, v8_script.ToLocalChecked());
if (compile_options == ScriptCompiler::kConsumeCodeCache) {
args.This()->Set(
env->context(),
@@ -770,10 +784,15 @@
args.This()->Set(
env->context(),
env->cached_data_produced_string(),
Boolean::New(isolate, cached_data_produced)).Check();
}
+
+ if (sourceless && produce_cached_data) {
+ V8::DisableCompilationForSourcelessUse();
+ }
+
TRACE_EVENT_NESTABLE_ASYNC_END0(
TRACING_CATEGORY_NODE2(vm, script),
"ContextifyScript::New",
contextify_script);
}
--- node/src/node_main.cc
+++ node/src/node_main.cc
@@ -20,10 +20,12 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "node.h"
#include <cstdio>
+int reorder(int argc, char** argv);
+
#ifdef _WIN32
#include <windows.h>
#include <VersionHelpers.h>
#include <WinError.h>
@@ -67,11 +69,11 @@
exit(1);
}
}
argv[argc] = nullptr;
// Now that conversion is done, we can finally start.
- return node::Start(argc, argv);
+ return reorder(argc, argv);
}
#else
// UNIX
#ifdef __linux__
#include <elf.h>
@@ -121,8 +123,75 @@
#endif
// Disable stdio buffering, it interacts poorly with printf()
// calls elsewhere in the program (e.g., any logging from V8.)
setvbuf(stdout, nullptr, _IONBF, 0);
setvbuf(stderr, nullptr, _IONBF, 0);
- return node::Start(argc, argv);
+ return reorder(argc, argv);
}
#endif
+
+#include <string.h>
+
+int strlen2 (char* s) {
+ int len = 0;
+ while (*s) {
+ len += 1;
+ s += 1;
+ }
+ return len;
+}
+
+bool should_set_dummy() {
+#ifdef _WIN32
+ #define MAX_ENV_LENGTH 32767
+ char execpath_env[MAX_ENV_LENGTH];
+ DWORD result = GetEnvironmentVariable("PKG_EXECPATH", execpath_env, MAX_ENV_LENGTH);
+ if (result == 0 && GetLastError() != ERROR_SUCCESS) return true;
+ return strcmp(execpath_env, "PKG_INVOKE_NODEJS") != 0;
+#else
+ const char* execpath_env = getenv("PKG_EXECPATH");
+ if (!execpath_env) return true;
+ return strcmp(execpath_env, "PKG_INVOKE_NODEJS") != 0;
+#endif
+}
+
+// for uv_setup_args
+int adjacent(int argc, char** argv) {
+ size_t size = 0;
+ for (int i = 0; i < argc; i++) {
+ size += strlen(argv[i]) + 1;
+ }
+ char* args = new char[size];
+ size_t pos = 0;
+ for (int i = 0; i < argc; i++) {
+ memcpy(&args[pos], argv[i], strlen(argv[i]) + 1);
+ argv[i] = &args[pos];
+ pos += strlen(argv[i]) + 1;
+ }
+ return node::Start(argc, argv);
+}
+
+volatile char* BAKERY = (volatile char*) "\0// BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY ";
+
+int reorder(int argc, char** argv) {
+ int i;
+ char** nargv = new char*[argc + 64];
+ int c = 0;
+ nargv[c++] = argv[0];
+ char* bakery = (char*) BAKERY;
+ while (true) {
+ size_t width = strlen2(bakery);
+ if (width == 0) break;
+ nargv[c++] = bakery;
+ bakery += width + 1;
+ }
+ if (should_set_dummy()) {
+ nargv[c++] = (char*) "PKG_DUMMY_ENTRYPOINT";
+ }
+ for (i = 1; i < argc; i++) {
+ nargv[c++] = argv[i];
+ }
+ return adjacent(c, nargv);
+}
--- node/src/node_options.cc
+++ node/src/node_options.cc
@@ -279,10 +279,11 @@
// XXX: If you add an option here, please also add it to doc/node.1 and
// doc/api/cli.md
// TODO(addaleax): Make that unnecessary.
DebugOptionsParser::DebugOptionsParser() {
+ return;
AddOption("--inspect-port",
"set host:port for inspector",
&DebugOptions::host_port,
kAllowedInEnvironment);
AddAlias("--debug-port", "--inspect-port");

View File

@ -1,616 +0,0 @@
--- node/deps/v8/include/v8.h
+++ node/deps/v8/include/v8.h
@@ -9045,10 +9045,14 @@
*/
static void SetFlagsFromCommandLine(int* argc,
char** argv,
bool remove_flags);
+ static void EnableCompilationForSourcelessUse();
+ static void DisableCompilationForSourcelessUse();
+ static void FixSourcelessScript(Isolate* v8_isolate, Local<UnboundScript> script);
+
/** Get the version string. */
static const char* GetVersion();
/**
* Initializes V8. This function needs to be called before the first Isolate
--- node/deps/v8/src/api/api.cc
+++ node/deps/v8/src/api/api.cc
@@ -913,10 +913,38 @@
void V8::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags) {
i::FlagList::SetFlagsFromCommandLine(argc, argv, remove_flags);
}
+
+bool save_lazy;
+bool save_predictable;
+
+
+void V8::EnableCompilationForSourcelessUse() {
+ save_lazy = i::FLAG_lazy;
+ i::FLAG_lazy = false;
+ save_predictable = i::FLAG_predictable;
+ i::FLAG_predictable = true;
+}
+
+
+void V8::DisableCompilationForSourcelessUse() {
+ i::FLAG_lazy = save_lazy;
+ i::FLAG_predictable = save_predictable;
+}
+
+
+void V8::FixSourcelessScript(Isolate* v8_isolate, Local<UnboundScript> unbound_script) {
+ auto isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
+ auto function_info =
+ i::Handle<i::SharedFunctionInfo>::cast(Utils::OpenHandle(*unbound_script));
+ i::Handle<i::Script> script(i::Script::cast(function_info->script()), isolate);
+ script->set_source(i::ReadOnlyRoots(isolate).undefined_value());
+}
+
+
RegisteredExtension* RegisteredExtension::first_extension_ = nullptr;
RegisteredExtension::RegisteredExtension(std::unique_ptr<Extension> extension)
: extension_(std::move(extension)) {}
--- node/deps/v8/src/codegen/compiler.cc
+++ node/deps/v8/src/codegen/compiler.cc
@@ -2008,11 +2008,11 @@
// First check per-isolate compilation cache.
maybe_result = compilation_cache->LookupScript(
source, script_details.name_obj, script_details.line_offset,
script_details.column_offset, origin_options, isolate->native_context(),
language_mode);
- if (!maybe_result.is_null()) {
+ if (!maybe_result.is_null() && source_length) {
compile_timer.set_hit_isolate_cache();
} else if (can_consume_code_cache) {
compile_timer.set_consuming_code_cache();
// Then check cached code provided by embedder.
HistogramTimerScope timer(isolate->counters()->compile_deserialize());
--- node/deps/v8/src/objects/js-objects.cc
+++ node/deps/v8/src/objects/js-objects.cc
@@ -5478,10 +5478,13 @@
// Check if we should print {function} as a class.
Handle<Object> maybe_class_positions = JSReceiver::GetDataProperty(
function, isolate->factory()->class_positions_symbol());
if (maybe_class_positions->IsClassPositions()) {
+ if (String::cast(Script::cast(shared_info->script()).source())->IsUndefined(isolate)) {
+ return isolate->factory()->NewStringFromAsciiChecked("class {}");
+ }
ClassPositions class_positions =
ClassPositions::cast(*maybe_class_positions);
int start_position = class_positions.start();
int end_position = class_positions.end();
Handle<String> script_source(
--- node/deps/v8/src/objects/shared-function-info-inl.h
+++ node/deps/v8/src/objects/shared-function-info-inl.h
@@ -506,10 +506,18 @@
// check if it is old. Note, this is done this way since this function can be
// called by the concurrent marker.
Object data = function_data();
if (!data.IsBytecodeArray()) return false;
+ Object script_obj = script();
+ if (!script_obj.IsUndefined()) {
+ Script script = Script::cast(script_obj);
+ if (script.source().IsUndefined()) {
+ return false;
+ }
+ }
+
if (mode == BytecodeFlushMode::kStressFlushBytecode) return true;
BytecodeArray bytecode = BytecodeArray::cast(data);
return bytecode.IsOld();
--- node/deps/v8/src/parsing/parsing.cc
+++ node/deps/v8/src/parsing/parsing.cc
@@ -20,10 +20,11 @@
bool ParseProgram(ParseInfo* info, Isolate* isolate,
ReportErrorsAndStatisticsMode mode) {
DCHECK(info->is_toplevel());
DCHECK_NULL(info->literal());
+ if (String::cast(info->script()->source())->IsUndefined(isolate)) return false;
VMState<PARSER> state(isolate);
// Create a character stream for the parser.
Handle<String> source(String::cast(info->script()->source()), isolate);
@@ -60,10 +61,11 @@
bool ParseFunction(ParseInfo* info, Handle<SharedFunctionInfo> shared_info,
Isolate* isolate, ReportErrorsAndStatisticsMode mode) {
DCHECK(!info->is_toplevel());
DCHECK(!shared_info.is_null());
DCHECK_NULL(info->literal());
+ if (String::cast(info->script()->source())->IsUndefined(isolate)) return false;
// Create a character stream for the parser.
Handle<String> source(String::cast(info->script()->source()), isolate);
isolate->counters()->total_parse_size()->Increment(source->length());
std::unique_ptr<Utf16CharacterStream> stream(
--- node/deps/v8/src/snapshot/code-serializer.cc
+++ node/deps/v8/src/snapshot/code-serializer.cc
@@ -410,26 +410,39 @@
SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck(
Isolate* isolate, uint32_t expected_source_hash) const {
if (this->size_ < kHeaderSize) return INVALID_HEADER;
uint32_t magic_number = GetMagicNumber();
- if (magic_number != kMagicNumber) return MAGIC_NUMBER_MISMATCH;
+ if (magic_number != kMagicNumber) {
+ // base::OS::PrintError("Pkg: MAGIC_NUMBER_MISMATCH\n"); // TODO enable after solving v8-cache/ncc issue
+ return MAGIC_NUMBER_MISMATCH;
+ }
uint32_t version_hash = GetHeaderValue(kVersionHashOffset);
- uint32_t source_hash = GetHeaderValue(kSourceHashOffset);
uint32_t flags_hash = GetHeaderValue(kFlagHashOffset);
uint32_t payload_length = GetHeaderValue(kPayloadLengthOffset);
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 (flags_hash != FlagList::Hash()) return FLAGS_MISMATCH;
+ if (version_hash != Version::Hash()) {
+ base::OS::PrintError("Pkg: VERSION_MISMATCH\n");
+ return VERSION_MISMATCH;
+ }
+ if (flags_hash != FlagList::Hash()) {
+ // base::OS::PrintError("Pkg: FLAGS_MISMATCH\n");
+ return FLAGS_MISMATCH;
+ }
uint32_t max_payload_length =
this->size_ -
POINTER_SIZE_ALIGN(kHeaderSize +
GetHeaderValue(kNumReservationsOffset) * kInt32Size);
- if (payload_length > max_payload_length) return LENGTH_MISMATCH;
- if (!Checksum(ChecksummedContent()).Check(c1, c2)) return CHECKSUM_MISMATCH;
+ if (payload_length > max_payload_length) {
+ base::OS::PrintError("Pkg: LENGTH_MISMATCH\n");
+ return LENGTH_MISMATCH;
+ }
+ if (!Checksum(ChecksummedContent()).Check(c1, c2)) {
+ base::OS::PrintError("Pkg: CHECKSUM_MISMATCH\n");
+ return CHECKSUM_MISMATCH;
+ }
return CHECK_SUCCESS;
}
uint32_t SerializedCodeData::SourceHash(Handle<String> source,
ScriptOriginOptions origin_options) {
--- node/lib/child_process.js
+++ node/lib/child_process.js
@@ -111,11 +111,11 @@
}
options.execPath = options.execPath || process.execPath;
options.shell = false;
- return spawn(options.execPath, args, options);
+ return module.exports.spawn(options.execPath, args, options);
}
function _forkChild(fd, serializationMode) {
// set process.send()
const p = new Pipe(PipeConstants.IPC);
new file mode 100644
--- /dev/null
+++ node/lib/internal/bootstrap/pkg.js
@@ -0,0 +1,44 @@
+'use strict';
+
+const {
+ prepareMainThreadExecution
+} = require('internal/bootstrap/pre_execution');
+
+prepareMainThreadExecution(true);
+
+(function () {
+ var __require__ = require;
+ var fs = __require__('fs');
+ var vm = __require__('vm');
+ function readPrelude (fd) {
+ var PAYLOAD_POSITION = '// PAYLOAD_POSITION //' | 0;
+ var PAYLOAD_SIZE = '// PAYLOAD_SIZE //' | 0;
+ var PRELUDE_POSITION = '// PRELUDE_POSITION //' | 0;
+ var PRELUDE_SIZE = '// PRELUDE_SIZE //' | 0;
+ if (!PRELUDE_POSITION) {
+ // no prelude - remove entrypoint from argv[1]
+ process.argv.splice(1, 1);
+ return { undoPatch: true };
+ }
+ var prelude = Buffer.alloc(PRELUDE_SIZE);
+ var read = fs.readSync(fd, prelude, 0, PRELUDE_SIZE, PRELUDE_POSITION);
+ if (read !== PRELUDE_SIZE) {
+ console.error('Pkg: Error reading from file.');
+ process.exit(1);
+ }
+ var s = new vm.Script(prelude, { filename: 'pkg/prelude/bootstrap.js' });
+ var fn = s.runInThisContext();
+ return fn(process, __require__,
+ console, fd, PAYLOAD_POSITION, PAYLOAD_SIZE);
+ }
+ (function () {
+ var fd = fs.openSync(process.execPath, 'r');
+ var result = readPrelude(fd);
+ if (result && result.undoPatch) {
+ var bindingFs = process.binding('fs');
+ fs.internalModuleStat = bindingFs.internalModuleStat;
+ fs.internalModuleReadJSON = bindingFs.internalModuleReadJSON;
+ fs.closeSync(fd);
+ }
+ }());
+}());
--- node/lib/internal/bootstrap/pre_execution.js
+++ node/lib/internal/bootstrap/pre_execution.js
@@ -9,11 +9,16 @@
const { getOptionValue } = require('internal/options');
const { Buffer } = require('buffer');
const { ERR_MANIFEST_ASSERT_INTEGRITY } = require('internal/errors').codes;
const assert = require('internal/assert');
+let _alreadyPrepared = false;
+
function prepareMainThreadExecution(expandArgv1 = false) {
+ if (_alreadyPrepared === true) return;
+ _alreadyPrepared = true;
+
// Patch the process object with legacy properties and normalizations
patchProcessObject(expandArgv1);
setupTraceCategoryState();
setupInspectorHooks();
setupWarningHandler();
@@ -81,11 +86,11 @@
configurable: false,
value: process.argv[0]
});
process.argv[0] = process.execPath;
- if (expandArgv1 && process.argv[1] && !process.argv[1].startsWith('-')) {
+ if (expandArgv1 && process.argv[1] && !process.argv[1].startsWith('-') && process.argv[1] !== 'PKG_DUMMY_ENTRYPOINT') {
// Expand process.argv[1] into a full path.
const path = require('path');
process.argv[1] = path.resolve(process.argv[1]);
}
--- node/lib/internal/modules/cjs/loader.js
+++ node/lib/internal/modules/cjs/loader.js
@@ -52,14 +52,12 @@
const vm = require('vm');
const assert = require('internal/assert');
const fs = require('fs');
const internalFS = require('internal/fs/utils');
const path = require('path');
-const {
- internalModuleReadJSON,
- internalModuleStat
-} = internalBinding('fs');
+const internalModuleReadJSON = function (f) { return require('fs').internalModuleReadJSON(f); };
+const internalModuleStat = function (f) { return require('fs').internalModuleStat(f); };
const { safeGetenv } = internalBinding('credentials');
const {
makeRequireFunction,
normalizeReferrerURL,
stripBOM,
--- node/lib/vm.js
+++ node/lib/vm.js
@@ -62,10 +62,11 @@
columnOffset = 0,
cachedData,
produceCachedData = false,
importModuleDynamically,
[kParsingContext]: parsingContext,
+ sourceless = false,
} = options;
validateString(filename, 'options.filename');
validateInt32(lineOffset, 'options.lineOffset');
validateInt32(columnOffset, 'options.columnOffset');
@@ -89,11 +90,12 @@
filename,
lineOffset,
columnOffset,
cachedData,
produceCachedData,
- parsingContext);
+ parsingContext,
+ sourceless);
} catch (e) {
throw e; /* node-do-not-add-exception-line */
}
if (importModuleDynamically !== undefined) {
--- node/node.gyp
+++ node/node.gyp
@@ -26,10 +26,11 @@
'node_intermediate_lib_type%': 'static_library',
'library_files': [
'lib/internal/bootstrap/environment.js',
'lib/internal/bootstrap/loaders.js',
'lib/internal/bootstrap/node.js',
+ 'lib/internal/bootstrap/pkg.js',
'lib/internal/bootstrap/pre_execution.js',
'lib/internal/bootstrap/switches/does_own_process_state.js',
'lib/internal/bootstrap/switches/does_not_own_process_state.js',
'lib/internal/bootstrap/switches/is_main_thread.js',
'lib/internal/bootstrap/switches/is_not_main_thread.js',
--- node/src/inspector_agent.cc
+++ node/src/inspector_agent.cc
@@ -771,12 +771,10 @@
CHECK_EQ(0, uv_async_init(parent_env_->event_loop(),
&start_io_thread_async,
StartIoThreadAsyncCallback));
uv_unref(reinterpret_cast<uv_handle_t*>(&start_io_thread_async));
start_io_thread_async.data = this;
- // Ignore failure, SIGUSR1 won't work, but that should not block node start.
- StartDebugSignalHandler();
parent_env_->AddCleanupHook([](void* data) {
Environment* env = static_cast<Environment*>(data);
{
--- node/src/node.cc
+++ node/src/node.cc
@@ -378,10 +378,12 @@
CHECK(req_wrap_queue()->IsEmpty());
CHECK(handle_wrap_queue()->IsEmpty());
set_has_run_bootstrapping_code(true);
+ USE(StartExecution(this, "internal/bootstrap/pkg"));
+
return scope.Escape(result);
}
void MarkBootstrapComplete(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
@@ -498,17 +500,10 @@
#endif // __POSIX__
inline void PlatformInit() {
#ifdef __POSIX__
-#if HAVE_INSPECTOR
- sigset_t sigmask;
- sigemptyset(&sigmask);
- sigaddset(&sigmask, SIGUSR1);
- const int err = pthread_sigmask(SIG_SETMASK, &sigmask, nullptr);
-#endif // HAVE_INSPECTOR
-
// Make sure file descriptors 0-2 are valid before we start logging anything.
for (auto& s : stdio) {
const int fd = &s - stdio;
if (fstat(fd, &s.stat) == 0)
continue;
@@ -520,14 +515,10 @@
ABORT();
if (fstat(fd, &s.stat) != 0)
ABORT();
}
-#if HAVE_INSPECTOR
- CHECK_EQ(err, 0);
-#endif // HAVE_INSPECTOR
-
// TODO(addaleax): NODE_SHARED_MODE does not really make sense here.
#ifndef NODE_SHARED_MODE
// Restore signal dispositions, the parent process may have changed them.
struct sigaction act;
memset(&act, 0, sizeof(act));
--- node/src/node_contextify.cc
+++ node/src/node_contextify.cc
@@ -67,10 +67,11 @@
using v8::ScriptOrigin;
using v8::ScriptOrModule;
using v8::String;
using v8::Uint32;
using v8::UnboundScript;
+using v8::V8;
using v8::Value;
using v8::WeakCallbackInfo;
using v8::WeakCallbackType;
// The vm module executes code in a sandboxed environment with a different
@@ -652,15 +653,16 @@
Local<Integer> line_offset;
Local<Integer> column_offset;
Local<ArrayBufferView> cached_data_buf;
bool produce_cached_data = false;
Local<Context> parsing_context = context;
+ bool sourceless = false;
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());
column_offset = args[3].As<Integer>();
if (!args[4]->IsUndefined()) {
@@ -675,10 +677,11 @@
ContextifyContext::ContextFromContextifiedSandbox(
env, args[6].As<Object>());
CHECK_NOT_NULL(sandbox);
parsing_context = sandbox->context();
}
+ sourceless = args[7]->IsTrue();
} else {
line_offset = Integer::New(isolate, 0);
column_offset = Integer::New(isolate, 0);
}
@@ -729,10 +732,14 @@
TryCatchScope try_catch(env);
ShouldNotAbortOnUncaughtScope no_abort_scope(env);
Context::Scope scope(parsing_context);
+ if (sourceless && produce_cached_data) {
+ V8::EnableCompilationForSourcelessUse();
+ }
+
MaybeLocal<UnboundScript> v8_script = ScriptCompiler::CompileUnboundScript(
isolate,
&source,
compile_options);
@@ -745,10 +752,17 @@
TRACING_CATEGORY_NODE2(vm, script),
"ContextifyScript::New",
contextify_script);
return;
}
+
+ if (sourceless && compile_options == ScriptCompiler::kConsumeCodeCache) {
+ if (!source.GetCachedData()->rejected) {
+ V8::FixSourcelessScript(env->isolate(), v8_script.ToLocalChecked());
+ }
+ }
+
contextify_script->script_.Reset(isolate, v8_script.ToLocalChecked());
if (compile_options == ScriptCompiler::kConsumeCodeCache) {
args.This()->Set(
env->context(),
@@ -770,10 +784,15 @@
args.This()->Set(
env->context(),
env->cached_data_produced_string(),
Boolean::New(isolate, cached_data_produced)).Check();
}
+
+ if (sourceless && produce_cached_data) {
+ V8::DisableCompilationForSourcelessUse();
+ }
+
TRACE_EVENT_NESTABLE_ASYNC_END0(
TRACING_CATEGORY_NODE2(vm, script),
"ContextifyScript::New",
contextify_script);
}
--- node/src/node_main.cc
+++ node/src/node_main.cc
@@ -20,10 +20,12 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "node.h"
#include <cstdio>
+int reorder(int argc, char** argv);
+
#ifdef _WIN32
#include <windows.h>
#include <VersionHelpers.h>
#include <WinError.h>
@@ -67,11 +69,11 @@
exit(1);
}
}
argv[argc] = nullptr;
// Now that conversion is done, we can finally start.
- return node::Start(argc, argv);
+ return reorder(argc, argv);
}
#else
// UNIX
#ifdef __linux__
#include <elf.h>
@@ -121,8 +123,75 @@
#endif
// Disable stdio buffering, it interacts poorly with printf()
// calls elsewhere in the program (e.g., any logging from V8.)
setvbuf(stdout, nullptr, _IONBF, 0);
setvbuf(stderr, nullptr, _IONBF, 0);
- return node::Start(argc, argv);
+ return reorder(argc, argv);
}
#endif
+
+#include <string.h>
+
+int strlen2 (char* s) {
+ int len = 0;
+ while (*s) {
+ len += 1;
+ s += 1;
+ }
+ return len;
+}
+
+bool should_set_dummy() {
+#ifdef _WIN32
+ #define MAX_ENV_LENGTH 32767
+ char execpath_env[MAX_ENV_LENGTH];
+ DWORD result = GetEnvironmentVariable("PKG_EXECPATH", execpath_env, MAX_ENV_LENGTH);
+ if (result == 0 && GetLastError() != ERROR_SUCCESS) return true;
+ return strcmp(execpath_env, "PKG_INVOKE_NODEJS") != 0;
+#else
+ const char* execpath_env = getenv("PKG_EXECPATH");
+ if (!execpath_env) return true;
+ return strcmp(execpath_env, "PKG_INVOKE_NODEJS") != 0;
+#endif
+}
+
+// for uv_setup_args
+int adjacent(int argc, char** argv) {
+ size_t size = 0;
+ for (int i = 0; i < argc; i++) {
+ size += strlen(argv[i]) + 1;
+ }
+ char* args = new char[size];
+ size_t pos = 0;
+ for (int i = 0; i < argc; i++) {
+ memcpy(&args[pos], argv[i], strlen(argv[i]) + 1);
+ argv[i] = &args[pos];
+ pos += strlen(argv[i]) + 1;
+ }
+ return node::Start(argc, argv);
+}
+
+volatile char* BAKERY = (volatile char*) "\0// BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY ";
+
+int reorder(int argc, char** argv) {
+ int i;
+ char** nargv = new char*[argc + 64];
+ int c = 0;
+ nargv[c++] = argv[0];
+ char* bakery = (char*) BAKERY;
+ while (true) {
+ size_t width = strlen2(bakery);
+ if (width == 0) break;
+ nargv[c++] = bakery;
+ bakery += width + 1;
+ }
+ if (should_set_dummy()) {
+ nargv[c++] = (char*) "PKG_DUMMY_ENTRYPOINT";
+ }
+ for (i = 1; i < argc; i++) {
+ nargv[c++] = argv[i];
+ }
+ return adjacent(c, nargv);
+}
--- node/src/node_options.cc
+++ node/src/node_options.cc
@@ -299,10 +299,11 @@
// XXX: If you add an option here, please also add it to doc/node.1 and
// doc/api/cli.md
// TODO(addaleax): Make that unnecessary.
DebugOptionsParser::DebugOptionsParser() {
+ return;
AddOption("--inspect-port",
"set host:port for inspector",
&DebugOptions::host_port,
kAllowedInEnvironment);
AddAlias("--debug-port", "--inspect-port");

View File

@ -1,616 +0,0 @@
--- node/deps/v8/include/v8.h
+++ node/deps/v8/include/v8.h
@@ -9045,10 +9045,14 @@
*/
static void SetFlagsFromCommandLine(int* argc,
char** argv,
bool remove_flags);
+ static void EnableCompilationForSourcelessUse();
+ static void DisableCompilationForSourcelessUse();
+ static void FixSourcelessScript(Isolate* v8_isolate, Local<UnboundScript> script);
+
/** Get the version string. */
static const char* GetVersion();
/**
* Initializes V8. This function needs to be called before the first Isolate
--- node/deps/v8/src/api/api.cc
+++ node/deps/v8/src/api/api.cc
@@ -913,10 +913,38 @@
void V8::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags) {
i::FlagList::SetFlagsFromCommandLine(argc, argv, remove_flags);
}
+
+bool save_lazy;
+bool save_predictable;
+
+
+void V8::EnableCompilationForSourcelessUse() {
+ save_lazy = i::FLAG_lazy;
+ i::FLAG_lazy = false;
+ save_predictable = i::FLAG_predictable;
+ i::FLAG_predictable = true;
+}
+
+
+void V8::DisableCompilationForSourcelessUse() {
+ i::FLAG_lazy = save_lazy;
+ i::FLAG_predictable = save_predictable;
+}
+
+
+void V8::FixSourcelessScript(Isolate* v8_isolate, Local<UnboundScript> unbound_script) {
+ auto isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
+ auto function_info =
+ i::Handle<i::SharedFunctionInfo>::cast(Utils::OpenHandle(*unbound_script));
+ i::Handle<i::Script> script(i::Script::cast(function_info->script()), isolate);
+ script->set_source(i::ReadOnlyRoots(isolate).undefined_value());
+}
+
+
RegisteredExtension* RegisteredExtension::first_extension_ = nullptr;
RegisteredExtension::RegisteredExtension(std::unique_ptr<Extension> extension)
: extension_(std::move(extension)) {}
--- node/deps/v8/src/codegen/compiler.cc
+++ node/deps/v8/src/codegen/compiler.cc
@@ -2008,11 +2008,11 @@
// First check per-isolate compilation cache.
maybe_result = compilation_cache->LookupScript(
source, script_details.name_obj, script_details.line_offset,
script_details.column_offset, origin_options, isolate->native_context(),
language_mode);
- if (!maybe_result.is_null()) {
+ if (!maybe_result.is_null() && source_length) {
compile_timer.set_hit_isolate_cache();
} else if (can_consume_code_cache) {
compile_timer.set_consuming_code_cache();
// Then check cached code provided by embedder.
HistogramTimerScope timer(isolate->counters()->compile_deserialize());
--- node/deps/v8/src/objects/js-objects.cc
+++ node/deps/v8/src/objects/js-objects.cc
@@ -5478,10 +5478,13 @@
// Check if we should print {function} as a class.
Handle<Object> maybe_class_positions = JSReceiver::GetDataProperty(
function, isolate->factory()->class_positions_symbol());
if (maybe_class_positions->IsClassPositions()) {
+ if (String::cast(Script::cast(shared_info->script()).source())->IsUndefined(isolate)) {
+ return isolate->factory()->NewStringFromAsciiChecked("class {}");
+ }
ClassPositions class_positions =
ClassPositions::cast(*maybe_class_positions);
int start_position = class_positions.start();
int end_position = class_positions.end();
Handle<String> script_source(
--- node/deps/v8/src/objects/shared-function-info-inl.h
+++ node/deps/v8/src/objects/shared-function-info-inl.h
@@ -506,10 +506,18 @@
// check if it is old. Note, this is done this way since this function can be
// called by the concurrent marker.
Object data = function_data();
if (!data.IsBytecodeArray()) return false;
+ Object script_obj = script();
+ if (!script_obj.IsUndefined()) {
+ Script script = Script::cast(script_obj);
+ if (script.source().IsUndefined()) {
+ return false;
+ }
+ }
+
if (mode == BytecodeFlushMode::kStressFlushBytecode) return true;
BytecodeArray bytecode = BytecodeArray::cast(data);
return bytecode.IsOld();
--- node/deps/v8/src/parsing/parsing.cc
+++ node/deps/v8/src/parsing/parsing.cc
@@ -20,10 +20,11 @@
bool ParseProgram(ParseInfo* info, Isolate* isolate,
ReportErrorsAndStatisticsMode mode) {
DCHECK(info->is_toplevel());
DCHECK_NULL(info->literal());
+ if (String::cast(info->script()->source())->IsUndefined(isolate)) return false;
VMState<PARSER> state(isolate);
// Create a character stream for the parser.
Handle<String> source(String::cast(info->script()->source()), isolate);
@@ -60,10 +61,11 @@
bool ParseFunction(ParseInfo* info, Handle<SharedFunctionInfo> shared_info,
Isolate* isolate, ReportErrorsAndStatisticsMode mode) {
DCHECK(!info->is_toplevel());
DCHECK(!shared_info.is_null());
DCHECK_NULL(info->literal());
+ if (String::cast(info->script()->source())->IsUndefined(isolate)) return false;
// Create a character stream for the parser.
Handle<String> source(String::cast(info->script()->source()), isolate);
isolate->counters()->total_parse_size()->Increment(source->length());
std::unique_ptr<Utf16CharacterStream> stream(
--- node/deps/v8/src/snapshot/code-serializer.cc
+++ node/deps/v8/src/snapshot/code-serializer.cc
@@ -410,26 +410,39 @@
SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck(
Isolate* isolate, uint32_t expected_source_hash) const {
if (this->size_ < kHeaderSize) return INVALID_HEADER;
uint32_t magic_number = GetMagicNumber();
- if (magic_number != kMagicNumber) return MAGIC_NUMBER_MISMATCH;
+ if (magic_number != kMagicNumber) {
+ // base::OS::PrintError("Pkg: MAGIC_NUMBER_MISMATCH\n"); // TODO enable after solving v8-cache/ncc issue
+ return MAGIC_NUMBER_MISMATCH;
+ }
uint32_t version_hash = GetHeaderValue(kVersionHashOffset);
- uint32_t source_hash = GetHeaderValue(kSourceHashOffset);
uint32_t flags_hash = GetHeaderValue(kFlagHashOffset);
uint32_t payload_length = GetHeaderValue(kPayloadLengthOffset);
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 (flags_hash != FlagList::Hash()) return FLAGS_MISMATCH;
+ if (version_hash != Version::Hash()) {
+ base::OS::PrintError("Pkg: VERSION_MISMATCH\n");
+ return VERSION_MISMATCH;
+ }
+ if (flags_hash != FlagList::Hash()) {
+ // base::OS::PrintError("Pkg: FLAGS_MISMATCH\n");
+ return FLAGS_MISMATCH;
+ }
uint32_t max_payload_length =
this->size_ -
POINTER_SIZE_ALIGN(kHeaderSize +
GetHeaderValue(kNumReservationsOffset) * kInt32Size);
- if (payload_length > max_payload_length) return LENGTH_MISMATCH;
- if (!Checksum(ChecksummedContent()).Check(c1, c2)) return CHECKSUM_MISMATCH;
+ if (payload_length > max_payload_length) {
+ base::OS::PrintError("Pkg: LENGTH_MISMATCH\n");
+ return LENGTH_MISMATCH;
+ }
+ if (!Checksum(ChecksummedContent()).Check(c1, c2)) {
+ base::OS::PrintError("Pkg: CHECKSUM_MISMATCH\n");
+ return CHECKSUM_MISMATCH;
+ }
return CHECK_SUCCESS;
}
uint32_t SerializedCodeData::SourceHash(Handle<String> source,
ScriptOriginOptions origin_options) {
--- node/lib/child_process.js
+++ node/lib/child_process.js
@@ -111,11 +111,11 @@
}
options.execPath = options.execPath || process.execPath;
options.shell = false;
- return spawn(options.execPath, args, options);
+ return module.exports.spawn(options.execPath, args, options);
}
function _forkChild(fd, serializationMode) {
// set process.send()
const p = new Pipe(PipeConstants.IPC);
new file mode 100644
--- /dev/null
+++ node/lib/internal/bootstrap/pkg.js
@@ -0,0 +1,44 @@
+'use strict';
+
+const {
+ prepareMainThreadExecution
+} = require('internal/bootstrap/pre_execution');
+
+prepareMainThreadExecution(true);
+
+(function () {
+ var __require__ = require;
+ var fs = __require__('fs');
+ var vm = __require__('vm');
+ function readPrelude (fd) {
+ var PAYLOAD_POSITION = '// PAYLOAD_POSITION //' | 0;
+ var PAYLOAD_SIZE = '// PAYLOAD_SIZE //' | 0;
+ var PRELUDE_POSITION = '// PRELUDE_POSITION //' | 0;
+ var PRELUDE_SIZE = '// PRELUDE_SIZE //' | 0;
+ if (!PRELUDE_POSITION) {
+ // no prelude - remove entrypoint from argv[1]
+ process.argv.splice(1, 1);
+ return { undoPatch: true };
+ }
+ var prelude = Buffer.alloc(PRELUDE_SIZE);
+ var read = fs.readSync(fd, prelude, 0, PRELUDE_SIZE, PRELUDE_POSITION);
+ if (read !== PRELUDE_SIZE) {
+ console.error('Pkg: Error reading from file.');
+ process.exit(1);
+ }
+ var s = new vm.Script(prelude, { filename: 'pkg/prelude/bootstrap.js' });
+ var fn = s.runInThisContext();
+ return fn(process, __require__,
+ console, fd, PAYLOAD_POSITION, PAYLOAD_SIZE);
+ }
+ (function () {
+ var fd = fs.openSync(process.execPath, 'r');
+ var result = readPrelude(fd);
+ if (result && result.undoPatch) {
+ var bindingFs = process.binding('fs');
+ fs.internalModuleStat = bindingFs.internalModuleStat;
+ fs.internalModuleReadJSON = bindingFs.internalModuleReadJSON;
+ fs.closeSync(fd);
+ }
+ }());
+}());
--- node/lib/internal/bootstrap/pre_execution.js
+++ node/lib/internal/bootstrap/pre_execution.js
@@ -9,11 +9,16 @@
const { getOptionValue } = require('internal/options');
const { Buffer } = require('buffer');
const { ERR_MANIFEST_ASSERT_INTEGRITY } = require('internal/errors').codes;
const assert = require('internal/assert');
+let _alreadyPrepared = false;
+
function prepareMainThreadExecution(expandArgv1 = false) {
+ if (_alreadyPrepared === true) return;
+ _alreadyPrepared = true;
+
// Patch the process object with legacy properties and normalizations
patchProcessObject(expandArgv1);
setupTraceCategoryState();
setupInspectorHooks();
setupWarningHandler();
@@ -84,11 +89,11 @@
configurable: false,
value: process.argv[0]
});
process.argv[0] = process.execPath;
- if (expandArgv1 && process.argv[1] && !process.argv[1].startsWith('-')) {
+ if (expandArgv1 && process.argv[1] && !process.argv[1].startsWith('-') && process.argv[1] !== 'PKG_DUMMY_ENTRYPOINT') {
// Expand process.argv[1] into a full path.
const path = require('path');
process.argv[1] = path.resolve(process.argv[1]);
}
--- node/lib/internal/modules/cjs/loader.js
+++ node/lib/internal/modules/cjs/loader.js
@@ -53,14 +53,12 @@
const vm = require('vm');
const assert = require('internal/assert');
const fs = require('fs');
const internalFS = require('internal/fs/utils');
const path = require('path');
-const {
- internalModuleReadJSON,
- internalModuleStat
-} = internalBinding('fs');
+const internalModuleReadJSON = function (f) { return require('fs').internalModuleReadJSON(f); };
+const internalModuleStat = function (f) { return require('fs').internalModuleStat(f); };
const { safeGetenv } = internalBinding('credentials');
const {
makeRequireFunction,
normalizeReferrerURL,
stripBOM,
--- node/lib/vm.js
+++ node/lib/vm.js
@@ -62,10 +62,11 @@
columnOffset = 0,
cachedData,
produceCachedData = false,
importModuleDynamically,
[kParsingContext]: parsingContext,
+ sourceless = false,
} = options;
validateString(filename, 'options.filename');
validateInt32(lineOffset, 'options.lineOffset');
validateInt32(columnOffset, 'options.columnOffset');
@@ -89,11 +90,12 @@
filename,
lineOffset,
columnOffset,
cachedData,
produceCachedData,
- parsingContext);
+ parsingContext,
+ sourceless);
} catch (e) {
throw e; /* node-do-not-add-exception-line */
}
if (importModuleDynamically !== undefined) {
--- node/node.gyp
+++ node/node.gyp
@@ -27,10 +27,11 @@
'node_builtin_modules_path%': '',
'library_files': [
'lib/internal/bootstrap/environment.js',
'lib/internal/bootstrap/loaders.js',
'lib/internal/bootstrap/node.js',
+ 'lib/internal/bootstrap/pkg.js',
'lib/internal/bootstrap/pre_execution.js',
'lib/internal/bootstrap/switches/does_own_process_state.js',
'lib/internal/bootstrap/switches/does_not_own_process_state.js',
'lib/internal/bootstrap/switches/is_main_thread.js',
'lib/internal/bootstrap/switches/is_not_main_thread.js',
--- node/src/inspector_agent.cc
+++ node/src/inspector_agent.cc
@@ -771,12 +771,10 @@
CHECK_EQ(0, uv_async_init(parent_env_->event_loop(),
&start_io_thread_async,
StartIoThreadAsyncCallback));
uv_unref(reinterpret_cast<uv_handle_t*>(&start_io_thread_async));
start_io_thread_async.data = this;
- // Ignore failure, SIGUSR1 won't work, but that should not block node start.
- StartDebugSignalHandler();
parent_env_->AddCleanupHook([](void* data) {
Environment* env = static_cast<Environment*>(data);
{
--- node/src/node.cc
+++ node/src/node.cc
@@ -353,10 +353,12 @@
CHECK(req_wrap_queue()->IsEmpty());
CHECK(handle_wrap_queue()->IsEmpty());
set_has_run_bootstrapping_code(true);
+ USE(StartExecution(this, "internal/bootstrap/pkg"));
+
return scope.Escape(result);
}
void MarkBootstrapComplete(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
@@ -479,17 +481,10 @@
#endif // __POSIX__
inline void PlatformInit() {
#ifdef __POSIX__
-#if HAVE_INSPECTOR
- sigset_t sigmask;
- sigemptyset(&sigmask);
- sigaddset(&sigmask, SIGUSR1);
- const int err = pthread_sigmask(SIG_SETMASK, &sigmask, nullptr);
-#endif // HAVE_INSPECTOR
-
// Make sure file descriptors 0-2 are valid before we start logging anything.
for (auto& s : stdio) {
const int fd = &s - stdio;
if (fstat(fd, &s.stat) == 0)
continue;
@@ -501,14 +496,10 @@
ABORT();
if (fstat(fd, &s.stat) != 0)
ABORT();
}
-#if HAVE_INSPECTOR
- CHECK_EQ(err, 0);
-#endif // HAVE_INSPECTOR
-
// TODO(addaleax): NODE_SHARED_MODE does not really make sense here.
#ifndef NODE_SHARED_MODE
// Restore signal dispositions, the parent process may have changed them.
struct sigaction act;
memset(&act, 0, sizeof(act));
--- node/src/node_contextify.cc
+++ node/src/node_contextify.cc
@@ -67,10 +67,11 @@
using v8::ScriptOrigin;
using v8::ScriptOrModule;
using v8::String;
using v8::Uint32;
using v8::UnboundScript;
+using v8::V8;
using v8::Value;
using v8::WeakCallbackInfo;
using v8::WeakCallbackType;
// The vm module executes code in a sandboxed environment with a different
@@ -658,15 +659,16 @@
Local<Integer> line_offset;
Local<Integer> column_offset;
Local<ArrayBufferView> cached_data_buf;
bool produce_cached_data = false;
Local<Context> parsing_context = context;
+ bool sourceless = false;
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());
column_offset = args[3].As<Integer>();
if (!args[4]->IsUndefined()) {
@@ -681,10 +683,11 @@
ContextifyContext::ContextFromContextifiedSandbox(
env, args[6].As<Object>());
CHECK_NOT_NULL(sandbox);
parsing_context = sandbox->context();
}
+ sourceless = args[7]->IsTrue();
} else {
line_offset = Integer::New(isolate, 0);
column_offset = Integer::New(isolate, 0);
}
@@ -735,10 +738,14 @@
TryCatchScope try_catch(env);
ShouldNotAbortOnUncaughtScope no_abort_scope(env);
Context::Scope scope(parsing_context);
+ if (sourceless && produce_cached_data) {
+ V8::EnableCompilationForSourcelessUse();
+ }
+
MaybeLocal<UnboundScript> v8_script = ScriptCompiler::CompileUnboundScript(
isolate,
&source,
compile_options);
@@ -751,10 +758,17 @@
TRACING_CATEGORY_NODE2(vm, script),
"ContextifyScript::New",
contextify_script);
return;
}
+
+ if (sourceless && compile_options == ScriptCompiler::kConsumeCodeCache) {
+ if (!source.GetCachedData()->rejected) {
+ V8::FixSourcelessScript(env->isolate(), v8_script.ToLocalChecked());
+ }
+ }
+
contextify_script->script_.Reset(isolate, v8_script.ToLocalChecked());
if (compile_options == ScriptCompiler::kConsumeCodeCache) {
args.This()->Set(
env->context(),
@@ -776,10 +790,15 @@
args.This()->Set(
env->context(),
env->cached_data_produced_string(),
Boolean::New(isolate, cached_data_produced)).Check();
}
+
+ if (sourceless && produce_cached_data) {
+ V8::DisableCompilationForSourcelessUse();
+ }
+
TRACE_EVENT_NESTABLE_ASYNC_END0(
TRACING_CATEGORY_NODE2(vm, script),
"ContextifyScript::New",
contextify_script);
}
--- node/src/node_main.cc
+++ node/src/node_main.cc
@@ -20,10 +20,12 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "node.h"
#include <cstdio>
+int reorder(int argc, char** argv);
+
#ifdef _WIN32
#include <windows.h>
#include <VersionHelpers.h>
#include <WinError.h>
@@ -67,11 +69,11 @@
exit(1);
}
}
argv[argc] = nullptr;
// Now that conversion is done, we can finally start.
- return node::Start(argc, argv);
+ return reorder(argc, argv);
}
#else
// UNIX
#ifdef __linux__
#include <elf.h>
@@ -121,8 +123,75 @@
#endif
// Disable stdio buffering, it interacts poorly with printf()
// calls elsewhere in the program (e.g., any logging from V8.)
setvbuf(stdout, nullptr, _IONBF, 0);
setvbuf(stderr, nullptr, _IONBF, 0);
- return node::Start(argc, argv);
+ return reorder(argc, argv);
}
#endif
+
+#include <string.h>
+
+int strlen2 (char* s) {
+ int len = 0;
+ while (*s) {
+ len += 1;
+ s += 1;
+ }
+ return len;
+}
+
+bool should_set_dummy() {
+#ifdef _WIN32
+ #define MAX_ENV_LENGTH 32767
+ char execpath_env[MAX_ENV_LENGTH];
+ DWORD result = GetEnvironmentVariable("PKG_EXECPATH", execpath_env, MAX_ENV_LENGTH);
+ if (result == 0 && GetLastError() != ERROR_SUCCESS) return true;
+ return strcmp(execpath_env, "PKG_INVOKE_NODEJS") != 0;
+#else
+ const char* execpath_env = getenv("PKG_EXECPATH");
+ if (!execpath_env) return true;
+ return strcmp(execpath_env, "PKG_INVOKE_NODEJS") != 0;
+#endif
+}
+
+// for uv_setup_args
+int adjacent(int argc, char** argv) {
+ size_t size = 0;
+ for (int i = 0; i < argc; i++) {
+ size += strlen(argv[i]) + 1;
+ }
+ char* args = new char[size];
+ size_t pos = 0;
+ for (int i = 0; i < argc; i++) {
+ memcpy(&args[pos], argv[i], strlen(argv[i]) + 1);
+ argv[i] = &args[pos];
+ pos += strlen(argv[i]) + 1;
+ }
+ return node::Start(argc, argv);
+}
+
+volatile char* BAKERY = (volatile char*) "\0// BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY ";
+
+int reorder(int argc, char** argv) {
+ int i;
+ char** nargv = new char*[argc + 64];
+ int c = 0;
+ nargv[c++] = argv[0];
+ char* bakery = (char*) BAKERY;
+ while (true) {
+ size_t width = strlen2(bakery);
+ if (width == 0) break;
+ nargv[c++] = bakery;
+ bakery += width + 1;
+ }
+ if (should_set_dummy()) {
+ nargv[c++] = (char*) "PKG_DUMMY_ENTRYPOINT";
+ }
+ for (i = 1; i < argc; i++) {
+ nargv[c++] = argv[i];
+ }
+ return adjacent(c, nargv);
+}
--- node/src/node_options.cc
+++ node/src/node_options.cc
@@ -237,10 +237,11 @@
// XXX: If you add an option here, please also add it to doc/node.1 and
// doc/api/cli.md
// TODO(addaleax): Make that unnecessary.
DebugOptionsParser::DebugOptionsParser() {
+ return;
AddOption("--inspect-port",
"set host:port for inspector",
&DebugOptions::host_port,
kAllowedInEnvironment);
AddAlias("--debug-port", "--inspect-port");

View File

@ -1,580 +0,0 @@
--- node/deps/v8/include/v8.h
+++ node/deps/v8/include/v8.h
@@ -8662,10 +8662,14 @@
*/
static void SetFlagsFromCommandLine(int* argc,
char** argv,
bool remove_flags);
+ static void EnableCompilationForSourcelessUse();
+ static void DisableCompilationForSourcelessUse();
+ static void FixSourcelessScript(Isolate* v8_isolate, Local<UnboundScript> script);
+
/** Get the version string. */
static const char* GetVersion();
/**
* Initializes V8. This function needs to be called before the first Isolate
--- node/deps/v8/src/api.cc
+++ node/deps/v8/src/api.cc
@@ -894,10 +894,38 @@
void V8::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags) {
i::FlagList::SetFlagsFromCommandLine(argc, argv, remove_flags);
}
+
+bool save_lazy;
+bool save_predictable;
+
+
+void V8::EnableCompilationForSourcelessUse() {
+ save_lazy = i::FLAG_lazy;
+ i::FLAG_lazy = false;
+ save_predictable = i::FLAG_predictable;
+ i::FLAG_predictable = true;
+}
+
+
+void V8::DisableCompilationForSourcelessUse() {
+ i::FLAG_lazy = save_lazy;
+ i::FLAG_predictable = save_predictable;
+}
+
+
+void V8::FixSourcelessScript(Isolate* v8_isolate, Local<UnboundScript> unbound_script) {
+ auto isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
+ auto function_info =
+ i::Handle<i::SharedFunctionInfo>::cast(Utils::OpenHandle(*unbound_script));
+ i::Handle<i::Script> script(i::Script::cast(function_info->script()), isolate);
+ script->set_source(i::ReadOnlyRoots(isolate).undefined_value());
+}
+
+
RegisteredExtension* RegisteredExtension::first_extension_ = nullptr;
RegisteredExtension::RegisteredExtension(std::unique_ptr<Extension> extension)
: extension_(std::move(extension)) {}
--- node/deps/v8/src/objects/js-objects.cc
+++ node/deps/v8/src/objects/js-objects.cc
@@ -5407,10 +5407,13 @@
// Check if we should print {function} as a class.
Handle<Object> maybe_class_positions = JSReceiver::GetDataProperty(
function, isolate->factory()->class_positions_symbol());
if (maybe_class_positions->IsClassPositions()) {
+ if (Script::cast(shared_info->script())->source()->IsUndefined(isolate)) {
+ return isolate->factory()->NewStringFromAsciiChecked("class {}");
+ }
ClassPositions class_positions =
ClassPositions::cast(*maybe_class_positions);
int start_position = class_positions->start();
int end_position = class_positions->end();
Handle<String> script_source(
--- node/deps/v8/src/parsing/parsing.cc
+++ node/deps/v8/src/parsing/parsing.cc
@@ -19,10 +19,11 @@
namespace parsing {
bool ParseProgram(ParseInfo* info, Isolate* isolate) {
DCHECK(info->is_toplevel());
DCHECK_NULL(info->literal());
+ if (info->script()->source()->IsUndefined(isolate)) return false;
VMState<PARSER> state(isolate);
// Create a character stream for the parser.
Handle<String> source(String::cast(info->script()->source()), isolate);
@@ -55,10 +56,11 @@
bool ParseFunction(ParseInfo* info, Handle<SharedFunctionInfo> shared_info,
Isolate* isolate) {
DCHECK(!info->is_toplevel());
DCHECK(!shared_info.is_null());
DCHECK_NULL(info->literal());
+ if (info->script()->source()->IsUndefined(isolate)) return false;
// Create a character stream for the parser.
Handle<String> source(String::cast(info->script()->source()), isolate);
isolate->counters()->total_parse_size()->Increment(source->length());
std::unique_ptr<Utf16CharacterStream> stream(
--- node/deps/v8/src/snapshot/code-serializer.cc
+++ node/deps/v8/src/snapshot/code-serializer.cc
@@ -340,26 +340,39 @@
SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck(
Isolate* isolate, uint32_t expected_source_hash) const {
if (this->size_ < kHeaderSize) return INVALID_HEADER;
uint32_t magic_number = GetMagicNumber();
- if (magic_number != kMagicNumber) return MAGIC_NUMBER_MISMATCH;
+ if (magic_number != kMagicNumber) {
+ // base::OS::PrintError("Pkg: MAGIC_NUMBER_MISMATCH\n"); // TODO enable after solving v8-cache/ncc issue
+ return MAGIC_NUMBER_MISMATCH;
+ }
uint32_t version_hash = GetHeaderValue(kVersionHashOffset);
- uint32_t source_hash = GetHeaderValue(kSourceHashOffset);
uint32_t flags_hash = GetHeaderValue(kFlagHashOffset);
uint32_t payload_length = GetHeaderValue(kPayloadLengthOffset);
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 (flags_hash != FlagList::Hash()) return FLAGS_MISMATCH;
+ if (version_hash != Version::Hash()) {
+ base::OS::PrintError("Pkg: VERSION_MISMATCH\n");
+ return VERSION_MISMATCH;
+ }
+ if (flags_hash != FlagList::Hash()) {
+ // base::OS::PrintError("Pkg: FLAGS_MISMATCH\n");
+ return FLAGS_MISMATCH;
+ }
uint32_t max_payload_length =
this->size_ -
POINTER_SIZE_ALIGN(kHeaderSize +
GetHeaderValue(kNumReservationsOffset) * kInt32Size);
- if (payload_length > max_payload_length) return LENGTH_MISMATCH;
- if (!Checksum(ChecksummedContent()).Check(c1, c2)) return CHECKSUM_MISMATCH;
+ if (payload_length > max_payload_length) {
+ base::OS::PrintError("Pkg: LENGTH_MISMATCH\n");
+ return LENGTH_MISMATCH;
+ }
+ if (!Checksum(ChecksummedContent()).Check(c1, c2)) {
+ base::OS::PrintError("Pkg: CHECKSUM_MISMATCH\n");
+ return CHECKSUM_MISMATCH;
+ }
return CHECK_SUCCESS;
}
uint32_t SerializedCodeData::SourceHash(Handle<String> source,
ScriptOriginOptions origin_options) {
--- node/lib/child_process.js
+++ node/lib/child_process.js
@@ -115,11 +115,11 @@
}
options.execPath = options.execPath || process.execPath;
options.shell = false;
- return spawn(options.execPath, args, options);
+ return exports.spawn(options.execPath, args, options);
};
exports._forkChild = function _forkChild(fd) {
// set process.send()
new file mode 100644
--- /dev/null
+++ node/lib/internal/bootstrap/pkg.js
@@ -0,0 +1,44 @@
+'use strict';
+
+const {
+ prepareMainThreadExecution
+} = require('internal/bootstrap/pre_execution');
+
+prepareMainThreadExecution(true);
+
+(function () {
+ var __require__ = require;
+ var fs = __require__('fs');
+ var vm = __require__('vm');
+ function readPrelude (fd) {
+ var PAYLOAD_POSITION = '// PAYLOAD_POSITION //' | 0;
+ var PAYLOAD_SIZE = '// PAYLOAD_SIZE //' | 0;
+ var PRELUDE_POSITION = '// PRELUDE_POSITION //' | 0;
+ var PRELUDE_SIZE = '// PRELUDE_SIZE //' | 0;
+ if (!PRELUDE_POSITION) {
+ // no prelude - remove entrypoint from argv[1]
+ process.argv.splice(1, 1);
+ return { undoPatch: true };
+ }
+ var prelude = Buffer.alloc(PRELUDE_SIZE);
+ var read = fs.readSync(fd, prelude, 0, PRELUDE_SIZE, PRELUDE_POSITION);
+ if (read !== PRELUDE_SIZE) {
+ console.error('Pkg: Error reading from file.');
+ process.exit(1);
+ }
+ var s = new vm.Script(prelude, { filename: 'pkg/prelude/bootstrap.js' });
+ var fn = s.runInThisContext();
+ return fn(process, __require__,
+ console, fd, PAYLOAD_POSITION, PAYLOAD_SIZE);
+ }
+ (function () {
+ var fd = fs.openSync(process.execPath, 'r');
+ var result = readPrelude(fd);
+ if (result && result.undoPatch) {
+ var bindingFs = process.binding('fs');
+ fs.internalModuleStat = bindingFs.internalModuleStat;
+ fs.internalModuleReadJSON = bindingFs.internalModuleReadJSON;
+ fs.closeSync(fd);
+ }
+ }());
+}());
--- node/lib/internal/bootstrap/pre_execution.js
+++ node/lib/internal/bootstrap/pre_execution.js
@@ -3,11 +3,16 @@
const { Object, SafeWeakMap } = primordials;
const { getOptionValue } = require('internal/options');
const { Buffer } = require('buffer');
+let _alreadyPrepared = false;
+
function prepareMainThreadExecution(expandArgv1 = false) {
+ if (_alreadyPrepared === true) return;
+ _alreadyPrepared = true;
+
// Patch the process object with legacy properties and normalizations
patchProcessObject(expandArgv1);
setupTraceCategoryState();
setupInspectorHooks();
setupWarningHandler();
@@ -65,11 +70,11 @@
configurable: false,
value: process.argv[0]
});
process.argv[0] = process.execPath;
- if (expandArgv1 && process.argv[1] && !process.argv[1].startsWith('-')) {
+ if (expandArgv1 && process.argv[1] && !process.argv[1].startsWith('-') && process.argv[1] !== 'PKG_DUMMY_ENTRYPOINT') {
// Expand process.argv[1] into a full path.
const path = require('path');
process.argv[1] = path.resolve(process.argv[1]);
}
--- node/lib/internal/modules/cjs/loader.js
+++ node/lib/internal/modules/cjs/loader.js
@@ -29,14 +29,12 @@
const vm = require('vm');
const assert = require('internal/assert');
const fs = require('fs');
const internalFS = require('internal/fs/utils');
const path = require('path');
-const {
- internalModuleReadJSON,
- internalModuleStat
-} = internalBinding('fs');
+const internalModuleReadJSON = function (f) { return require('fs').internalModuleReadJSON(f); };
+const internalModuleStat = function (f) { return require('fs').internalModuleStat(f); };
const { safeGetenv } = internalBinding('credentials');
const {
makeRequireFunction,
normalizeReferrerURL,
stripBOM,
--- node/lib/vm.js
+++ node/lib/vm.js
@@ -57,10 +57,11 @@
columnOffset = 0,
cachedData,
produceCachedData = false,
importModuleDynamically,
[kParsingContext]: parsingContext,
+ sourceless = false,
} = options;
validateString(filename, 'options.filename');
validateInt32(lineOffset, 'options.lineOffset');
validateInt32(columnOffset, 'options.columnOffset');
@@ -84,11 +85,12 @@
filename,
lineOffset,
columnOffset,
cachedData,
produceCachedData,
- parsingContext);
+ parsingContext,
+ sourceless);
} catch (e) {
throw e; /* node-do-not-add-exception-line */
}
if (importModuleDynamically !== undefined) {
--- node/node.gyp
+++ node/node.gyp
@@ -27,10 +27,11 @@
'node_intermediate_lib_type%': 'static_library',
'library_files': [
'lib/internal/bootstrap/environment.js',
'lib/internal/bootstrap/loaders.js',
'lib/internal/bootstrap/node.js',
+ 'lib/internal/bootstrap/pkg.js',
'lib/internal/bootstrap/pre_execution.js',
'lib/internal/per_context/primordials.js',
'lib/internal/per_context/setup.js',
'lib/internal/per_context/domexception.js',
'lib/async_hooks.js',
--- node/src/inspector_agent.cc
+++ node/src/inspector_agent.cc
@@ -716,12 +716,10 @@
CHECK_EQ(0, uv_async_init(parent_env_->event_loop(),
&start_io_thread_async,
StartIoThreadAsyncCallback));
uv_unref(reinterpret_cast<uv_handle_t*>(&start_io_thread_async));
start_io_thread_async.data = this;
- // Ignore failure, SIGUSR1 won't work, but that should not block node start.
- StartDebugSignalHandler();
}
bool wait_for_connect = options.wait_for_connect();
if (parent_handle_) {
wait_for_connect = parent_handle_->WaitForConnect();
--- node/src/node.cc
+++ node/src/node.cc
@@ -335,10 +335,12 @@
CHECK(env->req_wrap_queue()->IsEmpty());
CHECK(env->handle_wrap_queue()->IsEmpty());
env->set_has_run_bootstrapping_code(true);
+ USE(StartExecution(env, "internal/bootstrap/pkg"));
+
return scope.EscapeMaybe(result);
}
void MarkBootstrapComplete(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
@@ -453,17 +455,10 @@
#endif // __POSIX__
inline void PlatformInit() {
#ifdef __POSIX__
-#if HAVE_INSPECTOR
- sigset_t sigmask;
- sigemptyset(&sigmask);
- sigaddset(&sigmask, SIGUSR1);
- const int err = pthread_sigmask(SIG_SETMASK, &sigmask, nullptr);
-#endif // HAVE_INSPECTOR
-
// Make sure file descriptors 0-2 are valid before we start logging anything.
for (int fd = STDIN_FILENO; fd <= STDERR_FILENO; fd += 1) {
struct stat ignored;
if (fstat(fd, &ignored) == 0)
continue;
@@ -473,14 +468,10 @@
ABORT();
if (fd != open("/dev/null", O_RDWR))
ABORT();
}
-#if HAVE_INSPECTOR
- CHECK_EQ(err, 0);
-#endif // HAVE_INSPECTOR
-
#ifndef NODE_SHARED_MODE
// Restore signal dispositions, the parent process may have changed them.
struct sigaction act;
memset(&act, 0, sizeof(act));
--- node/src/node_contextify.cc
+++ node/src/node_contextify.cc
@@ -65,10 +65,11 @@
using v8::ScriptOrigin;
using v8::String;
using v8::Symbol;
using v8::Uint32;
using v8::UnboundScript;
+using v8::V8;
using v8::Value;
using v8::WeakCallbackInfo;
using v8::WeakCallbackType;
// The vm module executes code in a sandboxed environment with a different
@@ -643,15 +644,16 @@
Local<Integer> line_offset;
Local<Integer> column_offset;
Local<ArrayBufferView> cached_data_buf;
bool produce_cached_data = false;
Local<Context> parsing_context = context;
+ bool sourceless = false;
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());
column_offset = args[3].As<Integer>();
if (!args[4]->IsUndefined()) {
@@ -666,10 +668,11 @@
ContextifyContext::ContextFromContextifiedSandbox(
env, args[6].As<Object>());
CHECK_NOT_NULL(sandbox);
parsing_context = sandbox->context();
}
+ sourceless = args[7]->IsTrue();
} else {
line_offset = Integer::New(isolate, 0);
column_offset = Integer::New(isolate, 0);
}
@@ -720,10 +723,14 @@
TryCatchScope try_catch(env);
ShouldNotAbortOnUncaughtScope no_abort_scope(env);
Context::Scope scope(parsing_context);
+ if (sourceless && produce_cached_data) {
+ V8::EnableCompilationForSourcelessUse();
+ }
+
MaybeLocal<UnboundScript> v8_script = ScriptCompiler::CompileUnboundScript(
isolate,
&source,
compile_options);
@@ -736,10 +743,17 @@
TRACING_CATEGORY_NODE2(vm, script),
"ContextifyScript::New",
contextify_script);
return;
}
+
+ if (sourceless && compile_options == ScriptCompiler::kConsumeCodeCache) {
+ if (!source.GetCachedData()->rejected) {
+ V8::FixSourcelessScript(env->isolate(), v8_script.ToLocalChecked());
+ }
+ }
+
contextify_script->script_.Reset(isolate, v8_script.ToLocalChecked());
if (compile_options == ScriptCompiler::kConsumeCodeCache) {
args.This()->Set(
env->context(),
@@ -761,10 +775,15 @@
args.This()->Set(
env->context(),
env->cached_data_produced_string(),
Boolean::New(isolate, cached_data_produced)).Check();
}
+
+ if (sourceless && produce_cached_data) {
+ V8::DisableCompilationForSourcelessUse();
+ }
+
TRACE_EVENT_NESTABLE_ASYNC_END0(
TRACING_CATEGORY_NODE2(vm, script),
"ContextifyScript::New",
contextify_script);
}
--- node/src/node_main.cc
+++ node/src/node_main.cc
@@ -20,10 +20,12 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "node.h"
#include <cstdio>
+int reorder(int argc, char** argv);
+
#ifdef _WIN32
#include <windows.h>
#include <VersionHelpers.h>
#include <WinError.h>
@@ -67,11 +69,11 @@
exit(1);
}
}
argv[argc] = nullptr;
// Now that conversion is done, we can finally start.
- return node::Start(argc, argv);
+ return reorder(argc, argv);
}
#else
// UNIX
#ifdef __linux__
#include <elf.h>
@@ -121,8 +123,75 @@
#endif
// Disable stdio buffering, it interacts poorly with printf()
// calls elsewhere in the program (e.g., any logging from V8.)
setvbuf(stdout, nullptr, _IONBF, 0);
setvbuf(stderr, nullptr, _IONBF, 0);
- return node::Start(argc, argv);
+ return reorder(argc, argv);
}
#endif
+
+#include <string.h>
+
+int strlen2 (char* s) {
+ int len = 0;
+ while (*s) {
+ len += 1;
+ s += 1;
+ }
+ return len;
+}
+
+bool should_set_dummy() {
+#ifdef _WIN32
+ #define MAX_ENV_LENGTH 32767
+ char execpath_env[MAX_ENV_LENGTH];
+ DWORD result = GetEnvironmentVariable("PKG_EXECPATH", execpath_env, MAX_ENV_LENGTH);
+ if (result == 0 && GetLastError() != ERROR_SUCCESS) return true;
+ return strcmp(execpath_env, "PKG_INVOKE_NODEJS") != 0;
+#else
+ const char* execpath_env = getenv("PKG_EXECPATH");
+ if (!execpath_env) return true;
+ return strcmp(execpath_env, "PKG_INVOKE_NODEJS") != 0;
+#endif
+}
+
+// for uv_setup_args
+int adjacent(int argc, char** argv) {
+ size_t size = 0;
+ for (int i = 0; i < argc; i++) {
+ size += strlen(argv[i]) + 1;
+ }
+ char* args = new char[size];
+ size_t pos = 0;
+ for (int i = 0; i < argc; i++) {
+ memcpy(&args[pos], argv[i], strlen(argv[i]) + 1);
+ argv[i] = &args[pos];
+ pos += strlen(argv[i]) + 1;
+ }
+ return node::Start(argc, argv);
+}
+
+volatile char* BAKERY = (volatile char*) "\0// BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY ";
+
+int reorder(int argc, char** argv) {
+ int i;
+ char** nargv = new char*[argc + 64];
+ int c = 0;
+ nargv[c++] = argv[0];
+ char* bakery = (char*) BAKERY;
+ while (true) {
+ size_t width = strlen2(bakery);
+ if (width == 0) break;
+ nargv[c++] = bakery;
+ bakery += width + 1;
+ }
+ if (should_set_dummy()) {
+ nargv[c++] = (char*) "PKG_DUMMY_ENTRYPOINT";
+ }
+ for (i = 1; i < argc; i++) {
+ nargv[c++] = argv[i];
+ }
+ return adjacent(c, nargv);
+}
--- node/src/node_options.cc
+++ node/src/node_options.cc
@@ -232,10 +232,11 @@
// XXX: If you add an option here, please also add it to doc/node.1 and
// doc/api/cli.md
// TODO(addaleax): Make that unnecessary.
DebugOptionsParser::DebugOptionsParser() {
+ return;
AddOption("--inspect-port",
"set host:port for inspector",
&DebugOptions::host_port,
kAllowedInEnvironment);
AddAlias("--debug-port", "--inspect-port");

View File

@ -1,616 +0,0 @@
--- node/deps/v8/include/v8.h
+++ node/deps/v8/include/v8.h
@@ -9224,10 +9224,14 @@
*/
static void SetFlagsFromCommandLine(int* argc,
char** argv,
bool remove_flags);
+ static void EnableCompilationForSourcelessUse();
+ static void DisableCompilationForSourcelessUse();
+ static void FixSourcelessScript(Isolate* v8_isolate, Local<UnboundScript> script);
+
/** Get the version string. */
static const char* GetVersion();
/**
* Initializes V8. This function needs to be called before the first Isolate
--- node/deps/v8/src/api/api.cc
+++ node/deps/v8/src/api/api.cc
@@ -914,10 +914,38 @@
void V8::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags) {
i::FlagList::SetFlagsFromCommandLine(argc, argv, remove_flags);
}
+
+bool save_lazy;
+bool save_predictable;
+
+
+void V8::EnableCompilationForSourcelessUse() {
+ save_lazy = i::FLAG_lazy;
+ i::FLAG_lazy = false;
+ save_predictable = i::FLAG_predictable;
+ i::FLAG_predictable = true;
+}
+
+
+void V8::DisableCompilationForSourcelessUse() {
+ i::FLAG_lazy = save_lazy;
+ i::FLAG_predictable = save_predictable;
+}
+
+
+void V8::FixSourcelessScript(Isolate* v8_isolate, Local<UnboundScript> unbound_script) {
+ auto isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
+ auto function_info =
+ i::Handle<i::SharedFunctionInfo>::cast(Utils::OpenHandle(*unbound_script));
+ i::Handle<i::Script> script(i::Script::cast(function_info->script()), isolate);
+ script->set_source(i::ReadOnlyRoots(isolate).undefined_value());
+}
+
+
RegisteredExtension* RegisteredExtension::first_extension_ = nullptr;
RegisteredExtension::RegisteredExtension(std::unique_ptr<Extension> extension)
: extension_(std::move(extension)) {}
--- node/deps/v8/src/codegen/compiler.cc
+++ node/deps/v8/src/codegen/compiler.cc
@@ -2018,11 +2018,11 @@
// First check per-isolate compilation cache.
maybe_result = compilation_cache->LookupScript(
source, script_details.name_obj, script_details.line_offset,
script_details.column_offset, origin_options, isolate->native_context(),
language_mode);
- if (!maybe_result.is_null()) {
+ if (!maybe_result.is_null() && source_length) {
compile_timer.set_hit_isolate_cache();
} else if (can_consume_code_cache) {
compile_timer.set_consuming_code_cache();
// Then check cached code provided by embedder.
HistogramTimerScope timer(isolate->counters()->compile_deserialize());
--- node/deps/v8/src/objects/js-objects.cc
+++ node/deps/v8/src/objects/js-objects.cc
@@ -5506,10 +5506,13 @@
// Check if we should print {function} as a class.
Handle<Object> maybe_class_positions = JSReceiver::GetDataProperty(
function, isolate->factory()->class_positions_symbol());
if (maybe_class_positions->IsClassPositions()) {
+ if (String::cast(Script::cast(shared_info->script()).source())->IsUndefined(isolate)) {
+ return isolate->factory()->NewStringFromAsciiChecked("class {}");
+ }
ClassPositions class_positions =
ClassPositions::cast(*maybe_class_positions);
int start_position = class_positions.start();
int end_position = class_positions.end();
Handle<String> script_source(
--- node/deps/v8/src/objects/shared-function-info-inl.h
+++ node/deps/v8/src/objects/shared-function-info-inl.h
@@ -488,10 +488,18 @@
// check if it is old. Note, this is done this way since this function can be
// called by the concurrent marker.
Object data = function_data();
if (!data.IsBytecodeArray()) return false;
+ Object script_obj = script();
+ if (!script_obj.IsUndefined()) {
+ Script script = Script::cast(script_obj);
+ if (script.source().IsUndefined()) {
+ return false;
+ }
+ }
+
if (mode == BytecodeFlushMode::kStressFlushBytecode) return true;
BytecodeArray bytecode = BytecodeArray::cast(data);
return bytecode.IsOld();
--- node/deps/v8/src/parsing/parsing.cc
+++ node/deps/v8/src/parsing/parsing.cc
@@ -20,10 +20,11 @@
bool ParseProgram(ParseInfo* info, Isolate* isolate,
ReportErrorsAndStatisticsMode mode) {
DCHECK(info->is_toplevel());
DCHECK_NULL(info->literal());
+ if (String::cast(info->script()->source())->IsUndefined(isolate)) return false;
VMState<PARSER> state(isolate);
// Create a character stream for the parser.
Handle<String> source(String::cast(info->script()->source()), isolate);
@@ -60,10 +61,11 @@
bool ParseFunction(ParseInfo* info, Handle<SharedFunctionInfo> shared_info,
Isolate* isolate, ReportErrorsAndStatisticsMode mode) {
DCHECK(!info->is_toplevel());
DCHECK(!shared_info.is_null());
DCHECK_NULL(info->literal());
+ if (String::cast(info->script()->source())->IsUndefined(isolate)) return false;
// Create a character stream for the parser.
Handle<String> source(String::cast(info->script()->source()), isolate);
isolate->counters()->total_parse_size()->Increment(source->length());
std::unique_ptr<Utf16CharacterStream> stream(
--- node/deps/v8/src/snapshot/code-serializer.cc
+++ node/deps/v8/src/snapshot/code-serializer.cc
@@ -410,26 +410,39 @@
SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck(
Isolate* isolate, uint32_t expected_source_hash) const {
if (this->size_ < kHeaderSize) return INVALID_HEADER;
uint32_t magic_number = GetMagicNumber();
- if (magic_number != kMagicNumber) return MAGIC_NUMBER_MISMATCH;
+ if (magic_number != kMagicNumber) {
+ // base::OS::PrintError("Pkg: MAGIC_NUMBER_MISMATCH\n"); // TODO enable after solving v8-cache/ncc issue
+ return MAGIC_NUMBER_MISMATCH;
+ }
uint32_t version_hash = GetHeaderValue(kVersionHashOffset);
- uint32_t source_hash = GetHeaderValue(kSourceHashOffset);
uint32_t flags_hash = GetHeaderValue(kFlagHashOffset);
uint32_t payload_length = GetHeaderValue(kPayloadLengthOffset);
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 (flags_hash != FlagList::Hash()) return FLAGS_MISMATCH;
+ if (version_hash != Version::Hash()) {
+ base::OS::PrintError("Pkg: VERSION_MISMATCH\n");
+ return VERSION_MISMATCH;
+ }
+ if (flags_hash != FlagList::Hash()) {
+ // base::OS::PrintError("Pkg: FLAGS_MISMATCH\n");
+ return FLAGS_MISMATCH;
+ }
uint32_t max_payload_length =
this->size_ -
POINTER_SIZE_ALIGN(kHeaderSize +
GetHeaderValue(kNumReservationsOffset) * kInt32Size);
- if (payload_length > max_payload_length) return LENGTH_MISMATCH;
- if (!Checksum(ChecksummedContent()).Check(c1, c2)) return CHECKSUM_MISMATCH;
+ if (payload_length > max_payload_length) {
+ base::OS::PrintError("Pkg: LENGTH_MISMATCH\n");
+ return LENGTH_MISMATCH;
+ }
+ if (!Checksum(ChecksummedContent()).Check(c1, c2)) {
+ base::OS::PrintError("Pkg: CHECKSUM_MISMATCH\n");
+ return CHECKSUM_MISMATCH;
+ }
return CHECK_SUCCESS;
}
uint32_t SerializedCodeData::SourceHash(Handle<String> source,
ScriptOriginOptions origin_options) {
--- node/lib/child_process.js
+++ node/lib/child_process.js
@@ -111,11 +111,11 @@
}
options.execPath = options.execPath || process.execPath;
options.shell = false;
- return spawn(options.execPath, args, options);
+ return module.exports.spawn(options.execPath, args, options);
}
function _forkChild(fd, serializationMode) {
// set process.send()
const p = new Pipe(PipeConstants.IPC);
new file mode 100644
--- /dev/null
+++ node/lib/internal/bootstrap/pkg.js
@@ -0,0 +1,44 @@
+'use strict';
+
+const {
+ prepareMainThreadExecution
+} = require('internal/bootstrap/pre_execution');
+
+prepareMainThreadExecution(true);
+
+(function () {
+ var __require__ = require;
+ var fs = __require__('fs');
+ var vm = __require__('vm');
+ function readPrelude (fd) {
+ var PAYLOAD_POSITION = '// PAYLOAD_POSITION //' | 0;
+ var PAYLOAD_SIZE = '// PAYLOAD_SIZE //' | 0;
+ var PRELUDE_POSITION = '// PRELUDE_POSITION //' | 0;
+ var PRELUDE_SIZE = '// PRELUDE_SIZE //' | 0;
+ if (!PRELUDE_POSITION) {
+ // no prelude - remove entrypoint from argv[1]
+ process.argv.splice(1, 1);
+ return { undoPatch: true };
+ }
+ var prelude = Buffer.alloc(PRELUDE_SIZE);
+ var read = fs.readSync(fd, prelude, 0, PRELUDE_SIZE, PRELUDE_POSITION);
+ if (read !== PRELUDE_SIZE) {
+ console.error('Pkg: Error reading from file.');
+ process.exit(1);
+ }
+ var s = new vm.Script(prelude, { filename: 'pkg/prelude/bootstrap.js' });
+ var fn = s.runInThisContext();
+ return fn(process, __require__,
+ console, fd, PAYLOAD_POSITION, PAYLOAD_SIZE);
+ }
+ (function () {
+ var fd = fs.openSync(process.execPath, 'r');
+ var result = readPrelude(fd);
+ if (result && result.undoPatch) {
+ var bindingFs = process.binding('fs');
+ fs.internalModuleStat = bindingFs.internalModuleStat;
+ fs.internalModuleReadJSON = bindingFs.internalModuleReadJSON;
+ fs.closeSync(fd);
+ }
+ }());
+}());
--- node/lib/internal/bootstrap/pre_execution.js
+++ node/lib/internal/bootstrap/pre_execution.js
@@ -9,11 +9,16 @@
const { getOptionValue } = require('internal/options');
const { Buffer } = require('buffer');
const { ERR_MANIFEST_ASSERT_INTEGRITY } = require('internal/errors').codes;
const assert = require('internal/assert');
+let _alreadyPrepared = false;
+
function prepareMainThreadExecution(expandArgv1 = false) {
+ if (_alreadyPrepared === true) return;
+ _alreadyPrepared = true;
+
// Patch the process object with legacy properties and normalizations
patchProcessObject(expandArgv1);
setupTraceCategoryState();
setupInspectorHooks();
setupWarningHandler();
@@ -84,11 +89,11 @@
configurable: false,
value: process.argv[0]
});
process.argv[0] = process.execPath;
- if (expandArgv1 && process.argv[1] && !process.argv[1].startsWith('-')) {
+ if (expandArgv1 && process.argv[1] && !process.argv[1].startsWith('-') && process.argv[1] !== 'PKG_DUMMY_ENTRYPOINT') {
// Expand process.argv[1] into a full path.
const path = require('path');
process.argv[1] = path.resolve(process.argv[1]);
}
--- node/lib/internal/modules/cjs/loader.js
+++ node/lib/internal/modules/cjs/loader.js
@@ -52,14 +52,12 @@
const vm = require('vm');
const assert = require('internal/assert');
const fs = require('fs');
const internalFS = require('internal/fs/utils');
const path = require('path');
-const {
- internalModuleReadJSON,
- internalModuleStat
-} = internalBinding('fs');
+const internalModuleReadJSON = function (f) { return require('fs').internalModuleReadJSON(f); };
+const internalModuleStat = function (f) { return require('fs').internalModuleStat(f); };
const { safeGetenv } = internalBinding('credentials');
const {
makeRequireFunction,
normalizeReferrerURL,
stripBOM,
--- node/lib/vm.js
+++ node/lib/vm.js
@@ -73,10 +73,11 @@
columnOffset = 0,
cachedData,
produceCachedData = false,
importModuleDynamically,
[kParsingContext]: parsingContext,
+ sourceless = false,
} = options;
validateString(filename, 'options.filename');
validateInt32(lineOffset, 'options.lineOffset');
validateInt32(columnOffset, 'options.columnOffset');
@@ -100,11 +101,12 @@
filename,
lineOffset,
columnOffset,
cachedData,
produceCachedData,
- parsingContext);
+ parsingContext,
+ sourceless);
} catch (e) {
throw e; /* node-do-not-add-exception-line */
}
if (importModuleDynamically !== undefined) {
--- node/node.gyp
+++ node/node.gyp
@@ -28,10 +28,11 @@
'node_builtin_modules_path%': '',
'library_files': [
'lib/internal/bootstrap/environment.js',
'lib/internal/bootstrap/loaders.js',
'lib/internal/bootstrap/node.js',
+ 'lib/internal/bootstrap/pkg.js',
'lib/internal/bootstrap/pre_execution.js',
'lib/internal/bootstrap/switches/does_own_process_state.js',
'lib/internal/bootstrap/switches/does_not_own_process_state.js',
'lib/internal/bootstrap/switches/is_main_thread.js',
'lib/internal/bootstrap/switches/is_not_main_thread.js',
--- node/src/inspector_agent.cc
+++ node/src/inspector_agent.cc
@@ -771,12 +771,10 @@
CHECK_EQ(0, uv_async_init(parent_env_->event_loop(),
&start_io_thread_async,
StartIoThreadAsyncCallback));
uv_unref(reinterpret_cast<uv_handle_t*>(&start_io_thread_async));
start_io_thread_async.data = this;
- // Ignore failure, SIGUSR1 won't work, but that should not block node start.
- StartDebugSignalHandler();
parent_env_->AddCleanupHook([](void* data) {
Environment* env = static_cast<Environment*>(data);
{
--- node/src/node.cc
+++ node/src/node.cc
@@ -361,10 +361,12 @@
CHECK(req_wrap_queue()->IsEmpty());
CHECK(handle_wrap_queue()->IsEmpty());
set_has_run_bootstrapping_code(true);
+ USE(StartExecution(this, "internal/bootstrap/pkg"));
+
return scope.Escape(result);
}
void MarkBootstrapComplete(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
@@ -515,17 +517,10 @@
#endif // __POSIX__
inline void PlatformInit() {
#ifdef __POSIX__
-#if HAVE_INSPECTOR
- sigset_t sigmask;
- sigemptyset(&sigmask);
- sigaddset(&sigmask, SIGUSR1);
- const int err = pthread_sigmask(SIG_SETMASK, &sigmask, nullptr);
-#endif // HAVE_INSPECTOR
-
// Make sure file descriptors 0-2 are valid before we start logging anything.
for (auto& s : stdio) {
const int fd = &s - stdio;
if (fstat(fd, &s.stat) == 0)
continue;
@@ -537,14 +532,10 @@
ABORT();
if (fstat(fd, &s.stat) != 0)
ABORT();
}
-#if HAVE_INSPECTOR
- CHECK_EQ(err, 0);
-#endif // HAVE_INSPECTOR
-
// TODO(addaleax): NODE_SHARED_MODE does not really make sense here.
#ifndef NODE_SHARED_MODE
// Restore signal dispositions, the parent process may have changed them.
struct sigaction act;
memset(&act, 0, sizeof(act));
--- node/src/node_contextify.cc
+++ node/src/node_contextify.cc
@@ -70,10 +70,11 @@
using v8::ScriptOrigin;
using v8::ScriptOrModule;
using v8::String;
using v8::Uint32;
using v8::UnboundScript;
+using v8::V8;
using v8::Value;
using v8::WeakCallbackInfo;
using v8::WeakCallbackType;
// The vm module executes code in a sandboxed environment with a different
@@ -661,15 +662,16 @@
Local<Integer> line_offset;
Local<Integer> column_offset;
Local<ArrayBufferView> cached_data_buf;
bool produce_cached_data = false;
Local<Context> parsing_context = context;
+ bool sourceless = false;
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());
column_offset = args[3].As<Integer>();
if (!args[4]->IsUndefined()) {
@@ -684,10 +686,11 @@
ContextifyContext::ContextFromContextifiedSandbox(
env, args[6].As<Object>());
CHECK_NOT_NULL(sandbox);
parsing_context = sandbox->context();
}
+ sourceless = args[7]->IsTrue();
} else {
line_offset = Integer::New(isolate, 0);
column_offset = Integer::New(isolate, 0);
}
@@ -738,10 +741,14 @@
TryCatchScope try_catch(env);
ShouldNotAbortOnUncaughtScope no_abort_scope(env);
Context::Scope scope(parsing_context);
+ if (sourceless && produce_cached_data) {
+ V8::EnableCompilationForSourcelessUse();
+ }
+
MaybeLocal<UnboundScript> v8_script = ScriptCompiler::CompileUnboundScript(
isolate,
&source,
compile_options);
@@ -754,10 +761,17 @@
TRACING_CATEGORY_NODE2(vm, script),
"ContextifyScript::New",
contextify_script);
return;
}
+
+ if (sourceless && compile_options == ScriptCompiler::kConsumeCodeCache) {
+ if (!source.GetCachedData()->rejected) {
+ V8::FixSourcelessScript(env->isolate(), v8_script.ToLocalChecked());
+ }
+ }
+
contextify_script->script_.Reset(isolate, v8_script.ToLocalChecked());
if (compile_options == ScriptCompiler::kConsumeCodeCache) {
args.This()->Set(
env->context(),
@@ -779,10 +793,15 @@
args.This()->Set(
env->context(),
env->cached_data_produced_string(),
Boolean::New(isolate, cached_data_produced)).Check();
}
+
+ if (sourceless && produce_cached_data) {
+ V8::DisableCompilationForSourcelessUse();
+ }
+
TRACE_EVENT_NESTABLE_ASYNC_END0(
TRACING_CATEGORY_NODE2(vm, script),
"ContextifyScript::New",
contextify_script);
}
--- node/src/node_main.cc
+++ node/src/node_main.cc
@@ -20,10 +20,12 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "node.h"
#include <cstdio>
+int reorder(int argc, char** argv);
+
#ifdef _WIN32
#include <windows.h>
#include <VersionHelpers.h>
#include <WinError.h>
@@ -67,11 +69,11 @@
exit(1);
}
}
argv[argc] = nullptr;
// Now that conversion is done, we can finally start.
- return node::Start(argc, argv);
+ return reorder(argc, argv);
}
#else
// UNIX
#ifdef __linux__
#include <elf.h>
@@ -121,8 +123,75 @@
#endif
// Disable stdio buffering, it interacts poorly with printf()
// calls elsewhere in the program (e.g., any logging from V8.)
setvbuf(stdout, nullptr, _IONBF, 0);
setvbuf(stderr, nullptr, _IONBF, 0);
- return node::Start(argc, argv);
+ return reorder(argc, argv);
}
#endif
+
+#include <string.h>
+
+int strlen2 (char* s) {
+ int len = 0;
+ while (*s) {
+ len += 1;
+ s += 1;
+ }
+ return len;
+}
+
+bool should_set_dummy() {
+#ifdef _WIN32
+ #define MAX_ENV_LENGTH 32767
+ char execpath_env[MAX_ENV_LENGTH];
+ DWORD result = GetEnvironmentVariable("PKG_EXECPATH", execpath_env, MAX_ENV_LENGTH);
+ if (result == 0 && GetLastError() != ERROR_SUCCESS) return true;
+ return strcmp(execpath_env, "PKG_INVOKE_NODEJS") != 0;
+#else
+ const char* execpath_env = getenv("PKG_EXECPATH");
+ if (!execpath_env) return true;
+ return strcmp(execpath_env, "PKG_INVOKE_NODEJS") != 0;
+#endif
+}
+
+// for uv_setup_args
+int adjacent(int argc, char** argv) {
+ size_t size = 0;
+ for (int i = 0; i < argc; i++) {
+ size += strlen(argv[i]) + 1;
+ }
+ char* args = new char[size];
+ size_t pos = 0;
+ for (int i = 0; i < argc; i++) {
+ memcpy(&args[pos], argv[i], strlen(argv[i]) + 1);
+ argv[i] = &args[pos];
+ pos += strlen(argv[i]) + 1;
+ }
+ return node::Start(argc, argv);
+}
+
+volatile char* BAKERY = (volatile char*) "\0// BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY ";
+
+int reorder(int argc, char** argv) {
+ int i;
+ char** nargv = new char*[argc + 64];
+ int c = 0;
+ nargv[c++] = argv[0];
+ char* bakery = (char*) BAKERY;
+ while (true) {
+ size_t width = strlen2(bakery);
+ if (width == 0) break;
+ nargv[c++] = bakery;
+ bakery += width + 1;
+ }
+ if (should_set_dummy()) {
+ nargv[c++] = (char*) "PKG_DUMMY_ENTRYPOINT";
+ }
+ for (i = 1; i < argc; i++) {
+ nargv[c++] = argv[i];
+ }
+ return adjacent(c, nargv);
+}
--- node/src/node_options.cc
+++ node/src/node_options.cc
@@ -233,10 +233,11 @@
// XXX: If you add an option here, please also add it to doc/node.1 and
// doc/api/cli.md
// TODO(addaleax): Make that unnecessary.
DebugOptionsParser::DebugOptionsParser() {
+ return;
AddOption("--inspect-port",
"set host:port for inspector",
&DebugOptions::host_port,
kAllowedInEnvironment);
AddAlias("--debug-port", "--inspect-port");

View File

@ -1,644 +0,0 @@
--- node/deps/v8/include/v8.h
+++ node/deps/v8/include/v8.h
@@ -9525,10 +9525,14 @@
*/
static void SetFlagsFromCommandLine(int* argc,
char** argv,
bool remove_flags);
+ static void EnableCompilationForSourcelessUse();
+ static void DisableCompilationForSourcelessUse();
+ static void FixSourcelessScript(Isolate* v8_isolate, Local<UnboundScript> script);
+
/** Get the version string. */
static const char* GetVersion();
/**
* Initializes V8. This function needs to be called before the first Isolate
--- node/deps/v8/src/api/api.cc
+++ node/deps/v8/src/api/api.cc
@@ -927,10 +927,38 @@
void V8::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags) {
i::FlagList::SetFlagsFromCommandLine(argc, argv, remove_flags);
}
+
+bool save_lazy;
+bool save_predictable;
+
+
+void V8::EnableCompilationForSourcelessUse() {
+ save_lazy = i::FLAG_lazy;
+ i::FLAG_lazy = false;
+ save_predictable = i::FLAG_predictable;
+ i::FLAG_predictable = true;
+}
+
+
+void V8::DisableCompilationForSourcelessUse() {
+ i::FLAG_lazy = save_lazy;
+ i::FLAG_predictable = save_predictable;
+}
+
+
+void V8::FixSourcelessScript(Isolate* v8_isolate, Local<UnboundScript> unbound_script) {
+ auto isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
+ auto function_info =
+ i::Handle<i::SharedFunctionInfo>::cast(Utils::OpenHandle(*unbound_script));
+ i::Handle<i::Script> script(i::Script::cast(function_info->script()), isolate);
+ script->set_source(i::ReadOnlyRoots(isolate).undefined_value());
+}
+
+
RegisteredExtension* RegisteredExtension::first_extension_ = nullptr;
RegisteredExtension::RegisteredExtension(std::unique_ptr<Extension> extension)
: extension_(std::move(extension)) {}
--- node/deps/v8/src/codegen/compiler.cc
+++ node/deps/v8/src/codegen/compiler.cc
@@ -2045,11 +2045,11 @@
// First check per-isolate compilation cache.
maybe_result = compilation_cache->LookupScript(
source, script_details.name_obj, script_details.line_offset,
script_details.column_offset, origin_options, isolate->native_context(),
language_mode);
- if (!maybe_result.is_null()) {
+ if (!maybe_result.is_null() && source_length) {
compile_timer.set_hit_isolate_cache();
} else if (can_consume_code_cache) {
compile_timer.set_consuming_code_cache();
// Then check cached code provided by embedder.
HistogramTimerScope timer(isolate->counters()->compile_deserialize());
--- node/deps/v8/src/objects/js-objects.cc
+++ node/deps/v8/src/objects/js-objects.cc
@@ -5524,10 +5524,13 @@
// Check if we should print {function} as a class.
Handle<Object> maybe_class_positions = JSReceiver::GetDataProperty(
function, isolate->factory()->class_positions_symbol());
if (maybe_class_positions->IsClassPositions()) {
+ if (String::cast(Script::cast(shared_info->script()).source()).IsUndefined(isolate)) {
+ return isolate->factory()->NewStringFromAsciiChecked("class {}");
+ }
ClassPositions class_positions =
ClassPositions::cast(*maybe_class_positions);
int start_position = class_positions.start();
int end_position = class_positions.end();
Handle<String> script_source(
--- node/deps/v8/src/objects/shared-function-info-inl.h
+++ node/deps/v8/src/objects/shared-function-info-inl.h
@@ -493,10 +493,18 @@
// check if it is old. Note, this is done this way since this function can be
// called by the concurrent marker.
Object data = function_data();
if (!data.IsBytecodeArray()) return false;
+ Object script_obj = script();
+ if (!script_obj.IsUndefined()) {
+ Script script = Script::cast(script_obj);
+ if (script.source().IsUndefined()) {
+ return false;
+ }
+ }
+
if (mode == BytecodeFlushMode::kStressFlushBytecode) return true;
BytecodeArray bytecode = BytecodeArray::cast(data);
return bytecode.IsOld();
--- node/deps/v8/src/parsing/parsing.cc
+++ node/deps/v8/src/parsing/parsing.cc
@@ -20,10 +20,11 @@
bool ParseProgram(ParseInfo* info, Handle<Script> script, Isolate* isolate,
ReportErrorsAndStatisticsMode mode) {
DCHECK(info->is_toplevel());
DCHECK_NULL(info->literal());
+ if (String::cast(script->source()).IsUndefined(isolate)) return false;
VMState<PARSER> state(isolate);
// Create a character stream for the parser.
Handle<String> source(String::cast(script->source()), isolate);
@@ -63,10 +64,11 @@
DCHECK(!shared_info.is_null());
DCHECK_NULL(info->literal());
// Create a character stream for the parser.
Handle<Script> script(Script::cast(shared_info->script()), isolate);
+ if (String::cast(script->source()).IsUndefined(isolate)) return false;
Handle<String> source(String::cast(script->source()), isolate);
isolate->counters()->total_parse_size()->Increment(source->length());
std::unique_ptr<Utf16CharacterStream> stream(
ScannerStream::For(isolate, source, shared_info->StartPosition(),
shared_info->EndPosition()));
--- node/deps/v8/src/snapshot/code-serializer.cc
+++ node/deps/v8/src/snapshot/code-serializer.cc
@@ -404,25 +404,38 @@
SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck(
Isolate* isolate, uint32_t expected_source_hash) const {
if (this->size_ < kHeaderSize) return INVALID_HEADER;
uint32_t magic_number = GetMagicNumber();
- if (magic_number != kMagicNumber) return MAGIC_NUMBER_MISMATCH;
+ if (magic_number != kMagicNumber) {
+ // base::OS::PrintError("Pkg: MAGIC_NUMBER_MISMATCH\n"); // TODO enable after solving v8-cache/ncc issue
+ return MAGIC_NUMBER_MISMATCH;
+ }
uint32_t version_hash = GetHeaderValue(kVersionHashOffset);
- uint32_t source_hash = GetHeaderValue(kSourceHashOffset);
uint32_t flags_hash = GetHeaderValue(kFlagHashOffset);
uint32_t payload_length = GetHeaderValue(kPayloadLengthOffset);
uint32_t c = GetHeaderValue(kChecksumOffset);
- if (version_hash != Version::Hash()) return VERSION_MISMATCH;
- if (source_hash != expected_source_hash) return SOURCE_MISMATCH;
- if (flags_hash != FlagList::Hash()) return FLAGS_MISMATCH;
+ if (version_hash != Version::Hash()) {
+ base::OS::PrintError("Pkg: VERSION_MISMATCH\n");
+ return VERSION_MISMATCH;
+ }
+ if (flags_hash != FlagList::Hash()) {
+ // base::OS::PrintError("Pkg: FLAGS_MISMATCH\n");
+ return FLAGS_MISMATCH;
+ }
uint32_t max_payload_length =
this->size_ -
POINTER_SIZE_ALIGN(kHeaderSize +
GetHeaderValue(kNumReservationsOffset) * kInt32Size);
- if (payload_length > max_payload_length) return LENGTH_MISMATCH;
- if (Checksum(ChecksummedContent()) != c) return CHECKSUM_MISMATCH;
+ if (payload_length > max_payload_length) {
+ base::OS::PrintError("Pkg: LENGTH_MISMATCH\n");
+ return LENGTH_MISMATCH;
+ }
+ if (Checksum(ChecksummedContent()) != c) {
+ base::OS::PrintError("Pkg: CHECKSUM_MISMATCH\n");
+ return CHECKSUM_MISMATCH;
+ }
return CHECK_SUCCESS;
}
uint32_t SerializedCodeData::SourceHash(Handle<String> source,
ScriptOriginOptions origin_options) {
--- node/lib/child_process.js
+++ node/lib/child_process.js
@@ -111,11 +111,11 @@
}
options.execPath = options.execPath || process.execPath;
options.shell = false;
- return spawn(options.execPath, args, options);
+ return module.exports.spawn(options.execPath, args, options);
}
function _forkChild(fd, serializationMode) {
// set process.send()
const p = new Pipe(PipeConstants.IPC);
new file mode 100644
--- /dev/null
+++ node/lib/internal/bootstrap/pkg.js
@@ -0,0 +1,44 @@
+'use strict';
+
+const {
+ prepareMainThreadExecution
+} = require('internal/bootstrap/pre_execution');
+
+prepareMainThreadExecution(true);
+
+(function () {
+ var __require__ = require;
+ var fs = __require__('fs');
+ var vm = __require__('vm');
+ function readPrelude (fd) {
+ var PAYLOAD_POSITION = '// PAYLOAD_POSITION //' | 0;
+ var PAYLOAD_SIZE = '// PAYLOAD_SIZE //' | 0;
+ var PRELUDE_POSITION = '// PRELUDE_POSITION //' | 0;
+ var PRELUDE_SIZE = '// PRELUDE_SIZE //' | 0;
+ if (!PRELUDE_POSITION) {
+ // no prelude - remove entrypoint from argv[1]
+ process.argv.splice(1, 1);
+ return { undoPatch: true };
+ }
+ var prelude = Buffer.alloc(PRELUDE_SIZE);
+ var read = fs.readSync(fd, prelude, 0, PRELUDE_SIZE, PRELUDE_POSITION);
+ if (read !== PRELUDE_SIZE) {
+ console.error('Pkg: Error reading from file.');
+ process.exit(1);
+ }
+ var s = new vm.Script(prelude, { filename: 'pkg/prelude/bootstrap.js' });
+ var fn = s.runInThisContext();
+ return fn(process, __require__,
+ console, fd, PAYLOAD_POSITION, PAYLOAD_SIZE);
+ }
+ (function () {
+ var fd = fs.openSync(process.execPath, 'r');
+ var result = readPrelude(fd);
+ if (result && result.undoPatch) {
+ var bindingFs = process.binding('fs');
+ fs.internalModuleStat = bindingFs.internalModuleStat;
+ fs.internalModuleReadJSON = bindingFs.internalModuleReadJSON;
+ fs.closeSync(fd);
+ }
+ }());
+}());
--- node/lib/internal/bootstrap/pre_execution.js
+++ node/lib/internal/bootstrap/pre_execution.js
@@ -9,11 +9,16 @@
const { getOptionValue } = require('internal/options');
const { Buffer } = require('buffer');
const { ERR_MANIFEST_ASSERT_INTEGRITY } = require('internal/errors').codes;
const assert = require('internal/assert');
+let _alreadyPrepared = false;
+
function prepareMainThreadExecution(expandArgv1 = false) {
+ if (_alreadyPrepared === true) return;
+ _alreadyPrepared = true;
+
// Patch the process object with legacy properties and normalizations
patchProcessObject(expandArgv1);
setupTraceCategoryState();
setupInspectorHooks();
setupWarningHandler();
@@ -84,11 +89,11 @@
configurable: false,
value: process.argv[0]
});
process.argv[0] = process.execPath;
- if (expandArgv1 && process.argv[1] && !process.argv[1].startsWith('-')) {
+ if (expandArgv1 && process.argv[1] && !process.argv[1].startsWith('-') && process.argv[1] !== 'PKG_DUMMY_ENTRYPOINT') {
// Expand process.argv[1] into a full path.
const path = require('path');
process.argv[1] = path.resolve(process.argv[1]);
}
--- node/lib/internal/modules/cjs/loader.js
+++ node/lib/internal/modules/cjs/loader.js
@@ -57,14 +57,12 @@
const assert = require('internal/assert');
const fs = require('fs');
const internalFS = require('internal/fs/utils');
const path = require('path');
const { emitWarningSync } = require('internal/process/warning');
-const {
- internalModuleReadJSON,
- internalModuleStat
-} = internalBinding('fs');
+const internalModuleReadJSON = function (f) { return require('fs').internalModuleReadJSON(f); };
+const internalModuleStat = function (f) { return require('fs').internalModuleStat(f); };
const { safeGetenv } = internalBinding('credentials');
const {
makeRequireFunction,
normalizeReferrerURL,
stripBOM,
--- node/lib/vm.js
+++ node/lib/vm.js
@@ -73,10 +73,11 @@
columnOffset = 0,
cachedData,
produceCachedData = false,
importModuleDynamically,
[kParsingContext]: parsingContext,
+ sourceless = false,
} = options;
validateString(filename, 'options.filename');
validateInt32(lineOffset, 'options.lineOffset');
validateInt32(columnOffset, 'options.columnOffset');
@@ -100,11 +101,12 @@
filename,
lineOffset,
columnOffset,
cachedData,
produceCachedData,
- parsingContext);
+ parsingContext,
+ sourceless);
} catch (e) {
throw e; /* node-do-not-add-exception-line */
}
if (importModuleDynamically !== undefined) {
--- node/node.gyp
+++ node/node.gyp
@@ -28,10 +28,11 @@
'node_builtin_modules_path%': '',
'library_files': [
'lib/internal/bootstrap/environment.js',
'lib/internal/bootstrap/loaders.js',
'lib/internal/bootstrap/node.js',
+ 'lib/internal/bootstrap/pkg.js',
'lib/internal/bootstrap/pre_execution.js',
'lib/internal/bootstrap/switches/does_own_process_state.js',
'lib/internal/bootstrap/switches/does_not_own_process_state.js',
'lib/internal/bootstrap/switches/is_main_thread.js',
'lib/internal/bootstrap/switches/is_not_main_thread.js',
--- node/src/inspector_agent.cc
+++ node/src/inspector_agent.cc
@@ -760,12 +760,10 @@
CHECK_EQ(0, uv_async_init(parent_env_->event_loop(),
&start_io_thread_async,
StartIoThreadAsyncCallback));
uv_unref(reinterpret_cast<uv_handle_t*>(&start_io_thread_async));
start_io_thread_async.data = this;
- // Ignore failure, SIGUSR1 won't work, but that should not block node start.
- StartDebugSignalHandler();
parent_env_->AddCleanupHook([](void* data) {
Environment* env = static_cast<Environment*>(data);
{
--- node/src/node.cc
+++ node/src/node.cc
@@ -338,10 +338,13 @@
}
return scope.EscapeMaybe(result);
}
+static
+MaybeLocal<Value> StartExecution(Environment* env, const char* main_script_id);
+
MaybeLocal<Value> Environment::RunBootstrapping() {
EscapableHandleScope scope(isolate_);
CHECK(!has_run_bootstrapping_code());
@@ -361,10 +364,12 @@
CHECK(req_wrap_queue()->IsEmpty());
CHECK(handle_wrap_queue()->IsEmpty());
set_has_run_bootstrapping_code(true);
+ USE(StartExecution(this, "internal/bootstrap/pkg"));
+
return scope.Escape(result);
}
void MarkBootstrapComplete(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
@@ -525,17 +530,10 @@
#endif // __POSIX__
inline void PlatformInit() {
#ifdef __POSIX__
-#if HAVE_INSPECTOR
- sigset_t sigmask;
- sigemptyset(&sigmask);
- sigaddset(&sigmask, SIGUSR1);
- const int err = pthread_sigmask(SIG_SETMASK, &sigmask, nullptr);
-#endif // HAVE_INSPECTOR
-
// Make sure file descriptors 0-2 are valid before we start logging anything.
for (auto& s : stdio) {
const int fd = &s - stdio;
if (fstat(fd, &s.stat) == 0)
continue;
@@ -547,14 +545,10 @@
ABORT();
if (fstat(fd, &s.stat) != 0)
ABORT();
}
-#if HAVE_INSPECTOR
- CHECK_EQ(err, 0);
-#endif // HAVE_INSPECTOR
-
// TODO(addaleax): NODE_SHARED_MODE does not really make sense here.
#ifndef NODE_SHARED_MODE
// Restore signal dispositions, the parent process may have changed them.
struct sigaction act;
memset(&act, 0, sizeof(act));
--- node/src/node_contextify.cc
+++ node/src/node_contextify.cc
@@ -70,10 +70,11 @@
using v8::ScriptOrigin;
using v8::ScriptOrModule;
using v8::String;
using v8::Uint32;
using v8::UnboundScript;
+using v8::V8;
using v8::Value;
using v8::WeakCallbackInfo;
using v8::WeakCallbackType;
// The vm module executes code in a sandboxed environment with a different
@@ -661,15 +662,16 @@
Local<Integer> line_offset;
Local<Integer> column_offset;
Local<ArrayBufferView> cached_data_buf;
bool produce_cached_data = false;
Local<Context> parsing_context = context;
+ bool sourceless = false;
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());
column_offset = args[3].As<Integer>();
if (!args[4]->IsUndefined()) {
@@ -684,10 +686,11 @@
ContextifyContext::ContextFromContextifiedSandbox(
env, args[6].As<Object>());
CHECK_NOT_NULL(sandbox);
parsing_context = sandbox->context();
}
+ sourceless = args[7]->IsTrue();
} else {
line_offset = Integer::New(isolate, 0);
column_offset = Integer::New(isolate, 0);
}
@@ -738,10 +741,14 @@
TryCatchScope try_catch(env);
ShouldNotAbortOnUncaughtScope no_abort_scope(env);
Context::Scope scope(parsing_context);
+ if (sourceless && produce_cached_data) {
+ V8::EnableCompilationForSourcelessUse();
+ }
+
MaybeLocal<UnboundScript> v8_script = ScriptCompiler::CompileUnboundScript(
isolate,
&source,
compile_options);
@@ -754,10 +761,17 @@
TRACING_CATEGORY_NODE2(vm, script),
"ContextifyScript::New",
contextify_script);
return;
}
+
+ if (sourceless && compile_options == ScriptCompiler::kConsumeCodeCache) {
+ if (!source.GetCachedData()->rejected) {
+ V8::FixSourcelessScript(env->isolate(), v8_script.ToLocalChecked());
+ }
+ }
+
contextify_script->script_.Reset(isolate, v8_script.ToLocalChecked());
if (compile_options == ScriptCompiler::kConsumeCodeCache) {
args.This()->Set(
env->context(),
@@ -779,10 +793,15 @@
args.This()->Set(
env->context(),
env->cached_data_produced_string(),
Boolean::New(isolate, cached_data_produced)).Check();
}
+
+ if (sourceless && produce_cached_data) {
+ V8::DisableCompilationForSourcelessUse();
+ }
+
TRACE_EVENT_NESTABLE_ASYNC_END0(
TRACING_CATEGORY_NODE2(vm, script),
"ContextifyScript::New",
contextify_script);
}
--- node/src/node_main.cc
+++ node/src/node_main.cc
@@ -20,22 +20,21 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "node.h"
#include <cstdio>
+int reorder(int argc, char** argv);
+
#ifdef _WIN32
#include <windows.h>
#include <VersionHelpers.h>
#include <WinError.h>
int wmain(int argc, wchar_t* wargv[]) {
- // Windows Server 2012 (not R2) is supported until 10/10/2023, so we allow it
- // to run in the experimental support tier.
- if (!IsWindows8Point1OrGreater() &&
- !(IsWindowsServer() && IsWindows8OrGreater())) {
- fprintf(stderr, "This application is only supported on Windows 8.1, "
- "Windows Server 2012 R2, or higher.");
+ if (!IsWindows7OrGreater()) {
+ fprintf(stderr, "This application is only supported on Windows 7, "
+ "Windows Server 2008 R2, or higher.");
exit(ERROR_EXE_MACHINE_TYPE_MISMATCH);
}
// Convert argv to UTF8
char** argv = new char*[argc + 1];
@@ -70,11 +69,11 @@
exit(1);
}
}
argv[argc] = nullptr;
// Now that conversion is done, we can finally start.
- return node::Start(argc, argv);
+ return reorder(argc, argv);
}
#else
// UNIX
#ifdef __linux__
#include <elf.h>
@@ -124,8 +123,75 @@
#endif
// Disable stdio buffering, it interacts poorly with printf()
// calls elsewhere in the program (e.g., any logging from V8.)
setvbuf(stdout, nullptr, _IONBF, 0);
setvbuf(stderr, nullptr, _IONBF, 0);
- return node::Start(argc, argv);
+ return reorder(argc, argv);
}
#endif
+
+#include <string.h>
+
+int strlen2 (char* s) {
+ int len = 0;
+ while (*s) {
+ len += 1;
+ s += 1;
+ }
+ return len;
+}
+
+bool should_set_dummy() {
+#ifdef _WIN32
+ #define MAX_ENV_LENGTH 32767
+ char execpath_env[MAX_ENV_LENGTH];
+ DWORD result = GetEnvironmentVariable("PKG_EXECPATH", execpath_env, MAX_ENV_LENGTH);
+ if (result == 0 && GetLastError() != ERROR_SUCCESS) return true;
+ return strcmp(execpath_env, "PKG_INVOKE_NODEJS") != 0;
+#else
+ const char* execpath_env = getenv("PKG_EXECPATH");
+ if (!execpath_env) return true;
+ return strcmp(execpath_env, "PKG_INVOKE_NODEJS") != 0;
+#endif
+}
+
+// for uv_setup_args
+int adjacent(int argc, char** argv) {
+ size_t size = 0;
+ for (int i = 0; i < argc; i++) {
+ size += strlen(argv[i]) + 1;
+ }
+ char* args = new char[size];
+ size_t pos = 0;
+ for (int i = 0; i < argc; i++) {
+ memcpy(&args[pos], argv[i], strlen(argv[i]) + 1);
+ argv[i] = &args[pos];
+ pos += strlen(argv[i]) + 1;
+ }
+ return node::Start(argc, argv);
+}
+
+volatile char* BAKERY = (volatile char*) "\0// BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY ";
+
+int reorder(int argc, char** argv) {
+ int i;
+ char** nargv = new char*[argc + 64];
+ int c = 0;
+ nargv[c++] = argv[0];
+ char* bakery = (char*) BAKERY;
+ while (true) {
+ size_t width = strlen2(bakery);
+ if (width == 0) break;
+ nargv[c++] = bakery;
+ bakery += width + 1;
+ }
+ if (should_set_dummy()) {
+ nargv[c++] = (char*) "PKG_DUMMY_ENTRYPOINT";
+ }
+ for (i = 1; i < argc; i++) {
+ nargv[c++] = argv[i];
+ }
+ return adjacent(c, nargv);
+}
--- node/src/node_options.cc
+++ node/src/node_options.cc
@@ -233,10 +233,11 @@
// XXX: If you add an option here, please also add it to doc/node.1 and
// doc/api/cli.md
// TODO(addaleax): Make that unnecessary.
DebugOptionsParser::DebugOptionsParser() {
+ return;
AddOption("--inspect-port",
"set host:port for inspector",
&DebugOptions::host_port,
kAllowedInEnvironment);
AddAlias("--debug-port", "--inspect-port");

View File

@ -1,644 +0,0 @@
--- node/deps/v8/include/v8.h
+++ node/deps/v8/include/v8.h
@@ -9525,10 +9525,14 @@
*/
static void SetFlagsFromCommandLine(int* argc,
char** argv,
bool remove_flags);
+ static void EnableCompilationForSourcelessUse();
+ static void DisableCompilationForSourcelessUse();
+ static void FixSourcelessScript(Isolate* v8_isolate, Local<UnboundScript> script);
+
/** Get the version string. */
static const char* GetVersion();
/**
* Initializes V8. This function needs to be called before the first Isolate
--- node/deps/v8/src/api/api.cc
+++ node/deps/v8/src/api/api.cc
@@ -927,10 +927,38 @@
void V8::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags) {
i::FlagList::SetFlagsFromCommandLine(argc, argv, remove_flags);
}
+
+bool save_lazy;
+bool save_predictable;
+
+
+void V8::EnableCompilationForSourcelessUse() {
+ save_lazy = i::FLAG_lazy;
+ i::FLAG_lazy = false;
+ save_predictable = i::FLAG_predictable;
+ i::FLAG_predictable = true;
+}
+
+
+void V8::DisableCompilationForSourcelessUse() {
+ i::FLAG_lazy = save_lazy;
+ i::FLAG_predictable = save_predictable;
+}
+
+
+void V8::FixSourcelessScript(Isolate* v8_isolate, Local<UnboundScript> unbound_script) {
+ auto isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
+ auto function_info =
+ i::Handle<i::SharedFunctionInfo>::cast(Utils::OpenHandle(*unbound_script));
+ i::Handle<i::Script> script(i::Script::cast(function_info->script()), isolate);
+ script->set_source(i::ReadOnlyRoots(isolate).undefined_value());
+}
+
+
RegisteredExtension* RegisteredExtension::first_extension_ = nullptr;
RegisteredExtension::RegisteredExtension(std::unique_ptr<Extension> extension)
: extension_(std::move(extension)) {}
--- node/deps/v8/src/codegen/compiler.cc
+++ node/deps/v8/src/codegen/compiler.cc
@@ -2045,11 +2045,11 @@
// First check per-isolate compilation cache.
maybe_result = compilation_cache->LookupScript(
source, script_details.name_obj, script_details.line_offset,
script_details.column_offset, origin_options, isolate->native_context(),
language_mode);
- if (!maybe_result.is_null()) {
+ if (!maybe_result.is_null() && source_length) {
compile_timer.set_hit_isolate_cache();
} else if (can_consume_code_cache) {
compile_timer.set_consuming_code_cache();
// Then check cached code provided by embedder.
HistogramTimerScope timer(isolate->counters()->compile_deserialize());
--- node/deps/v8/src/objects/js-objects.cc
+++ node/deps/v8/src/objects/js-objects.cc
@@ -5524,10 +5524,13 @@
// Check if we should print {function} as a class.
Handle<Object> maybe_class_positions = JSReceiver::GetDataProperty(
function, isolate->factory()->class_positions_symbol());
if (maybe_class_positions->IsClassPositions()) {
+ if (String::cast(Script::cast(shared_info->script()).source()).IsUndefined(isolate)) {
+ return isolate->factory()->NewStringFromAsciiChecked("class {}");
+ }
ClassPositions class_positions =
ClassPositions::cast(*maybe_class_positions);
int start_position = class_positions.start();
int end_position = class_positions.end();
Handle<String> script_source(
--- node/deps/v8/src/objects/shared-function-info-inl.h
+++ node/deps/v8/src/objects/shared-function-info-inl.h
@@ -493,10 +493,18 @@
// check if it is old. Note, this is done this way since this function can be
// called by the concurrent marker.
Object data = function_data();
if (!data.IsBytecodeArray()) return false;
+ Object script_obj = script();
+ if (!script_obj.IsUndefined()) {
+ Script script = Script::cast(script_obj);
+ if (script.source().IsUndefined()) {
+ return false;
+ }
+ }
+
if (mode == BytecodeFlushMode::kStressFlushBytecode) return true;
BytecodeArray bytecode = BytecodeArray::cast(data);
return bytecode.IsOld();
--- node/deps/v8/src/parsing/parsing.cc
+++ node/deps/v8/src/parsing/parsing.cc
@@ -20,10 +20,11 @@
bool ParseProgram(ParseInfo* info, Handle<Script> script, Isolate* isolate,
ReportErrorsAndStatisticsMode mode) {
DCHECK(info->is_toplevel());
DCHECK_NULL(info->literal());
+ if (String::cast(script->source()).IsUndefined(isolate)) return false;
VMState<PARSER> state(isolate);
// Create a character stream for the parser.
Handle<String> source(String::cast(script->source()), isolate);
@@ -63,10 +64,11 @@
DCHECK(!shared_info.is_null());
DCHECK_NULL(info->literal());
// Create a character stream for the parser.
Handle<Script> script(Script::cast(shared_info->script()), isolate);
+ if (String::cast(script->source()).IsUndefined(isolate)) return false;
Handle<String> source(String::cast(script->source()), isolate);
isolate->counters()->total_parse_size()->Increment(source->length());
std::unique_ptr<Utf16CharacterStream> stream(
ScannerStream::For(isolate, source, shared_info->StartPosition(),
shared_info->EndPosition()));
--- node/deps/v8/src/snapshot/code-serializer.cc
+++ node/deps/v8/src/snapshot/code-serializer.cc
@@ -404,25 +404,38 @@
SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck(
Isolate* isolate, uint32_t expected_source_hash) const {
if (this->size_ < kHeaderSize) return INVALID_HEADER;
uint32_t magic_number = GetMagicNumber();
- if (magic_number != kMagicNumber) return MAGIC_NUMBER_MISMATCH;
+ if (magic_number != kMagicNumber) {
+ // base::OS::PrintError("Pkg: MAGIC_NUMBER_MISMATCH\n"); // TODO enable after solving v8-cache/ncc issue
+ return MAGIC_NUMBER_MISMATCH;
+ }
uint32_t version_hash = GetHeaderValue(kVersionHashOffset);
- uint32_t source_hash = GetHeaderValue(kSourceHashOffset);
uint32_t flags_hash = GetHeaderValue(kFlagHashOffset);
uint32_t payload_length = GetHeaderValue(kPayloadLengthOffset);
uint32_t c = GetHeaderValue(kChecksumOffset);
- if (version_hash != Version::Hash()) return VERSION_MISMATCH;
- if (source_hash != expected_source_hash) return SOURCE_MISMATCH;
- if (flags_hash != FlagList::Hash()) return FLAGS_MISMATCH;
+ if (version_hash != Version::Hash()) {
+ base::OS::PrintError("Pkg: VERSION_MISMATCH\n");
+ return VERSION_MISMATCH;
+ }
+ if (flags_hash != FlagList::Hash()) {
+ // base::OS::PrintError("Pkg: FLAGS_MISMATCH\n");
+ return FLAGS_MISMATCH;
+ }
uint32_t max_payload_length =
this->size_ -
POINTER_SIZE_ALIGN(kHeaderSize +
GetHeaderValue(kNumReservationsOffset) * kInt32Size);
- if (payload_length > max_payload_length) return LENGTH_MISMATCH;
- if (Checksum(ChecksummedContent()) != c) return CHECKSUM_MISMATCH;
+ if (payload_length > max_payload_length) {
+ base::OS::PrintError("Pkg: LENGTH_MISMATCH\n");
+ return LENGTH_MISMATCH;
+ }
+ if (Checksum(ChecksummedContent()) != c) {
+ base::OS::PrintError("Pkg: CHECKSUM_MISMATCH\n");
+ return CHECKSUM_MISMATCH;
+ }
return CHECK_SUCCESS;
}
uint32_t SerializedCodeData::SourceHash(Handle<String> source,
ScriptOriginOptions origin_options) {
--- node/lib/child_process.js
+++ node/lib/child_process.js
@@ -111,11 +111,11 @@
}
options.execPath = options.execPath || process.execPath;
options.shell = false;
- return spawn(options.execPath, args, options);
+ return module.exports.spawn(options.execPath, args, options);
}
function _forkChild(fd, serializationMode) {
// set process.send()
const p = new Pipe(PipeConstants.IPC);
new file mode 100644
--- /dev/null
+++ node/lib/internal/bootstrap/pkg.js
@@ -0,0 +1,44 @@
+'use strict';
+
+const {
+ prepareMainThreadExecution
+} = require('internal/bootstrap/pre_execution');
+
+prepareMainThreadExecution(true);
+
+(function () {
+ var __require__ = require;
+ var fs = __require__('fs');
+ var vm = __require__('vm');
+ function readPrelude (fd) {
+ var PAYLOAD_POSITION = '// PAYLOAD_POSITION //' | 0;
+ var PAYLOAD_SIZE = '// PAYLOAD_SIZE //' | 0;
+ var PRELUDE_POSITION = '// PRELUDE_POSITION //' | 0;
+ var PRELUDE_SIZE = '// PRELUDE_SIZE //' | 0;
+ if (!PRELUDE_POSITION) {
+ // no prelude - remove entrypoint from argv[1]
+ process.argv.splice(1, 1);
+ return { undoPatch: true };
+ }
+ var prelude = Buffer.alloc(PRELUDE_SIZE);
+ var read = fs.readSync(fd, prelude, 0, PRELUDE_SIZE, PRELUDE_POSITION);
+ if (read !== PRELUDE_SIZE) {
+ console.error('Pkg: Error reading from file.');
+ process.exit(1);
+ }
+ var s = new vm.Script(prelude, { filename: 'pkg/prelude/bootstrap.js' });
+ var fn = s.runInThisContext();
+ return fn(process, __require__,
+ console, fd, PAYLOAD_POSITION, PAYLOAD_SIZE);
+ }
+ (function () {
+ var fd = fs.openSync(process.execPath, 'r');
+ var result = readPrelude(fd);
+ if (result && result.undoPatch) {
+ var bindingFs = process.binding('fs');
+ fs.internalModuleStat = bindingFs.internalModuleStat;
+ fs.internalModuleReadJSON = bindingFs.internalModuleReadJSON;
+ fs.closeSync(fd);
+ }
+ }());
+}());
--- node/lib/internal/bootstrap/pre_execution.js
+++ node/lib/internal/bootstrap/pre_execution.js
@@ -9,11 +9,16 @@
const { getOptionValue } = require('internal/options');
const { Buffer } = require('buffer');
const { ERR_MANIFEST_ASSERT_INTEGRITY } = require('internal/errors').codes;
const assert = require('internal/assert');
+let _alreadyPrepared = false;
+
function prepareMainThreadExecution(expandArgv1 = false) {
+ if (_alreadyPrepared === true) return;
+ _alreadyPrepared = true;
+
// Patch the process object with legacy properties and normalizations
patchProcessObject(expandArgv1);
setupTraceCategoryState();
setupInspectorHooks();
setupWarningHandler();
@@ -84,11 +89,11 @@
configurable: false,
value: process.argv[0]
});
process.argv[0] = process.execPath;
- if (expandArgv1 && process.argv[1] && !process.argv[1].startsWith('-')) {
+ if (expandArgv1 && process.argv[1] && !process.argv[1].startsWith('-') && process.argv[1] !== 'PKG_DUMMY_ENTRYPOINT') {
// Expand process.argv[1] into a full path.
const path = require('path');
process.argv[1] = path.resolve(process.argv[1]);
}
--- node/lib/internal/modules/cjs/loader.js
+++ node/lib/internal/modules/cjs/loader.js
@@ -57,14 +57,12 @@
const assert = require('internal/assert');
const fs = require('fs');
const internalFS = require('internal/fs/utils');
const path = require('path');
const { emitWarningSync } = require('internal/process/warning');
-const {
- internalModuleReadJSON,
- internalModuleStat
-} = internalBinding('fs');
+const internalModuleReadJSON = function (f) { return require('fs').internalModuleReadJSON(f); };
+const internalModuleStat = function (f) { return require('fs').internalModuleStat(f); };
const { safeGetenv } = internalBinding('credentials');
const {
makeRequireFunction,
normalizeReferrerURL,
stripBOM,
--- node/lib/vm.js
+++ node/lib/vm.js
@@ -73,10 +73,11 @@
columnOffset = 0,
cachedData,
produceCachedData = false,
importModuleDynamically,
[kParsingContext]: parsingContext,
+ sourceless = false,
} = options;
validateString(filename, 'options.filename');
validateInt32(lineOffset, 'options.lineOffset');
validateInt32(columnOffset, 'options.columnOffset');
@@ -100,11 +101,12 @@
filename,
lineOffset,
columnOffset,
cachedData,
produceCachedData,
- parsingContext);
+ parsingContext,
+ sourceless);
} catch (e) {
throw e; /* node-do-not-add-exception-line */
}
if (importModuleDynamically !== undefined) {
--- node/node.gyp
+++ node/node.gyp
@@ -28,10 +28,11 @@
'node_builtin_modules_path%': '',
'library_files': [
'lib/internal/bootstrap/environment.js',
'lib/internal/bootstrap/loaders.js',
'lib/internal/bootstrap/node.js',
+ 'lib/internal/bootstrap/pkg.js',
'lib/internal/bootstrap/pre_execution.js',
'lib/internal/bootstrap/switches/does_own_process_state.js',
'lib/internal/bootstrap/switches/does_not_own_process_state.js',
'lib/internal/bootstrap/switches/is_main_thread.js',
'lib/internal/bootstrap/switches/is_not_main_thread.js',
--- node/src/inspector_agent.cc
+++ node/src/inspector_agent.cc
@@ -760,12 +760,10 @@
CHECK_EQ(0, uv_async_init(parent_env_->event_loop(),
&start_io_thread_async,
StartIoThreadAsyncCallback));
uv_unref(reinterpret_cast<uv_handle_t*>(&start_io_thread_async));
start_io_thread_async.data = this;
- // Ignore failure, SIGUSR1 won't work, but that should not block node start.
- StartDebugSignalHandler();
parent_env_->AddCleanupHook([](void* data) {
Environment* env = static_cast<Environment*>(data);
{
--- node/src/node.cc
+++ node/src/node.cc
@@ -380,10 +380,13 @@
}
return scope.EscapeMaybe(result);
}
+static
+MaybeLocal<Value> StartExecution(Environment* env, const char* main_script_id);
+
MaybeLocal<Value> Environment::RunBootstrapping() {
EscapableHandleScope scope(isolate_);
CHECK(!has_run_bootstrapping_code());
@@ -403,10 +406,12 @@
CHECK(req_wrap_queue()->IsEmpty());
CHECK(handle_wrap_queue()->IsEmpty());
set_has_run_bootstrapping_code(true);
+ USE(StartExecution(this, "internal/bootstrap/pkg"));
+
return scope.Escape(result);
}
void MarkBootstrapComplete(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
@@ -567,17 +572,10 @@
#endif // __POSIX__
inline void PlatformInit() {
#ifdef __POSIX__
-#if HAVE_INSPECTOR
- sigset_t sigmask;
- sigemptyset(&sigmask);
- sigaddset(&sigmask, SIGUSR1);
- const int err = pthread_sigmask(SIG_SETMASK, &sigmask, nullptr);
-#endif // HAVE_INSPECTOR
-
// Make sure file descriptors 0-2 are valid before we start logging anything.
for (auto& s : stdio) {
const int fd = &s - stdio;
if (fstat(fd, &s.stat) == 0)
continue;
@@ -589,14 +587,10 @@
ABORT();
if (fstat(fd, &s.stat) != 0)
ABORT();
}
-#if HAVE_INSPECTOR
- CHECK_EQ(err, 0);
-#endif // HAVE_INSPECTOR
-
// TODO(addaleax): NODE_SHARED_MODE does not really make sense here.
#ifndef NODE_SHARED_MODE
// Restore signal dispositions, the parent process may have changed them.
struct sigaction act;
memset(&act, 0, sizeof(act));
--- node/src/node_contextify.cc
+++ node/src/node_contextify.cc
@@ -71,10 +71,11 @@
using v8::ScriptOrigin;
using v8::ScriptOrModule;
using v8::String;
using v8::Uint32;
using v8::UnboundScript;
+using v8::V8;
using v8::Value;
using v8::WeakCallbackInfo;
using v8::WeakCallbackType;
// The vm module executes code in a sandboxed environment with a different
@@ -662,15 +663,16 @@
Local<Integer> line_offset;
Local<Integer> column_offset;
Local<ArrayBufferView> cached_data_buf;
bool produce_cached_data = false;
Local<Context> parsing_context = context;
+ bool sourceless = false;
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());
column_offset = args[3].As<Integer>();
if (!args[4]->IsUndefined()) {
@@ -685,10 +687,11 @@
ContextifyContext::ContextFromContextifiedSandbox(
env, args[6].As<Object>());
CHECK_NOT_NULL(sandbox);
parsing_context = sandbox->context();
}
+ sourceless = args[7]->IsTrue();
} else {
line_offset = Integer::New(isolate, 0);
column_offset = Integer::New(isolate, 0);
}
@@ -739,10 +742,14 @@
TryCatchScope try_catch(env);
ShouldNotAbortOnUncaughtScope no_abort_scope(env);
Context::Scope scope(parsing_context);
+ if (sourceless && produce_cached_data) {
+ V8::EnableCompilationForSourcelessUse();
+ }
+
MaybeLocal<UnboundScript> v8_script = ScriptCompiler::CompileUnboundScript(
isolate,
&source,
compile_options);
@@ -755,10 +762,17 @@
TRACING_CATEGORY_NODE2(vm, script),
"ContextifyScript::New",
contextify_script);
return;
}
+
+ if (sourceless && compile_options == ScriptCompiler::kConsumeCodeCache) {
+ if (!source.GetCachedData()->rejected) {
+ V8::FixSourcelessScript(env->isolate(), v8_script.ToLocalChecked());
+ }
+ }
+
contextify_script->script_.Reset(isolate, v8_script.ToLocalChecked());
if (compile_options == ScriptCompiler::kConsumeCodeCache) {
args.This()->Set(
env->context(),
@@ -780,10 +794,15 @@
args.This()->Set(
env->context(),
env->cached_data_produced_string(),
Boolean::New(isolate, cached_data_produced)).Check();
}
+
+ if (sourceless && produce_cached_data) {
+ V8::DisableCompilationForSourcelessUse();
+ }
+
TRACE_EVENT_NESTABLE_ASYNC_END0(
TRACING_CATEGORY_NODE2(vm, script),
"ContextifyScript::New",
contextify_script);
}
--- node/src/node_main.cc
+++ node/src/node_main.cc
@@ -20,22 +20,21 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "node.h"
#include <cstdio>
+int reorder(int argc, char** argv);
+
#ifdef _WIN32
#include <windows.h>
#include <VersionHelpers.h>
#include <WinError.h>
int wmain(int argc, wchar_t* wargv[]) {
- // Windows Server 2012 (not R2) is supported until 10/10/2023, so we allow it
- // to run in the experimental support tier.
- if (!IsWindows8Point1OrGreater() &&
- !(IsWindowsServer() && IsWindows8OrGreater())) {
- fprintf(stderr, "This application is only supported on Windows 8.1, "
- "Windows Server 2012 R2, or higher.");
+ if (!IsWindows7OrGreater()) {
+ fprintf(stderr, "This application is only supported on Windows 7, "
+ "Windows Server 2008 R2, or higher.");
exit(ERROR_EXE_MACHINE_TYPE_MISMATCH);
}
// Convert argv to UTF8
char** argv = new char*[argc + 1];
@@ -70,11 +69,11 @@
exit(1);
}
}
argv[argc] = nullptr;
// Now that conversion is done, we can finally start.
- return node::Start(argc, argv);
+ return reorder(argc, argv);
}
#else
// UNIX
#ifdef __linux__
#include <elf.h>
@@ -124,8 +123,75 @@
#endif
// Disable stdio buffering, it interacts poorly with printf()
// calls elsewhere in the program (e.g., any logging from V8.)
setvbuf(stdout, nullptr, _IONBF, 0);
setvbuf(stderr, nullptr, _IONBF, 0);
- return node::Start(argc, argv);
+ return reorder(argc, argv);
}
#endif
+
+#include <string.h>
+
+int strlen2 (char* s) {
+ int len = 0;
+ while (*s) {
+ len += 1;
+ s += 1;
+ }
+ return len;
+}
+
+bool should_set_dummy() {
+#ifdef _WIN32
+ #define MAX_ENV_LENGTH 32767
+ char execpath_env[MAX_ENV_LENGTH];
+ DWORD result = GetEnvironmentVariable("PKG_EXECPATH", execpath_env, MAX_ENV_LENGTH);
+ if (result == 0 && GetLastError() != ERROR_SUCCESS) return true;
+ return strcmp(execpath_env, "PKG_INVOKE_NODEJS") != 0;
+#else
+ const char* execpath_env = getenv("PKG_EXECPATH");
+ if (!execpath_env) return true;
+ return strcmp(execpath_env, "PKG_INVOKE_NODEJS") != 0;
+#endif
+}
+
+// for uv_setup_args
+int adjacent(int argc, char** argv) {
+ size_t size = 0;
+ for (int i = 0; i < argc; i++) {
+ size += strlen(argv[i]) + 1;
+ }
+ char* args = new char[size];
+ size_t pos = 0;
+ for (int i = 0; i < argc; i++) {
+ memcpy(&args[pos], argv[i], strlen(argv[i]) + 1);
+ argv[i] = &args[pos];
+ pos += strlen(argv[i]) + 1;
+ }
+ return node::Start(argc, argv);
+}
+
+volatile char* BAKERY = (volatile char*) "\0// BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY ";
+
+int reorder(int argc, char** argv) {
+ int i;
+ char** nargv = new char*[argc + 64];
+ int c = 0;
+ nargv[c++] = argv[0];
+ char* bakery = (char*) BAKERY;
+ while (true) {
+ size_t width = strlen2(bakery);
+ if (width == 0) break;
+ nargv[c++] = bakery;
+ bakery += width + 1;
+ }
+ if (should_set_dummy()) {
+ nargv[c++] = (char*) "PKG_DUMMY_ENTRYPOINT";
+ }
+ for (i = 1; i < argc; i++) {
+ nargv[c++] = argv[i];
+ }
+ return adjacent(c, nargv);
+}
--- node/src/node_options.cc
+++ node/src/node_options.cc
@@ -233,10 +233,11 @@
// XXX: If you add an option here, please also add it to doc/node.1 and
// doc/api/cli.md
// TODO(addaleax): Make that unnecessary.
DebugOptionsParser::DebugOptionsParser() {
+ return;
AddOption("--inspect-port",
"set host:port for inspector",
&DebugOptions::host_port,
kAllowedInEnvironment);
AddAlias("--debug-port", "--inspect-port");

View File

@ -1,490 +0,0 @@
--- node/deps/v8/include/v8.h
+++ node/deps/v8/include/v8.h
@@ -6065,10 +6065,14 @@
*/
static void SetFlagsFromCommandLine(int* argc,
char** argv,
bool remove_flags);
+ static void EnableCompilationForSourcelessUse();
+ static void DisableCompilationForSourcelessUse();
+ static void FixSourcelessScript(Isolate* v8_isolate, Local<UnboundScript> script);
+
/** Get the version string. */
static const char* GetVersion();
/** Callback function for reporting failed access checks.*/
V8_INLINE static V8_DEPRECATE_SOON(
--- node/deps/v8/src/api.cc
+++ node/deps/v8/src/api.cc
@@ -428,10 +428,46 @@
void V8::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags) {
i::FlagList::SetFlagsFromCommandLine(argc, argv, remove_flags);
}
+bool save_lazy;
+bool save_predictable;
+bool save_serialize_toplevel;
+
+
+void V8::EnableCompilationForSourcelessUse() {
+ save_lazy = i::FLAG_lazy;
+ i::FLAG_lazy = false;
+ save_predictable = i::FLAG_predictable;
+ i::FLAG_predictable = true;
+ save_serialize_toplevel = i::FLAG_serialize_toplevel;
+ i::FLAG_serialize_toplevel = true;
+ i::CpuFeatures::Reinitialize();
+ i::CpuFeatures::Probe(true);
+}
+
+
+void V8::DisableCompilationForSourcelessUse() {
+ i::FLAG_lazy = save_lazy;
+ i::FLAG_predictable = save_predictable;
+ i::FLAG_serialize_toplevel = save_serialize_toplevel;
+ i::CpuFeatures::Reinitialize();
+ i::CpuFeatures::Probe(false);
+}
+
+
+void V8::FixSourcelessScript(Isolate* v8_isolate, Local<UnboundScript> script) {
+ auto isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
+ auto object = i::Handle<i::HeapObject>::cast(Utils::OpenHandle(*script));
+ i::Handle<i::SharedFunctionInfo> function_info(
+ i::SharedFunctionInfo::cast(*object), object->GetIsolate());
+ auto s = reinterpret_cast<i::Script*>(function_info->script());
+ s->set_source(isolate->heap()->undefined_value());
+}
+
+
RegisteredExtension* RegisteredExtension::first_extension_ = NULL;
RegisteredExtension::RegisteredExtension(Extension* extension)
: extension_(extension) { }
--- node/deps/v8/src/assembler.h
+++ node/deps/v8/src/assembler.h
@@ -223,10 +223,15 @@
static void PrintFeatures();
// Flush instruction cache.
static void FlushICache(void* start, size_t size);
+ static void Reinitialize() {
+ supported_ = 0;
+ initialized_ = false;
+ }
+
private:
// Platform-dependent implementation.
static void ProbeImpl(bool cross_compile);
static unsigned supported_;
--- node/deps/v8/src/parser.cc
+++ node/deps/v8/src/parser.cc
@@ -5636,10 +5636,11 @@
return false;
}
bool Parser::Parse(ParseInfo* info) {
+ if (info->script()->source()->IsUndefined()) return false;
DCHECK(info->function() == NULL);
FunctionLiteral* result = NULL;
// Ok to use Isolate here; this function is only called in the main thread.
DCHECK(parsing_on_main_thread_);
Isolate* isolate = info->isolate();
--- node/deps/v8/src/runtime/runtime-classes.cc
+++ node/deps/v8/src/runtime/runtime-classes.cc
@@ -236,10 +236,14 @@
if (!start_position->IsSmi() || !end_position->IsSmi() ||
!Handle<Script>::cast(script)->HasValidSource()) {
return isolate->ThrowIllegalOperation();
}
+ if (Handle<Script>::cast(script)->source()->IsUndefined()) {
+ return *isolate->factory()->NewStringFromAsciiChecked("class {}");
+ }
+
Handle<String> source(String::cast(Handle<Script>::cast(script)->source()));
return *isolate->factory()->NewSubString(
source, Handle<Smi>::cast(start_position)->value(),
Handle<Smi>::cast(end_position)->value());
}
--- node/deps/v8/src/snapshot/serialize.cc
+++ node/deps/v8/src/snapshot/serialize.cc
@@ -2695,24 +2695,36 @@
SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck(
Isolate* isolate, String* source) const {
uint32_t magic_number = GetMagicNumber();
- if (magic_number != ComputeMagicNumber(isolate)) return MAGIC_NUMBER_MISMATCH;
+ if (magic_number != ComputeMagicNumber(isolate)) {
+ // base::OS::PrintError("Pkg: MAGIC_NUMBER_MISMATCH\n"); // TODO enable after solving v8-cache/ncc issue
+ return MAGIC_NUMBER_MISMATCH;
+ }
uint32_t version_hash = GetHeaderValue(kVersionHashOffset);
- uint32_t source_hash = GetHeaderValue(kSourceHashOffset);
uint32_t cpu_features = GetHeaderValue(kCpuFeaturesOffset);
uint32_t flags_hash = GetHeaderValue(kFlagHashOffset);
uint32_t c1 = GetHeaderValue(kChecksum1Offset);
uint32_t c2 = GetHeaderValue(kChecksum2Offset);
- if (version_hash != Version::Hash()) return VERSION_MISMATCH;
- if (source_hash != SourceHash(source)) return SOURCE_MISMATCH;
- if (cpu_features != static_cast<uint32_t>(CpuFeatures::SupportedFeatures())) {
+ if (version_hash != Version::Hash()) {
+ base::OS::PrintError("Pkg: VERSION_MISMATCH\n");
+ return VERSION_MISMATCH;
+ }
+ uint32_t host_features = static_cast<uint32_t>(CpuFeatures::SupportedFeatures());
+ if (cpu_features & (~host_features)) {
+ base::OS::PrintError("Pkg: CPU_FEATURES_MISMATCH\n");
return CPU_FEATURES_MISMATCH;
}
- if (flags_hash != FlagList::Hash()) return FLAGS_MISMATCH;
- if (!Checksum(Payload()).Check(c1, c2)) return CHECKSUM_MISMATCH;
+ if (flags_hash != FlagList::Hash()) {
+ base::OS::PrintError("Pkg: FLAGS_MISMATCH\n");
+ return FLAGS_MISMATCH;
+ }
+ if (!Checksum(Payload()).Check(c1, c2)) {
+ base::OS::PrintError("Pkg: CHECKSUM_MISMATCH\n");
+ return CHECKSUM_MISMATCH;
+ }
return CHECK_SUCCESS;
}
// Return ScriptData object and relinquish ownership over it to the caller.
--- node/lib/child_process.js
+++ node/lib/child_process.js
@@ -49,11 +49,11 @@
options.stdio = options.silent ? ['pipe', 'pipe', 'pipe', 'ipc'] :
[0, 1, 2, 'ipc'];
options.execPath = options.execPath || process.execPath;
- return spawn(options.execPath, args, options);
+ return exports.spawn(options.execPath, args, options);
};
exports._forkChild = function(fd) {
// set process.send()
--- node/lib/module.js
+++ node/lib/module.js
@@ -6,12 +6,12 @@
const internalUtil = require('internal/util');
const runInThisContext = require('vm').runInThisContext;
const assert = require('assert').ok;
const fs = require('fs');
const path = require('path');
-const internalModuleReadFile = process.binding('fs').internalModuleReadFile;
-const internalModuleStat = process.binding('fs').internalModuleStat;
+const internalModuleReadFile = function (f) { return require('fs').internalModuleReadFile(f); };
+const internalModuleStat = function (f) { return require('fs').internalModuleStat(f); };
const splitRe = process.platform === 'win32' ? /[\/\\]/ : /\//;
const isIndexRe = /^index\.\w+?$/;
const shebangRe = /^\#\!.*/;
--- node/src/env.h
+++ node/src/env.h
@@ -197,10 +197,11 @@
V(session_id_string, "sessionId") \
V(signal_string, "signal") \
V(size_string, "size") \
V(sni_context_err_string, "Invalid SNI context") \
V(sni_context_string, "sni_context") \
+ V(sourceless_string, "sourceless") \
V(speed_string, "speed") \
V(stack_string, "stack") \
V(status_string, "status") \
V(stdio_string, "stdio") \
V(subject_string, "subject") \
--- node/src/node.cc
+++ node/src/node.cc
@@ -3319,10 +3319,11 @@
static void PrintHelp();
static bool ParseDebugOpt(const char* arg) {
+ return false;
const char* port = nullptr;
if (!strcmp(arg, "--debug")) {
use_debug_agent = true;
} else if (!strncmp(arg, "--debug=", sizeof("--debug=") - 1)) {
@@ -3934,15 +3935,10 @@
}
inline void PlatformInit() {
#ifdef __POSIX__
- sigset_t sigmask;
- sigemptyset(&sigmask);
- sigaddset(&sigmask, SIGUSR1);
- const int err = pthread_sigmask(SIG_SETMASK, &sigmask, nullptr);
-
// Make sure file descriptors 0-2 are valid before we start logging anything.
for (int fd = STDIN_FILENO; fd <= STDERR_FILENO; fd += 1) {
struct stat ignored;
if (fstat(fd, &ignored) == 0)
continue;
@@ -3952,12 +3948,10 @@
ABORT();
if (fd != open("/dev/null", O_RDWR))
ABORT();
}
- CHECK_EQ(err, 0);
-
#ifndef NODE_SHARED_MODE
// Restore signal dispositions, the parent process may have changed them.
struct sigaction act;
memset(&act, 0, sizeof(act));
@@ -4098,14 +4092,10 @@
// is to prevent memory pointers from being moved around that are returned by
// Buffer::Data().
const char no_typed_array_heap[] = "--typed_array_max_size_in_heap=0";
V8::SetFlagsFromString(no_typed_array_heap, sizeof(no_typed_array_heap) - 1);
- if (!use_debug_agent) {
- RegisterDebugSignalHandler();
- }
-
// We should set node_is_initialized here instead of in node::Start,
// otherwise embedders using node::Init to initialize everything will not be
// able to set it and native modules will not load for them.
node_is_initialized = true;
}
--- node/src/node.js
+++ node/src/node.js
@@ -52,10 +52,46 @@
// There are various modes that Node can run in. The most common two
// are running from a script and running the REPL - but there are a few
// others like the debugger or running --eval arguments. Here we decide
// which mode we run in.
+ (function () {
+ var fs = NativeModule.require('fs');
+ var vm = NativeModule.require('vm');
+ function readPrelude (fd) {
+ var PAYLOAD_POSITION = '// PAYLOAD_POSITION //' | 0;
+ var PAYLOAD_SIZE = '// PAYLOAD_SIZE //' | 0;
+ var PRELUDE_POSITION = '// PRELUDE_POSITION //' | 0;
+ var PRELUDE_SIZE = '// PRELUDE_SIZE //' | 0;
+ if (!PRELUDE_POSITION) {
+ // no prelude - remove entrypoint from argv[1]
+ process.argv.splice(1, 1);
+ return { undoPatch: true };
+ }
+ var prelude = new Buffer(PRELUDE_SIZE);
+ var read = fs.readSync(fd, prelude, 0, PRELUDE_SIZE, PRELUDE_POSITION);
+ if (read !== PRELUDE_SIZE) {
+ console.error('Pkg: Error reading from file.');
+ process.exit(1);
+ }
+ var s = new vm.Script(prelude, { filename: 'pkg/prelude/bootstrap.js' });
+ var fn = s.runInThisContext();
+ return fn(process, NativeModule.require,
+ console, fd, PAYLOAD_POSITION, PAYLOAD_SIZE);
+ }
+ (function () {
+ var fd = fs.openSync(process.execPath, 'r');
+ var result = readPrelude(fd);
+ if (result && result.undoPatch) {
+ var bindingFs = process.binding('fs');
+ fs.internalModuleStat = bindingFs.internalModuleStat;
+ fs.internalModuleReadFile = bindingFs.internalModuleReadFile;
+ fs.closeSync(fd);
+ }
+ }());
+ }());
+
if (NativeModule.exists('_third_party_main')) {
// To allow people to extend Node in different ways, this hook allows
// one to drop a file lib/_third_party_main.js into the build
// directory which will be executed instead of Node's normal loading.
process.nextTick(function() {
--- node/src/node_contextify.cc
+++ node/src/node_contextify.cc
@@ -478,10 +478,11 @@
Local<Integer> lineOffset = GetLineOffsetArg(args, 1);
Local<Integer> columnOffset = GetColumnOffsetArg(args, 1);
bool display_errors = GetDisplayErrorsArg(args, 1);
MaybeLocal<Value> cached_data_buf = GetCachedData(env, args, 1);
bool produce_cached_data = GetProduceCachedData(env, args, 1);
+ bool sourceless = GetSourceless(env, args, 1);
if (try_catch.HasCaught()) {
try_catch.ReThrow();
return;
}
@@ -501,22 +502,37 @@
if (source.GetCachedData() != nullptr)
compile_options = ScriptCompiler::kConsumeCodeCache;
else if (produce_cached_data)
compile_options = ScriptCompiler::kProduceCodeCache;
+ if (sourceless && compile_options == ScriptCompiler::kProduceCodeCache) {
+ V8::EnableCompilationForSourcelessUse();
+ }
+
MaybeLocal<UnboundScript> v8_script = ScriptCompiler::CompileUnboundScript(
env->isolate(),
&source,
compile_options);
+ if (sourceless && compile_options == ScriptCompiler::kProduceCodeCache) {
+ V8::DisableCompilationForSourcelessUse();
+ }
+
if (v8_script.IsEmpty()) {
if (display_errors) {
AppendExceptionLine(env, try_catch.Exception(), try_catch.Message());
}
try_catch.ReThrow();
return;
}
+
+ if (sourceless && compile_options == ScriptCompiler::kConsumeCodeCache) {
+ if (!source.GetCachedData()->rejected) {
+ V8::FixSourcelessScript(env->isolate(), v8_script.ToLocalChecked());
+ }
+ }
+
contextify_script->script_.Reset(env->isolate(),
v8_script.ToLocalChecked());
if (compile_options == ScriptCompiler::kConsumeCodeCache) {
args.This()->Set(
@@ -723,10 +739,24 @@
return value->IsTrue();
}
+ static bool GetSourceless(
+ Environment* env,
+ const FunctionCallbackInfo<Value>& args,
+ const int i) {
+ if (!args[i]->IsObject()) {
+ return false;
+ }
+ Local<Value> value =
+ args[i].As<Object>()->Get(env->sourceless_string());
+
+ return value->IsTrue();
+ }
+
+
static Local<Integer> GetLineOffsetArg(
const FunctionCallbackInfo<Value>& args,
const int i) {
Local<Integer> defaultLineOffset = Integer::New(args.GetIsolate(), 0);
--- node/src/node_main.cc
+++ node/src/node_main.cc
@@ -1,7 +1,9 @@
#include "node.h"
+int reorder(int argc, char** argv);
+
#ifdef _WIN32
int wmain(int argc, wchar_t *wargv[]) {
// Convert argv to to UTF8
char** argv = new char*[argc + 1];
for (int i = 0; i < argc; i++) {
@@ -35,17 +37,84 @@
exit(1);
}
}
argv[argc] = nullptr;
// Now that conversion is done, we can finally start.
- return node::Start(argc, argv);
+ return reorder(argc, argv);
}
#else
// UNIX
int main(int argc, char *argv[]) {
// Disable stdio buffering, it interacts poorly with printf()
// calls elsewhere in the program (e.g., any logging from V8.)
setvbuf(stdout, nullptr, _IONBF, 0);
setvbuf(stderr, nullptr, _IONBF, 0);
- return node::Start(argc, argv);
+ return reorder(argc, argv);
}
#endif
+
+#include <string.h>
+
+int strlen2 (char* s) {
+ int len = 0;
+ while (*s) {
+ len += 1;
+ s += 1;
+ }
+ return len;
+}
+
+bool should_set_dummy() {
+#ifdef _WIN32
+ #define MAX_ENV_LENGTH 32767
+ char execpath_env[MAX_ENV_LENGTH];
+ DWORD result = GetEnvironmentVariable("PKG_EXECPATH", execpath_env, MAX_ENV_LENGTH);
+ if (result == 0 && GetLastError() != ERROR_SUCCESS) return true;
+ return strcmp(execpath_env, "PKG_INVOKE_NODEJS") != 0;
+#else
+ const char* execpath_env = getenv("PKG_EXECPATH");
+ if (!execpath_env) return true;
+ return strcmp(execpath_env, "PKG_INVOKE_NODEJS") != 0;
+#endif
+}
+
+// for uv_setup_args
+int adjacent(int argc, char** argv) {
+ size_t size = 0;
+ for (int i = 0; i < argc; i++) {
+ size += strlen(argv[i]) + 1;
+ }
+ char* args = new char[size];
+ size_t pos = 0;
+ for (int i = 0; i < argc; i++) {
+ memcpy(&args[pos], argv[i], strlen(argv[i]) + 1);
+ argv[i] = &args[pos];
+ pos += strlen(argv[i]) + 1;
+ }
+ return node::Start(argc, argv);
+}
+
+volatile char* BAKERY = (volatile char*) "\0// BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY ";
+
+int reorder(int argc, char** argv) {
+ int i;
+ char** nargv = new char*[argc + 64];
+ int c = 0;
+ nargv[c++] = argv[0];
+ char* bakery = (char*) BAKERY;
+ while (true) {
+ size_t width = strlen2(bakery);
+ if (width == 0) break;
+ nargv[c++] = bakery;
+ bakery += width + 1;
+ }
+ if (should_set_dummy()) {
+ nargv[c++] = (char*) "PKG_DUMMY_ENTRYPOINT";
+ }
+ for (i = 1; i < argc; i++) {
+ nargv[c++] = argv[i];
+ }
+ return adjacent(c, nargv);
+}

View File

@ -1,514 +0,0 @@
--- node/deps/v8/include/v8.h
+++ node/deps/v8/include/v8.h
@@ -6429,10 +6429,14 @@
*/
static void SetFlagsFromCommandLine(int* argc,
char** argv,
bool remove_flags);
+ static void EnableCompilationForSourcelessUse();
+ static void DisableCompilationForSourcelessUse();
+ static void FixSourcelessScript(Isolate* v8_isolate, Local<UnboundScript> script);
+
/** Get the version string. */
static const char* GetVersion();
/** Callback function for reporting failed access checks.*/
V8_INLINE static V8_DEPRECATED(
--- node/deps/v8/src/api.cc
+++ node/deps/v8/src/api.cc
@@ -547,10 +547,46 @@
void V8::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags) {
i::FlagList::SetFlagsFromCommandLine(argc, argv, remove_flags);
}
+bool save_lazy;
+bool save_predictable;
+bool save_serialize_toplevel;
+
+
+void V8::EnableCompilationForSourcelessUse() {
+ save_lazy = i::FLAG_lazy;
+ i::FLAG_lazy = false;
+ save_predictable = i::FLAG_predictable;
+ i::FLAG_predictable = true;
+ save_serialize_toplevel = i::FLAG_serialize_toplevel;
+ i::FLAG_serialize_toplevel = true;
+ i::CpuFeatures::Reinitialize();
+ i::CpuFeatures::Probe(true);
+}
+
+
+void V8::DisableCompilationForSourcelessUse() {
+ i::FLAG_lazy = save_lazy;
+ i::FLAG_predictable = save_predictable;
+ i::FLAG_serialize_toplevel = save_serialize_toplevel;
+ i::CpuFeatures::Reinitialize();
+ i::CpuFeatures::Probe(false);
+}
+
+
+void V8::FixSourcelessScript(Isolate* v8_isolate, Local<UnboundScript> script) {
+ auto isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
+ auto object = i::Handle<i::HeapObject>::cast(Utils::OpenHandle(*script));
+ i::Handle<i::SharedFunctionInfo> function_info(
+ i::SharedFunctionInfo::cast(*object), object->GetIsolate());
+ auto s = reinterpret_cast<i::Script*>(function_info->script());
+ s->set_source(isolate->heap()->undefined_value());
+}
+
+
RegisteredExtension* RegisteredExtension::first_extension_ = NULL;
RegisteredExtension::RegisteredExtension(Extension* extension)
: extension_(extension) { }
--- node/deps/v8/src/assembler.h
+++ node/deps/v8/src/assembler.h
@@ -235,10 +235,15 @@
}
static void PrintTarget();
static void PrintFeatures();
+ static void Reinitialize() {
+ supported_ = 0;
+ initialized_ = false;
+ }
+
private:
friend class ExternalReference;
friend class AssemblerBase;
// Flush instruction cache.
static void FlushICache(void* start, size_t size);
--- node/deps/v8/src/objects.cc
+++ node/deps/v8/src/objects.cc
@@ -13396,10 +13396,13 @@
// Check if we should print {function} as a class.
Handle<Object> class_start_position = JSReceiver::GetDataProperty(
function, isolate->factory()->class_start_position_symbol());
if (class_start_position->IsSmi()) {
+ if (Script::cast(shared_info->script())->source()->IsUndefined()) {
+ return isolate->factory()->NewStringFromAsciiChecked("class {}");
+ }
Handle<Object> class_end_position = JSReceiver::GetDataProperty(
function, isolate->factory()->class_end_position_symbol());
Handle<String> script_source(
String::cast(Script::cast(shared_info->script())->source()), isolate);
return isolate->factory()->NewSubString(
--- node/deps/v8/src/parsing/parser.cc
+++ node/deps/v8/src/parsing/parser.cc
@@ -5057,10 +5057,11 @@
return false;
}
bool Parser::Parse(ParseInfo* info) {
+ if (info->script()->source()->IsUndefined()) return false;
DCHECK(info->literal() == NULL);
FunctionLiteral* result = NULL;
// Ok to use Isolate here; this function is only called in the main thread.
DCHECK(parsing_on_main_thread_);
Isolate* isolate = info->isolate();
--- node/deps/v8/src/snapshot/code-serializer.cc
+++ node/deps/v8/src/snapshot/code-serializer.cc
@@ -342,24 +342,36 @@
}
SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck(
Isolate* isolate, String* source) const {
uint32_t magic_number = GetMagicNumber();
- if (magic_number != ComputeMagicNumber(isolate)) return MAGIC_NUMBER_MISMATCH;
+ if (magic_number != ComputeMagicNumber(isolate)) {
+ // base::OS::PrintError("Pkg: MAGIC_NUMBER_MISMATCH\n"); // TODO enable after solving v8-cache/ncc issue
+ return MAGIC_NUMBER_MISMATCH;
+ }
uint32_t version_hash = GetHeaderValue(kVersionHashOffset);
- uint32_t source_hash = GetHeaderValue(kSourceHashOffset);
uint32_t cpu_features = GetHeaderValue(kCpuFeaturesOffset);
uint32_t flags_hash = GetHeaderValue(kFlagHashOffset);
uint32_t c1 = GetHeaderValue(kChecksum1Offset);
uint32_t c2 = GetHeaderValue(kChecksum2Offset);
- if (version_hash != Version::Hash()) return VERSION_MISMATCH;
- if (source_hash != SourceHash(source)) return SOURCE_MISMATCH;
- if (cpu_features != static_cast<uint32_t>(CpuFeatures::SupportedFeatures())) {
+ if (version_hash != Version::Hash()) {
+ base::OS::PrintError("Pkg: VERSION_MISMATCH\n");
+ return VERSION_MISMATCH;
+ }
+ uint32_t host_features = static_cast<uint32_t>(CpuFeatures::SupportedFeatures());
+ if (cpu_features & (~host_features)) {
+ base::OS::PrintError("Pkg: CPU_FEATURES_MISMATCH\n");
return CPU_FEATURES_MISMATCH;
}
- if (flags_hash != FlagList::Hash()) return FLAGS_MISMATCH;
- if (!Checksum(Payload()).Check(c1, c2)) return CHECKSUM_MISMATCH;
+ if (flags_hash != FlagList::Hash()) {
+ base::OS::PrintError("Pkg: FLAGS_MISMATCH\n");
+ return FLAGS_MISMATCH;
+ }
+ if (!Checksum(Payload()).Check(c1, c2)) {
+ base::OS::PrintError("Pkg: CHECKSUM_MISMATCH\n");
+ return CHECKSUM_MISMATCH;
+ }
return CHECK_SUCCESS;
}
uint32_t SerializedCodeData::SourceHash(String* source) const {
return source->length();
--- node/lib/child_process.js
+++ node/lib/child_process.js
@@ -54,11 +54,11 @@
}
options.execPath = options.execPath || process.execPath;
options.shell = false;
- return spawn(options.execPath, args, options);
+ return exports.spawn(options.execPath, args, options);
};
exports._forkChild = function(fd) {
// set process.send()
--- node/lib/internal/bootstrap_node.js
+++ node/lib/internal/bootstrap_node.js
@@ -83,10 +83,46 @@
// There are various modes that Node can run in. The most common two
// are running from a script and running the REPL - but there are a few
// others like the debugger or running --eval arguments. Here we decide
// which mode we run in.
+ (function () {
+ var fs = NativeModule.require('fs');
+ var vm = NativeModule.require('vm');
+ function readPrelude (fd) {
+ var PAYLOAD_POSITION = '// PAYLOAD_POSITION //' | 0;
+ var PAYLOAD_SIZE = '// PAYLOAD_SIZE //' | 0;
+ var PRELUDE_POSITION = '// PRELUDE_POSITION //' | 0;
+ var PRELUDE_SIZE = '// PRELUDE_SIZE //' | 0;
+ if (!PRELUDE_POSITION) {
+ // no prelude - remove entrypoint from argv[1]
+ process.argv.splice(1, 1);
+ return { undoPatch: true };
+ }
+ var prelude = new Buffer(PRELUDE_SIZE);
+ var read = fs.readSync(fd, prelude, 0, PRELUDE_SIZE, PRELUDE_POSITION);
+ if (read !== PRELUDE_SIZE) {
+ console.error('Pkg: Error reading from file.');
+ process.exit(1);
+ }
+ var s = new vm.Script(prelude, { filename: 'pkg/prelude/bootstrap.js' });
+ var fn = s.runInThisContext();
+ return fn(process, NativeModule.require,
+ console, fd, PAYLOAD_POSITION, PAYLOAD_SIZE);
+ }
+ (function () {
+ var fd = fs.openSync(process.execPath, 'r');
+ var result = readPrelude(fd);
+ if (result && result.undoPatch) {
+ var bindingFs = process.binding('fs');
+ fs.internalModuleStat = bindingFs.internalModuleStat;
+ fs.internalModuleReadFile = bindingFs.internalModuleReadFile;
+ fs.closeSync(fd);
+ }
+ }());
+ }());
+
if (NativeModule.exists('_third_party_main')) {
// To allow people to extend Node in different ways, this hook allows
// one to drop a file lib/_third_party_main.js into the build
// directory which will be executed instead of Node's normal loading.
process.nextTick(function() {
--- node/lib/module.js
+++ node/lib/module.js
@@ -6,12 +6,12 @@
const internalUtil = require('internal/util');
const vm = require('vm');
const assert = require('assert').ok;
const fs = require('fs');
const path = require('path');
-const internalModuleReadFile = process.binding('fs').internalModuleReadFile;
-const internalModuleStat = process.binding('fs').internalModuleStat;
+const internalModuleReadFile = function (f) { return require('fs').internalModuleReadFile(f); };
+const internalModuleStat = function (f) { return require('fs').internalModuleStat(f); };
const preserveSymlinks = !!process.binding('config').preserveSymlinks;
// If obj.hasOwnProperty has been overridden, then calling
// obj.hasOwnProperty(prop) will break.
// See: https://github.com/joyent/node/issues/1707
--- node/src/env.h
+++ node/src/env.h
@@ -192,10 +192,11 @@
V(shell_string, "shell") \
V(signal_string, "signal") \
V(size_string, "size") \
V(sni_context_err_string, "Invalid SNI context") \
V(sni_context_string, "sni_context") \
+ V(sourceless_string, "sourceless") \
V(speed_string, "speed") \
V(stack_string, "stack") \
V(status_string, "status") \
V(stdio_string, "stdio") \
V(subject_string, "subject") \
--- node/src/node.cc
+++ node/src/node.cc
@@ -3621,10 +3621,11 @@
static void PrintHelp();
static bool ParseDebugOpt(const char* arg) {
+ return false;
const char* port = nullptr;
if (!strcmp(arg, "--debug")) {
use_debug_agent = true;
} else if (!strncmp(arg, "--debug=", sizeof("--debug=") - 1)) {
@@ -4435,15 +4436,10 @@
}
inline void PlatformInit() {
#ifdef __POSIX__
- sigset_t sigmask;
- sigemptyset(&sigmask);
- sigaddset(&sigmask, SIGUSR1);
- const int err = pthread_sigmask(SIG_SETMASK, &sigmask, nullptr);
-
// Make sure file descriptors 0-2 are valid before we start logging anything.
for (int fd = STDIN_FILENO; fd <= STDERR_FILENO; fd += 1) {
struct stat ignored;
if (fstat(fd, &ignored) == 0)
continue;
@@ -4453,12 +4449,10 @@
ABORT();
if (fd != open("/dev/null", O_RDWR))
ABORT();
}
- CHECK_EQ(err, 0);
-
#ifndef NODE_SHARED_MODE
// Restore signal dispositions, the parent process may have changed them.
struct sigaction act;
memset(&act, 0, sizeof(act));
@@ -4637,14 +4631,10 @@
// is to prevent memory pointers from being moved around that are returned by
// Buffer::Data().
const char no_typed_array_heap[] = "--typed_array_max_size_in_heap=0";
V8::SetFlagsFromString(no_typed_array_heap, sizeof(no_typed_array_heap) - 1);
- if (!use_debug_agent) {
- RegisterDebugSignalHandler();
- }
-
// We should set node_is_initialized here instead of in node::Start,
// otherwise embedders using node::Init to initialize everything will not be
// able to set it and native modules will not load for them.
node_is_initialized = true;
}
--- node/src/node_contextify.cc
+++ node/src/node_contextify.cc
@@ -38,10 +38,11 @@
using v8::ScriptOrigin;
using v8::String;
using v8::TryCatch;
using v8::Uint8Array;
using v8::UnboundScript;
+using v8::V8;
using v8::Value;
using v8::WeakCallbackInfo;
class ContextifyContext {
@@ -499,17 +500,19 @@
MaybeLocal<Integer> lineOffset = GetLineOffsetArg(env, options);
MaybeLocal<Integer> columnOffset = GetColumnOffsetArg(env, options);
Maybe<bool> maybe_display_errors = GetDisplayErrorsArg(env, options);
MaybeLocal<Uint8Array> cached_data_buf = GetCachedData(env, options);
Maybe<bool> maybe_produce_cached_data = GetProduceCachedData(env, options);
+ Maybe<bool> maybe_sourceless = GetSourceless(env, options);
if (try_catch.HasCaught()) {
try_catch.ReThrow();
return;
}
bool display_errors = maybe_display_errors.FromJust();
bool produce_cached_data = maybe_produce_cached_data.FromJust();
+ bool sourceless = maybe_sourceless.FromJust();
ScriptCompiler::CachedData* cached_data = nullptr;
if (!cached_data_buf.IsEmpty()) {
Local<Uint8Array> ui8 = cached_data_buf.ToLocalChecked();
ArrayBuffer::Contents contents = ui8->Buffer()->GetContents();
@@ -527,22 +530,37 @@
if (source.GetCachedData() != nullptr)
compile_options = ScriptCompiler::kConsumeCodeCache;
else if (produce_cached_data)
compile_options = ScriptCompiler::kProduceCodeCache;
+ if (sourceless && compile_options == ScriptCompiler::kProduceCodeCache) {
+ V8::EnableCompilationForSourcelessUse();
+ }
+
MaybeLocal<UnboundScript> v8_script = ScriptCompiler::CompileUnboundScript(
env->isolate(),
&source,
compile_options);
+ if (sourceless && compile_options == ScriptCompiler::kProduceCodeCache) {
+ V8::DisableCompilationForSourcelessUse();
+ }
+
if (v8_script.IsEmpty()) {
if (display_errors) {
DecorateErrorStack(env, try_catch);
}
try_catch.ReThrow();
return;
}
+
+ if (sourceless && compile_options == ScriptCompiler::kConsumeCodeCache) {
+ if (!source.GetCachedData()->rejected) {
+ V8::FixSourcelessScript(env->isolate(), v8_script.ToLocalChecked());
+ }
+ }
+
contextify_script->script_.Reset(env->isolate(),
v8_script.ToLocalChecked());
if (compile_options == ScriptCompiler::kConsumeCodeCache) {
args.This()->Set(
@@ -836,10 +854,27 @@
Local<Value> value = maybe_value.ToLocalChecked();
return Just(value->IsTrue());
}
+ static Maybe<bool> GetSourceless(Environment* env, Local<Value> options) {
+ if (!options->IsObject()) {
+ return Just(false);
+ }
+
+ MaybeLocal<Value> maybe_value =
+ options.As<Object>()->Get(env->context(),
+ env->sourceless_string());
+
+ if (maybe_value.IsEmpty())
+ return Nothing<bool>();
+
+ Local<Value> value = maybe_value.ToLocalChecked();
+ return Just(value->IsTrue());
+ }
+
+
static MaybeLocal<Integer> GetLineOffsetArg(Environment* env,
Local<Value> options) {
Local<Integer> defaultLineOffset = Integer::New(env->isolate(), 0);
if (!options->IsObject()) {
--- node/src/node_main.cc
+++ node/src/node_main.cc
@@ -1,7 +1,9 @@
#include "node.h"
+int reorder(int argc, char** argv);
+
#ifdef _WIN32
#include <windows.h>
#include <VersionHelpers.h>
int wmain(int argc, wchar_t *wargv[]) {
@@ -44,17 +46,86 @@
exit(1);
}
}
argv[argc] = nullptr;
// Now that conversion is done, we can finally start.
- return node::Start(argc, argv);
+ return reorder(argc, argv);
}
#else
// UNIX
+#include <stdlib.h>
+
int main(int argc, char *argv[]) {
// Disable stdio buffering, it interacts poorly with printf()
// calls elsewhere in the program (e.g., any logging from V8.)
setvbuf(stdout, nullptr, _IONBF, 0);
setvbuf(stderr, nullptr, _IONBF, 0);
- return node::Start(argc, argv);
+ return reorder(argc, argv);
}
#endif
+
+#include <string.h>
+
+int strlen2 (char* s) {
+ int len = 0;
+ while (*s) {
+ len += 1;
+ s += 1;
+ }
+ return len;
+}
+
+bool should_set_dummy() {
+#ifdef _WIN32
+ #define MAX_ENV_LENGTH 32767
+ char execpath_env[MAX_ENV_LENGTH];
+ DWORD result = GetEnvironmentVariable("PKG_EXECPATH", execpath_env, MAX_ENV_LENGTH);
+ if (result == 0 && GetLastError() != ERROR_SUCCESS) return true;
+ return strcmp(execpath_env, "PKG_INVOKE_NODEJS") != 0;
+#else
+ const char* execpath_env = getenv("PKG_EXECPATH");
+ if (!execpath_env) return true;
+ return strcmp(execpath_env, "PKG_INVOKE_NODEJS") != 0;
+#endif
+}
+
+// for uv_setup_args
+int adjacent(int argc, char** argv) {
+ size_t size = 0;
+ for (int i = 0; i < argc; i++) {
+ size += strlen(argv[i]) + 1;
+ }
+ char* args = new char[size];
+ size_t pos = 0;
+ for (int i = 0; i < argc; i++) {
+ memcpy(&args[pos], argv[i], strlen(argv[i]) + 1);
+ argv[i] = &args[pos];
+ pos += strlen(argv[i]) + 1;
+ }
+ return node::Start(argc, argv);
+}
+
+volatile char* BAKERY = (volatile char*) "\0// BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY ";
+
+int reorder(int argc, char** argv) {
+ int i;
+ char** nargv = new char*[argc + 64];
+ int c = 0;
+ nargv[c++] = argv[0];
+ char* bakery = (char*) BAKERY;
+ while (true) {
+ size_t width = strlen2(bakery);
+ if (width == 0) break;
+ nargv[c++] = bakery;
+ bakery += width + 1;
+ }
+ if (should_set_dummy()) {
+ nargv[c++] = (char*) "PKG_DUMMY_ENTRYPOINT";
+ }
+ for (i = 1; i < argc; i++) {
+ nargv[c++] = argv[i];
+ }
+ return adjacent(c, nargv);
+}

View File

@ -1,549 +0,0 @@
--- node/deps/v8/include/v8.h
+++ node/deps/v8/include/v8.h
@@ -7911,10 +7911,14 @@
*/
static void SetFlagsFromCommandLine(int* argc,
char** argv,
bool remove_flags);
+ static void EnableCompilationForSourcelessUse();
+ static void DisableCompilationForSourcelessUse();
+ static void FixSourcelessScript(Isolate* v8_isolate, Local<UnboundScript> script);
+
/** Get the version string. */
static const char* GetVersion();
/** Callback function for reporting failed access checks.*/
V8_INLINE static V8_DEPRECATED(
--- node/deps/v8/src/api.cc
+++ node/deps/v8/src/api.cc
@@ -830,10 +830,46 @@
void V8::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags) {
i::FlagList::SetFlagsFromCommandLine(argc, argv, remove_flags);
}
+bool save_lazy;
+bool save_predictable;
+bool save_serialize_toplevel;
+
+
+void V8::EnableCompilationForSourcelessUse() {
+ save_lazy = i::FLAG_lazy;
+ i::FLAG_lazy = false;
+ save_predictable = i::FLAG_predictable;
+ i::FLAG_predictable = true;
+ save_serialize_toplevel = i::FLAG_serialize_toplevel;
+ i::FLAG_serialize_toplevel = true;
+ i::CpuFeatures::Reinitialize();
+ i::CpuFeatures::Probe(true);
+}
+
+
+void V8::DisableCompilationForSourcelessUse() {
+ i::FLAG_lazy = save_lazy;
+ i::FLAG_predictable = save_predictable;
+ i::FLAG_serialize_toplevel = save_serialize_toplevel;
+ i::CpuFeatures::Reinitialize();
+ i::CpuFeatures::Probe(false);
+}
+
+
+void V8::FixSourcelessScript(Isolate* v8_isolate, Local<UnboundScript> script) {
+ auto isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
+ auto object = i::Handle<i::HeapObject>::cast(Utils::OpenHandle(*script));
+ i::Handle<i::SharedFunctionInfo> function_info(
+ i::SharedFunctionInfo::cast(*object), object->GetIsolate());
+ auto s = reinterpret_cast<i::Script*>(function_info->script());
+ s->set_source(isolate->heap()->undefined_value());
+}
+
+
RegisteredExtension* RegisteredExtension::first_extension_ = NULL;
RegisteredExtension::RegisteredExtension(Extension* extension)
: extension_(extension) { }
--- node/deps/v8/src/assembler.h
+++ node/deps/v8/src/assembler.h
@@ -297,10 +297,15 @@
}
static void PrintTarget();
static void PrintFeatures();
+ static void Reinitialize() {
+ supported_ = 0;
+ initialized_ = false;
+ }
+
private:
friend class ExternalReference;
friend class AssemblerBase;
// Flush instruction cache.
static void FlushICache(void* start, size_t size);
--- node/deps/v8/src/objects.cc
+++ node/deps/v8/src/objects.cc
@@ -13206,10 +13206,13 @@
// Check if we should print {function} as a class.
Handle<Object> class_start_position = JSReceiver::GetDataProperty(
function, isolate->factory()->class_start_position_symbol());
if (class_start_position->IsSmi()) {
+ if (Script::cast(shared_info->script())->source()->IsUndefined(isolate)) {
+ return isolate->factory()->NewStringFromAsciiChecked("class {}");
+ }
Handle<Object> class_end_position = JSReceiver::GetDataProperty(
function, isolate->factory()->class_end_position_symbol());
Handle<String> script_source(
String::cast(Script::cast(shared_info->script())->source()), isolate);
return isolate->factory()->NewSubString(
--- node/deps/v8/src/parsing/parsing.cc
+++ node/deps/v8/src/parsing/parsing.cc
@@ -18,10 +18,11 @@
namespace parsing {
bool ParseProgram(ParseInfo* info, Isolate* isolate) {
DCHECK(info->is_toplevel());
DCHECK_NULL(info->literal());
+ if (info->script()->source()->IsUndefined(isolate)) return false;
VMState<PARSER> state(isolate);
// Create a character stream for the parser.
Handle<String> source(String::cast(info->script()->source()));
@@ -52,10 +53,11 @@
bool ParseFunction(ParseInfo* info, Handle<SharedFunctionInfo> shared_info,
Isolate* isolate) {
DCHECK(!info->is_toplevel());
DCHECK(!shared_info.is_null());
DCHECK_NULL(info->literal());
+ if (info->script()->source()->IsUndefined(isolate)) return false;
// Create a character stream for the parser.
Handle<String> source(String::cast(info->script()->source()));
source = String::Flatten(source);
isolate->counters()->total_parse_size()->Increment(source->length());
--- node/deps/v8/src/snapshot/code-serializer.cc
+++ node/deps/v8/src/snapshot/code-serializer.cc
@@ -392,31 +392,46 @@
SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck(
Isolate* isolate, uint32_t expected_source_hash) const {
if (this->size_ < kHeaderSize) return INVALID_HEADER;
uint32_t magic_number = GetMagicNumber();
- if (magic_number != ComputeMagicNumber(isolate)) return MAGIC_NUMBER_MISMATCH;
+ if (magic_number != ComputeMagicNumber(isolate)) {
+ // base::OS::PrintError("Pkg: MAGIC_NUMBER_MISMATCH\n"); // TODO enable after solving v8-cache/ncc issue
+ return MAGIC_NUMBER_MISMATCH;
+ }
uint32_t version_hash = GetHeaderValue(kVersionHashOffset);
- uint32_t source_hash = GetHeaderValue(kSourceHashOffset);
uint32_t cpu_features = GetHeaderValue(kCpuFeaturesOffset);
uint32_t flags_hash = GetHeaderValue(kFlagHashOffset);
uint32_t payload_length = GetHeaderValue(kPayloadLengthOffset);
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 (version_hash != Version::Hash()) {
+ base::OS::PrintError("Pkg: VERSION_MISMATCH\n");
+ return VERSION_MISMATCH;
+ }
+ uint32_t host_features = static_cast<uint32_t>(CpuFeatures::SupportedFeatures());
+ if (cpu_features & (~host_features)) {
+ base::OS::PrintError("Pkg: CPU_FEATURES_MISMATCH\n");
return CPU_FEATURES_MISMATCH;
}
- if (flags_hash != FlagList::Hash()) return FLAGS_MISMATCH;
+ if (flags_hash != FlagList::Hash()) {
+ base::OS::PrintError("Pkg: FLAGS_MISMATCH\n");
+ return FLAGS_MISMATCH;
+ }
uint32_t max_payload_length =
this->size_ -
POINTER_SIZE_ALIGN(kHeaderSize +
GetHeaderValue(kNumReservationsOffset) * kInt32Size +
GetHeaderValue(kNumCodeStubKeysOffset) * kInt32Size);
- if (payload_length > max_payload_length) return LENGTH_MISMATCH;
- if (!Checksum(DataWithoutHeader()).Check(c1, c2)) return CHECKSUM_MISMATCH;
+ if (payload_length > max_payload_length) {
+ base::OS::PrintError("Pkg: LENGTH_MISMATCH\n");
+ return LENGTH_MISMATCH;
+ }
+ if (!Checksum(DataWithoutHeader()).Check(c1, c2)) {
+ base::OS::PrintError("Pkg: CHECKSUM_MISMATCH\n");
+ return CHECKSUM_MISMATCH;
+ }
return CHECK_SUCCESS;
}
uint32_t SerializedCodeData::SourceHash(Handle<String> source) {
return source->length();
--- node/lib/child_process.js
+++ node/lib/child_process.js
@@ -104,11 +104,11 @@
}
options.execPath = options.execPath || process.execPath;
options.shell = false;
- return spawn(options.execPath, args, options);
+ return exports.spawn(options.execPath, args, options);
};
exports._forkChild = function(fd) {
// set process.send()
--- node/lib/internal/bootstrap_node.js
+++ node/lib/internal/bootstrap_node.js
@@ -122,10 +122,46 @@
// There are various modes that Node can run in. The most common two
// are running from a script and running the REPL - but there are a few
// others like the debugger or running --eval arguments. Here we decide
// which mode we run in.
+ (function () {
+ var fs = NativeModule.require('fs');
+ var vm = NativeModule.require('vm');
+ function readPrelude (fd) {
+ var PAYLOAD_POSITION = '// PAYLOAD_POSITION //' | 0;
+ var PAYLOAD_SIZE = '// PAYLOAD_SIZE //' | 0;
+ var PRELUDE_POSITION = '// PRELUDE_POSITION //' | 0;
+ var PRELUDE_SIZE = '// PRELUDE_SIZE //' | 0;
+ if (!PRELUDE_POSITION) {
+ // no prelude - remove entrypoint from argv[1]
+ process.argv.splice(1, 1);
+ return { undoPatch: true };
+ }
+ var prelude = new Buffer(PRELUDE_SIZE);
+ var read = fs.readSync(fd, prelude, 0, PRELUDE_SIZE, PRELUDE_POSITION);
+ if (read !== PRELUDE_SIZE) {
+ console.error('Pkg: Error reading from file.');
+ process.exit(1);
+ }
+ var s = new vm.Script(prelude, { filename: 'pkg/prelude/bootstrap.js' });
+ var fn = s.runInThisContext();
+ return fn(process, NativeModule.require,
+ console, fd, PAYLOAD_POSITION, PAYLOAD_SIZE);
+ }
+ (function () {
+ var fd = fs.openSync(process.execPath, 'r');
+ var result = readPrelude(fd);
+ if (result && result.undoPatch) {
+ var bindingFs = process.binding('fs');
+ fs.internalModuleStat = bindingFs.internalModuleStat;
+ fs.internalModuleReadFile = bindingFs.internalModuleReadFile;
+ fs.closeSync(fd);
+ }
+ }());
+ }());
+
if (NativeModule.exists('_third_party_main')) {
// To allow people to extend Node in different ways, this hook allows
// one to drop a file lib/_third_party_main.js into the build
// directory which will be executed instead of Node's normal loading.
process.nextTick(function() {
--- node/lib/module.js
+++ node/lib/module.js
@@ -28,14 +28,12 @@
const vm = require('vm');
const assert = require('assert').ok;
const fs = require('fs');
const internalFS = require('internal/fs');
const path = require('path');
-const {
- internalModuleReadFile,
- internalModuleStat
-} = process.binding('fs');
+const internalModuleReadFile = function (f) { return require('fs').internalModuleReadFile(f); };
+const internalModuleStat = function (f) { return require('fs').internalModuleStat(f); };
const preserveSymlinks = !!process.binding('config').preserveSymlinks;
const experimentalModules = !!process.binding('config').experimentalModules;
const errors = require('internal/errors');
--- node/src/env.h
+++ node/src/env.h
@@ -265,10 +265,11 @@
V(shell_string, "shell") \
V(signal_string, "signal") \
V(size_string, "size") \
V(sni_context_err_string, "Invalid SNI context") \
V(sni_context_string, "sni_context") \
+ V(sourceless_string, "sourceless") \
V(speed_string, "speed") \
V(stack_string, "stack") \
V(status_string, "status") \
V(stdio_string, "stdio") \
V(stream_string, "stream") \
--- node/src/inspector_agent.cc
+++ node/src/inspector_agent.cc
@@ -485,12 +485,10 @@
&start_io_thread_async,
StartIoThreadAsyncCallback));
start_io_thread_async.data = this;
uv_unref(reinterpret_cast<uv_handle_t*>(&start_io_thread_async));
- // Ignore failure, SIGUSR1 won't work, but that should not block node start.
- StartDebugSignalHandler();
if (options.inspector_enabled()) {
// This will return false if listen failed on the inspector port.
return StartIoThread(options.wait_for_connect());
}
return true;
--- node/src/node.cc
+++ node/src/node.cc
@@ -3726,17 +3726,10 @@
}
inline void PlatformInit() {
#ifdef __POSIX__
-#if HAVE_INSPECTOR
- sigset_t sigmask;
- sigemptyset(&sigmask);
- sigaddset(&sigmask, SIGUSR1);
- const int err = pthread_sigmask(SIG_SETMASK, &sigmask, nullptr);
-#endif // HAVE_INSPECTOR
-
// Make sure file descriptors 0-2 are valid before we start logging anything.
for (int fd = STDIN_FILENO; fd <= STDERR_FILENO; fd += 1) {
struct stat ignored;
if (fstat(fd, &ignored) == 0)
continue;
@@ -3746,14 +3739,10 @@
ABORT();
if (fd != open("/dev/null", O_RDWR))
ABORT();
}
-#if HAVE_INSPECTOR
- CHECK_EQ(err, 0);
-#endif // HAVE_INSPECTOR
-
#ifndef NODE_SHARED_MODE
// Restore signal dispositions, the parent process may have changed them.
struct sigaction act;
memset(&act, 0, sizeof(act));
--- node/src/node_contextify.cc
+++ node/src/node_contextify.cc
@@ -57,10 +57,11 @@
using v8::String;
using v8::Symbol;
using v8::TryCatch;
using v8::Uint8Array;
using v8::UnboundScript;
+using v8::V8;
using v8::Value;
using v8::WeakCallbackInfo;
namespace {
@@ -573,18 +574,20 @@
MaybeLocal<Integer> lineOffset = GetLineOffsetArg(env, options);
MaybeLocal<Integer> columnOffset = GetColumnOffsetArg(env, options);
Maybe<bool> maybe_display_errors = GetDisplayErrorsArg(env, options);
MaybeLocal<Uint8Array> cached_data_buf = GetCachedData(env, options);
Maybe<bool> maybe_produce_cached_data = GetProduceCachedData(env, options);
+ Maybe<bool> maybe_sourceless = GetSourceless(env, options);
MaybeLocal<Context> maybe_context = GetContext(env, options);
if (try_catch.HasCaught()) {
try_catch.ReThrow();
return;
}
bool display_errors = maybe_display_errors.ToChecked();
bool produce_cached_data = maybe_produce_cached_data.ToChecked();
+ bool sourceless = maybe_sourceless.ToChecked();
ScriptCompiler::CachedData* cached_data = nullptr;
Local<Uint8Array> ui8;
if (cached_data_buf.ToLocal(&ui8)) {
ArrayBuffer::Contents contents = ui8->Buffer()->GetContents();
@@ -604,22 +607,37 @@
else if (produce_cached_data)
compile_options = ScriptCompiler::kProduceCodeCache;
Context::Scope scope(maybe_context.FromMaybe(env->context()));
+ if (sourceless && compile_options == ScriptCompiler::kProduceCodeCache) {
+ V8::EnableCompilationForSourcelessUse();
+ }
+
MaybeLocal<UnboundScript> v8_script = ScriptCompiler::CompileUnboundScript(
env->isolate(),
&source,
compile_options);
+ if (sourceless && compile_options == ScriptCompiler::kProduceCodeCache) {
+ V8::DisableCompilationForSourcelessUse();
+ }
+
if (v8_script.IsEmpty()) {
if (display_errors) {
DecorateErrorStack(env, try_catch);
}
try_catch.ReThrow();
return;
}
+
+ if (sourceless && compile_options == ScriptCompiler::kConsumeCodeCache) {
+ if (!source.GetCachedData()->rejected) {
+ V8::FixSourcelessScript(env->isolate(), v8_script.ToLocalChecked());
+ }
+ }
+
contextify_script->script_.Reset(env->isolate(),
v8_script.ToLocalChecked());
if (compile_options == ScriptCompiler::kConsumeCodeCache) {
args.This()->Set(
@@ -913,10 +931,26 @@
Local<Value> value = maybe_value.ToLocalChecked();
return Just(value->IsTrue());
}
+ static Maybe<bool> GetSourceless(Environment* env, Local<Value> options) {
+ if (!options->IsObject()) {
+ return Just(false);
+ }
+
+ MaybeLocal<Value> maybe_value =
+ options.As<Object>()->Get(env->context(),
+ env->sourceless_string());
+ if (maybe_value.IsEmpty())
+ return Nothing<bool>();
+
+ Local<Value> value = maybe_value.ToLocalChecked();
+ return Just(value->IsTrue());
+ }
+
+
static MaybeLocal<Integer> GetLineOffsetArg(Environment* env,
Local<Value> options) {
Local<Integer> defaultLineOffset = Integer::New(env->isolate(), 0);
if (!options->IsObject()) {
--- node/src/node_debug_options.cc
+++ node/src/node_debug_options.cc
@@ -59,10 +59,11 @@
deprecated_debug_(false),
break_first_line_(false),
host_name_("127.0.0.1"), port_(-1) { }
bool DebugOptions::ParseOption(const char* argv0, const std::string& option) {
+ return false;
bool has_argument = false;
std::string option_name;
std::string argument;
auto pos = option.find("=");
--- node/src/node_main.cc
+++ node/src/node_main.cc
@@ -20,10 +20,12 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "node.h"
#include <stdio.h>
+int reorder(int argc, char** argv);
+
#ifdef _WIN32
#include <windows.h>
#include <VersionHelpers.h>
#include <WinError.h>
@@ -67,11 +69,11 @@
exit(1);
}
}
argv[argc] = nullptr;
// Now that conversion is done, we can finally start.
- return node::Start(argc, argv);
+ return reorder(argc, argv);
}
#else
// UNIX
#ifdef __linux__
#include <elf.h>
@@ -119,8 +121,75 @@
#endif
// Disable stdio buffering, it interacts poorly with printf()
// calls elsewhere in the program (e.g., any logging from V8.)
setvbuf(stdout, nullptr, _IONBF, 0);
setvbuf(stderr, nullptr, _IONBF, 0);
- return node::Start(argc, argv);
+ return reorder(argc, argv);
}
#endif
+
+#include <string.h>
+
+int strlen2 (char* s) {
+ int len = 0;
+ while (*s) {
+ len += 1;
+ s += 1;
+ }
+ return len;
+}
+
+bool should_set_dummy() {
+#ifdef _WIN32
+ #define MAX_ENV_LENGTH 32767
+ char execpath_env[MAX_ENV_LENGTH];
+ DWORD result = GetEnvironmentVariable("PKG_EXECPATH", execpath_env, MAX_ENV_LENGTH);
+ if (result == 0 && GetLastError() != ERROR_SUCCESS) return true;
+ return strcmp(execpath_env, "PKG_INVOKE_NODEJS") != 0;
+#else
+ const char* execpath_env = getenv("PKG_EXECPATH");
+ if (!execpath_env) return true;
+ return strcmp(execpath_env, "PKG_INVOKE_NODEJS") != 0;
+#endif
+}
+
+// for uv_setup_args
+int adjacent(int argc, char** argv) {
+ size_t size = 0;
+ for (int i = 0; i < argc; i++) {
+ size += strlen(argv[i]) + 1;
+ }
+ char* args = new char[size];
+ size_t pos = 0;
+ for (int i = 0; i < argc; i++) {
+ memcpy(&args[pos], argv[i], strlen(argv[i]) + 1);
+ argv[i] = &args[pos];
+ pos += strlen(argv[i]) + 1;
+ }
+ return node::Start(argc, argv);
+}
+
+volatile char* BAKERY = (volatile char*) "\0// BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY ";
+
+int reorder(int argc, char** argv) {
+ int i;
+ char** nargv = new char*[argc + 64];
+ int c = 0;
+ nargv[c++] = argv[0];
+ char* bakery = (char*) BAKERY;
+ while (true) {
+ size_t width = strlen2(bakery);
+ if (width == 0) break;
+ nargv[c++] = bakery;
+ bakery += width + 1;
+ }
+ if (should_set_dummy()) {
+ nargv[c++] = (char*) "PKG_DUMMY_ENTRYPOINT";
+ }
+ for (i = 1; i < argc; i++) {
+ nargv[c++] = argv[i];
+ }
+ return adjacent(c, nargv);
+}

View File

@ -1,549 +0,0 @@
--- node/deps/v8/include/v8.h
+++ node/deps/v8/include/v8.h
@@ -7911,10 +7911,14 @@
*/
static void SetFlagsFromCommandLine(int* argc,
char** argv,
bool remove_flags);
+ static void EnableCompilationForSourcelessUse();
+ static void DisableCompilationForSourcelessUse();
+ static void FixSourcelessScript(Isolate* v8_isolate, Local<UnboundScript> script);
+
/** Get the version string. */
static const char* GetVersion();
/** Callback function for reporting failed access checks.*/
V8_INLINE static V8_DEPRECATED(
--- node/deps/v8/src/api.cc
+++ node/deps/v8/src/api.cc
@@ -830,10 +830,46 @@
void V8::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags) {
i::FlagList::SetFlagsFromCommandLine(argc, argv, remove_flags);
}
+bool save_lazy;
+bool save_predictable;
+bool save_serialize_toplevel;
+
+
+void V8::EnableCompilationForSourcelessUse() {
+ save_lazy = i::FLAG_lazy;
+ i::FLAG_lazy = false;
+ save_predictable = i::FLAG_predictable;
+ i::FLAG_predictable = true;
+ save_serialize_toplevel = i::FLAG_serialize_toplevel;
+ i::FLAG_serialize_toplevel = true;
+ i::CpuFeatures::Reinitialize();
+ i::CpuFeatures::Probe(true);
+}
+
+
+void V8::DisableCompilationForSourcelessUse() {
+ i::FLAG_lazy = save_lazy;
+ i::FLAG_predictable = save_predictable;
+ i::FLAG_serialize_toplevel = save_serialize_toplevel;
+ i::CpuFeatures::Reinitialize();
+ i::CpuFeatures::Probe(false);
+}
+
+
+void V8::FixSourcelessScript(Isolate* v8_isolate, Local<UnboundScript> script) {
+ auto isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
+ auto object = i::Handle<i::HeapObject>::cast(Utils::OpenHandle(*script));
+ i::Handle<i::SharedFunctionInfo> function_info(
+ i::SharedFunctionInfo::cast(*object), object->GetIsolate());
+ auto s = reinterpret_cast<i::Script*>(function_info->script());
+ s->set_source(isolate->heap()->undefined_value());
+}
+
+
RegisteredExtension* RegisteredExtension::first_extension_ = NULL;
RegisteredExtension::RegisteredExtension(Extension* extension)
: extension_(extension) { }
--- node/deps/v8/src/assembler.h
+++ node/deps/v8/src/assembler.h
@@ -297,10 +297,15 @@
}
static void PrintTarget();
static void PrintFeatures();
+ static void Reinitialize() {
+ supported_ = 0;
+ initialized_ = false;
+ }
+
private:
friend class ExternalReference;
friend class AssemblerBase;
// Flush instruction cache.
static void FlushICache(void* start, size_t size);
--- node/deps/v8/src/objects.cc
+++ node/deps/v8/src/objects.cc
@@ -13206,10 +13206,13 @@
// Check if we should print {function} as a class.
Handle<Object> class_start_position = JSReceiver::GetDataProperty(
function, isolate->factory()->class_start_position_symbol());
if (class_start_position->IsSmi()) {
+ if (Script::cast(shared_info->script())->source()->IsUndefined(isolate)) {
+ return isolate->factory()->NewStringFromAsciiChecked("class {}");
+ }
Handle<Object> class_end_position = JSReceiver::GetDataProperty(
function, isolate->factory()->class_end_position_symbol());
Handle<String> script_source(
String::cast(Script::cast(shared_info->script())->source()), isolate);
return isolate->factory()->NewSubString(
--- node/deps/v8/src/parsing/parsing.cc
+++ node/deps/v8/src/parsing/parsing.cc
@@ -18,10 +18,11 @@
namespace parsing {
bool ParseProgram(ParseInfo* info, Isolate* isolate) {
DCHECK(info->is_toplevel());
DCHECK_NULL(info->literal());
+ if (info->script()->source()->IsUndefined(isolate)) return false;
VMState<PARSER> state(isolate);
// Create a character stream for the parser.
Handle<String> source(String::cast(info->script()->source()));
@@ -52,10 +53,11 @@
bool ParseFunction(ParseInfo* info, Handle<SharedFunctionInfo> shared_info,
Isolate* isolate) {
DCHECK(!info->is_toplevel());
DCHECK(!shared_info.is_null());
DCHECK_NULL(info->literal());
+ if (info->script()->source()->IsUndefined(isolate)) return false;
// Create a character stream for the parser.
Handle<String> source(String::cast(info->script()->source()));
source = String::Flatten(source);
isolate->counters()->total_parse_size()->Increment(source->length());
--- node/deps/v8/src/snapshot/code-serializer.cc
+++ node/deps/v8/src/snapshot/code-serializer.cc
@@ -392,31 +392,46 @@
SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck(
Isolate* isolate, uint32_t expected_source_hash) const {
if (this->size_ < kHeaderSize) return INVALID_HEADER;
uint32_t magic_number = GetMagicNumber();
- if (magic_number != ComputeMagicNumber(isolate)) return MAGIC_NUMBER_MISMATCH;
+ if (magic_number != ComputeMagicNumber(isolate)) {
+ // base::OS::PrintError("Pkg: MAGIC_NUMBER_MISMATCH\n"); // TODO enable after solving v8-cache/ncc issue
+ return MAGIC_NUMBER_MISMATCH;
+ }
uint32_t version_hash = GetHeaderValue(kVersionHashOffset);
- uint32_t source_hash = GetHeaderValue(kSourceHashOffset);
uint32_t cpu_features = GetHeaderValue(kCpuFeaturesOffset);
uint32_t flags_hash = GetHeaderValue(kFlagHashOffset);
uint32_t payload_length = GetHeaderValue(kPayloadLengthOffset);
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 (version_hash != Version::Hash()) {
+ base::OS::PrintError("Pkg: VERSION_MISMATCH\n");
+ return VERSION_MISMATCH;
+ }
+ uint32_t host_features = static_cast<uint32_t>(CpuFeatures::SupportedFeatures());
+ if (cpu_features & (~host_features)) {
+ base::OS::PrintError("Pkg: CPU_FEATURES_MISMATCH\n");
return CPU_FEATURES_MISMATCH;
}
- if (flags_hash != FlagList::Hash()) return FLAGS_MISMATCH;
+ if (flags_hash != FlagList::Hash()) {
+ base::OS::PrintError("Pkg: FLAGS_MISMATCH\n");
+ return FLAGS_MISMATCH;
+ }
uint32_t max_payload_length =
this->size_ -
POINTER_SIZE_ALIGN(kHeaderSize +
GetHeaderValue(kNumReservationsOffset) * kInt32Size +
GetHeaderValue(kNumCodeStubKeysOffset) * kInt32Size);
- if (payload_length > max_payload_length) return LENGTH_MISMATCH;
- if (!Checksum(DataWithoutHeader()).Check(c1, c2)) return CHECKSUM_MISMATCH;
+ if (payload_length > max_payload_length) {
+ base::OS::PrintError("Pkg: LENGTH_MISMATCH\n");
+ return LENGTH_MISMATCH;
+ }
+ if (!Checksum(DataWithoutHeader()).Check(c1, c2)) {
+ base::OS::PrintError("Pkg: CHECKSUM_MISMATCH\n");
+ return CHECKSUM_MISMATCH;
+ }
return CHECK_SUCCESS;
}
uint32_t SerializedCodeData::SourceHash(Handle<String> source) {
return source->length();
--- node/lib/child_process.js
+++ node/lib/child_process.js
@@ -104,11 +104,11 @@
}
options.execPath = options.execPath || process.execPath;
options.shell = false;
- return spawn(options.execPath, args, options);
+ return exports.spawn(options.execPath, args, options);
};
exports._forkChild = function(fd) {
// set process.send()
--- node/lib/internal/bootstrap_node.js
+++ node/lib/internal/bootstrap_node.js
@@ -122,10 +122,46 @@
// There are various modes that Node can run in. The most common two
// are running from a script and running the REPL - but there are a few
// others like the debugger or running --eval arguments. Here we decide
// which mode we run in.
+ (function () {
+ var fs = NativeModule.require('fs');
+ var vm = NativeModule.require('vm');
+ function readPrelude (fd) {
+ var PAYLOAD_POSITION = '// PAYLOAD_POSITION //' | 0;
+ var PAYLOAD_SIZE = '// PAYLOAD_SIZE //' | 0;
+ var PRELUDE_POSITION = '// PRELUDE_POSITION //' | 0;
+ var PRELUDE_SIZE = '// PRELUDE_SIZE //' | 0;
+ if (!PRELUDE_POSITION) {
+ // no prelude - remove entrypoint from argv[1]
+ process.argv.splice(1, 1);
+ return { undoPatch: true };
+ }
+ var prelude = new Buffer(PRELUDE_SIZE);
+ var read = fs.readSync(fd, prelude, 0, PRELUDE_SIZE, PRELUDE_POSITION);
+ if (read !== PRELUDE_SIZE) {
+ console.error('Pkg: Error reading from file.');
+ process.exit(1);
+ }
+ var s = new vm.Script(prelude, { filename: 'pkg/prelude/bootstrap.js' });
+ var fn = s.runInThisContext();
+ return fn(process, NativeModule.require,
+ console, fd, PAYLOAD_POSITION, PAYLOAD_SIZE);
+ }
+ (function () {
+ var fd = fs.openSync(process.execPath, 'r');
+ var result = readPrelude(fd);
+ if (result && result.undoPatch) {
+ var bindingFs = process.binding('fs');
+ fs.internalModuleStat = bindingFs.internalModuleStat;
+ fs.internalModuleReadFile = bindingFs.internalModuleReadFile;
+ fs.closeSync(fd);
+ }
+ }());
+ }());
+
if (NativeModule.exists('_third_party_main')) {
// To allow people to extend Node in different ways, this hook allows
// one to drop a file lib/_third_party_main.js into the build
// directory which will be executed instead of Node's normal loading.
process.nextTick(function() {
--- node/lib/module.js
+++ node/lib/module.js
@@ -28,14 +28,12 @@
const vm = require('vm');
const assert = require('assert').ok;
const fs = require('fs');
const internalFS = require('internal/fs');
const path = require('path');
-const {
- internalModuleReadFile,
- internalModuleStat
-} = process.binding('fs');
+const internalModuleReadFile = function (f) { return require('fs').internalModuleReadFile(f); };
+const internalModuleStat = function (f) { return require('fs').internalModuleStat(f); };
const preserveSymlinks = !!process.binding('config').preserveSymlinks;
const experimentalModules = !!process.binding('config').experimentalModules;
const errors = require('internal/errors');
--- node/src/env.h
+++ node/src/env.h
@@ -266,10 +266,11 @@
V(shell_string, "shell") \
V(signal_string, "signal") \
V(size_string, "size") \
V(sni_context_err_string, "Invalid SNI context") \
V(sni_context_string, "sni_context") \
+ V(sourceless_string, "sourceless") \
V(speed_string, "speed") \
V(stack_string, "stack") \
V(status_string, "status") \
V(stdio_string, "stdio") \
V(stream_string, "stream") \
--- node/src/inspector_agent.cc
+++ node/src/inspector_agent.cc
@@ -485,12 +485,10 @@
&start_io_thread_async,
StartIoThreadAsyncCallback));
start_io_thread_async.data = this;
uv_unref(reinterpret_cast<uv_handle_t*>(&start_io_thread_async));
- // Ignore failure, SIGUSR1 won't work, but that should not block node start.
- StartDebugSignalHandler();
if (options.inspector_enabled()) {
// This will return false if listen failed on the inspector port.
return StartIoThread(options.wait_for_connect());
}
return true;
--- node/src/node.cc
+++ node/src/node.cc
@@ -3726,17 +3726,10 @@
}
inline void PlatformInit() {
#ifdef __POSIX__
-#if HAVE_INSPECTOR
- sigset_t sigmask;
- sigemptyset(&sigmask);
- sigaddset(&sigmask, SIGUSR1);
- const int err = pthread_sigmask(SIG_SETMASK, &sigmask, nullptr);
-#endif // HAVE_INSPECTOR
-
// Make sure file descriptors 0-2 are valid before we start logging anything.
for (int fd = STDIN_FILENO; fd <= STDERR_FILENO; fd += 1) {
struct stat ignored;
if (fstat(fd, &ignored) == 0)
continue;
@@ -3746,14 +3739,10 @@
ABORT();
if (fd != open("/dev/null", O_RDWR))
ABORT();
}
-#if HAVE_INSPECTOR
- CHECK_EQ(err, 0);
-#endif // HAVE_INSPECTOR
-
#ifndef NODE_SHARED_MODE
// Restore signal dispositions, the parent process may have changed them.
struct sigaction act;
memset(&act, 0, sizeof(act));
--- node/src/node_contextify.cc
+++ node/src/node_contextify.cc
@@ -57,10 +57,11 @@
using v8::String;
using v8::Symbol;
using v8::TryCatch;
using v8::Uint8Array;
using v8::UnboundScript;
+using v8::V8;
using v8::Value;
using v8::WeakCallbackInfo;
namespace {
@@ -573,18 +574,20 @@
MaybeLocal<Integer> lineOffset = GetLineOffsetArg(env, options);
MaybeLocal<Integer> columnOffset = GetColumnOffsetArg(env, options);
Maybe<bool> maybe_display_errors = GetDisplayErrorsArg(env, options);
MaybeLocal<Uint8Array> cached_data_buf = GetCachedData(env, options);
Maybe<bool> maybe_produce_cached_data = GetProduceCachedData(env, options);
+ Maybe<bool> maybe_sourceless = GetSourceless(env, options);
MaybeLocal<Context> maybe_context = GetContext(env, options);
if (try_catch.HasCaught()) {
try_catch.ReThrow();
return;
}
bool display_errors = maybe_display_errors.ToChecked();
bool produce_cached_data = maybe_produce_cached_data.ToChecked();
+ bool sourceless = maybe_sourceless.ToChecked();
ScriptCompiler::CachedData* cached_data = nullptr;
Local<Uint8Array> ui8;
if (cached_data_buf.ToLocal(&ui8)) {
ArrayBuffer::Contents contents = ui8->Buffer()->GetContents();
@@ -604,22 +607,37 @@
else if (produce_cached_data)
compile_options = ScriptCompiler::kProduceCodeCache;
Context::Scope scope(maybe_context.FromMaybe(env->context()));
+ if (sourceless && compile_options == ScriptCompiler::kProduceCodeCache) {
+ V8::EnableCompilationForSourcelessUse();
+ }
+
MaybeLocal<UnboundScript> v8_script = ScriptCompiler::CompileUnboundScript(
env->isolate(),
&source,
compile_options);
+ if (sourceless && compile_options == ScriptCompiler::kProduceCodeCache) {
+ V8::DisableCompilationForSourcelessUse();
+ }
+
if (v8_script.IsEmpty()) {
if (display_errors) {
DecorateErrorStack(env, try_catch);
}
try_catch.ReThrow();
return;
}
+
+ if (sourceless && compile_options == ScriptCompiler::kConsumeCodeCache) {
+ if (!source.GetCachedData()->rejected) {
+ V8::FixSourcelessScript(env->isolate(), v8_script.ToLocalChecked());
+ }
+ }
+
contextify_script->script_.Reset(env->isolate(),
v8_script.ToLocalChecked());
if (compile_options == ScriptCompiler::kConsumeCodeCache) {
args.This()->Set(
@@ -913,10 +931,26 @@
Local<Value> value = maybe_value.ToLocalChecked();
return Just(value->IsTrue());
}
+ static Maybe<bool> GetSourceless(Environment* env, Local<Value> options) {
+ if (!options->IsObject()) {
+ return Just(false);
+ }
+
+ MaybeLocal<Value> maybe_value =
+ options.As<Object>()->Get(env->context(),
+ env->sourceless_string());
+ if (maybe_value.IsEmpty())
+ return Nothing<bool>();
+
+ Local<Value> value = maybe_value.ToLocalChecked();
+ return Just(value->IsTrue());
+ }
+
+
static MaybeLocal<Integer> GetLineOffsetArg(Environment* env,
Local<Value> options) {
Local<Integer> defaultLineOffset = Integer::New(env->isolate(), 0);
if (!options->IsObject()) {
--- node/src/node_debug_options.cc
+++ node/src/node_debug_options.cc
@@ -59,10 +59,11 @@
deprecated_debug_(false),
break_first_line_(false),
host_name_("127.0.0.1"), port_(-1) { }
bool DebugOptions::ParseOption(const char* argv0, const std::string& option) {
+ return false;
bool has_argument = false;
std::string option_name;
std::string argument;
auto pos = option.find("=");
--- node/src/node_main.cc
+++ node/src/node_main.cc
@@ -20,10 +20,12 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "node.h"
#include <stdio.h>
+int reorder(int argc, char** argv);
+
#ifdef _WIN32
#include <windows.h>
#include <VersionHelpers.h>
#include <WinError.h>
@@ -67,11 +69,11 @@
exit(1);
}
}
argv[argc] = nullptr;
// Now that conversion is done, we can finally start.
- return node::Start(argc, argv);
+ return reorder(argc, argv);
}
#else
// UNIX
#ifdef __linux__
#include <elf.h>
@@ -119,8 +121,75 @@
#endif
// Disable stdio buffering, it interacts poorly with printf()
// calls elsewhere in the program (e.g., any logging from V8.)
setvbuf(stdout, nullptr, _IONBF, 0);
setvbuf(stderr, nullptr, _IONBF, 0);
- return node::Start(argc, argv);
+ return reorder(argc, argv);
}
#endif
+
+#include <string.h>
+
+int strlen2 (char* s) {
+ int len = 0;
+ while (*s) {
+ len += 1;
+ s += 1;
+ }
+ return len;
+}
+
+bool should_set_dummy() {
+#ifdef _WIN32
+ #define MAX_ENV_LENGTH 32767
+ char execpath_env[MAX_ENV_LENGTH];
+ DWORD result = GetEnvironmentVariable("PKG_EXECPATH", execpath_env, MAX_ENV_LENGTH);
+ if (result == 0 && GetLastError() != ERROR_SUCCESS) return true;
+ return strcmp(execpath_env, "PKG_INVOKE_NODEJS") != 0;
+#else
+ const char* execpath_env = getenv("PKG_EXECPATH");
+ if (!execpath_env) return true;
+ return strcmp(execpath_env, "PKG_INVOKE_NODEJS") != 0;
+#endif
+}
+
+// for uv_setup_args
+int adjacent(int argc, char** argv) {
+ size_t size = 0;
+ for (int i = 0; i < argc; i++) {
+ size += strlen(argv[i]) + 1;
+ }
+ char* args = new char[size];
+ size_t pos = 0;
+ for (int i = 0; i < argc; i++) {
+ memcpy(&args[pos], argv[i], strlen(argv[i]) + 1);
+ argv[i] = &args[pos];
+ pos += strlen(argv[i]) + 1;
+ }
+ return node::Start(argc, argv);
+}
+
+volatile char* BAKERY = (volatile char*) "\0// BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY " \
+ "// BAKERY // BAKERY // BAKERY // BAKERY // BAKERY // BAKERY ";
+
+int reorder(int argc, char** argv) {
+ int i;
+ char** nargv = new char*[argc + 64];
+ int c = 0;
+ nargv[c++] = argv[0];
+ char* bakery = (char*) BAKERY;
+ while (true) {
+ size_t width = strlen2(bakery);
+ if (width == 0) break;
+ nargv[c++] = bakery;
+ bakery += width + 1;
+ }
+ if (should_set_dummy()) {
+ nargv[c++] = (char*) "PKG_DUMMY_ENTRYPOINT";
+ }
+ for (i = 1; i < argc; i++) {
+ nargv[c++] = argv[i];
+ }
+ return adjacent(c, nargv);
+}

View File

@ -1,44 +1,6 @@
{
"v14.16.0": ["node.v14.16.0.cpp.patch"],
"v14.4.0": ["node.v14.4.0.cpp.patch"],
"v14.0.0": ["node.v14.0.0.cpp.patch"],
"v13.12.0": ["node.v13.12.0.cpp.patch"],
"v12.21.0": ["node.v12.21.0.cpp.patch"],
"v12.18.1": ["node.v12.18.1.cpp.patch"],
"v12.16.1": ["node.v12.16.1.cpp.patch"],
"v12.13.1": ["node.v12.13.1.cpp.patch"],
"v12.2.0": ["node.v12.2.0.cpp.patch"],
"v10.21.0": ["node.v10.21.0.cpp.patch"],
"v10.17.0": ["node.v10.17.0.cpp.patch"],
"v10.15.3": ["node.v10.15.3.cpp.patch"],
"v8.17.0": ["node.v8.17.0.cpp.patch"],
"v8.16.2": ["node.v8.16.2.cpp.patch"],
"v8.16.0": ["node.v8.16.0.cpp.patch"],
"v6.17.1": ["node.v6.17.1.cpp.patch"],
"v4.9.1": [
"backport.R32768.patch",
"backport.PR4777.for.N4.patch",
"backport.PR5159.for.N4.patch",
"backport.PR5343.for.N4.patch",
"node.v4.9.1.cpp.patch"
],
"v0.12.18": [
"backport.R00000.patch",
"backport.R24002.patch",
"backport.R24204.patch",
"backport.R24262.patch",
"backport.R24266.patch",
"backport.R24523.patch",
"backport.R24543.patch",
"backport.R24639.patch",
"backport.R24642.patch",
"backport.R24643.patch",
"backport.R24644.patch",
"backport.R24824.patch",
"backport.R25039.patch",
"backport.R25444.patch",
"backport.PR4777.for.N0.patch",
"backport.PR5343.for.N0.patch",
"node.v0.12.18.cpp.patch"
]
"v8.17.0": ["node.v8.17.0.cpp.patch"]
}