Remove JS natives support, step 1

The natives blob is deprecated and will be removed in the next
release.

This commit does two things, 1. it disables the v8_extra_library_files
gn argument which will make building natives_blob.bin through gn
impossible; 2. it marks API functions associated with the natives blob
as V8_DEPRECATE_SOON.

Embedders should remove any uses of SetNativesDataBlob and replace all
calls to

 InitializeExternalStartupData(const char*, const char*)

with the new function

 InitializeExternalStartupDataFromFile(const char*)

Step 2 is to mark API functions as V8_DEPRECATED.
Step 3, in the next V8 release, is to remove these functions and all
other natives support in V8.

Bug: v8:7624
Change-Id: I745e96c60204a9b94d9240be65dd59bb9bdd0699
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1824944
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: Yang Guo <yangguo@chromium.org>
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Auto-Submit: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#64080}
This commit is contained in:
Jakob Gruber 2019-10-02 09:28:07 +02:00 committed by Commit Bot
parent 65d05bef39
commit 28a9dc2b81
10 changed files with 38 additions and 290 deletions

View File

@ -156,9 +156,7 @@ declare_args() {
# List of extra files to snapshot. They will be snapshotted in order so
# if files export symbols used by later files, they should go first.
#
# This default is used by cctests. Projects using V8 will want to override.
v8_extra_library_files = [ "//test/cctest/test-extra.js" ]
v8_extra_library_files = []
v8_enable_gdbjit =
((v8_current_cpu == "x86" || v8_current_cpu == "x64") &&
@ -258,6 +256,10 @@ assert(
assert(v8_use_snapshot || !v8_enable_shared_ro_heap,
"Shared read-only heap requires snapshot")
assert(v8_extra_library_files == [],
"v8_extra_library_files is no longer supported. Consider implementing " +
"custom API in C++ instead.")
v8_random_seed = "314159265"
v8_toolset_for_shell = "host"

View File

@ -9004,7 +9004,9 @@ class V8_EXPORT V8 {
* handled entirely on the embedders' side.
* - The call will abort if the data is invalid.
*/
static void SetNativesDataBlob(StartupData* startup_blob);
V8_DEPRECATE_SOON(
"The natives blob is deprecated (https://crbug.com/v8/7624).",
static void SetNativesDataBlob(StartupData* startup_blob));
static void SetSnapshotDataBlob(StartupData* startup_blob);
/** Set the callback to invoke in case of Dcheck failures. */
@ -9100,8 +9102,12 @@ class V8_EXPORT V8 {
* not perform any file IO.
*/
static void InitializeExternalStartupData(const char* directory_path);
static void InitializeExternalStartupData(const char* natives_blob,
const char* snapshot_blob);
V8_DEPRECATE_SOON(
"The natives blob is deprecated (https://crbug.com/v8/7624).",
static void InitializeExternalStartupData(const char* natives_blob,
const char* snapshot_blob));
static void InitializeExternalStartupDataFromFile(const char* snapshot_blob);
/**
* Sets the v8::Platform to use. This should be invoked before V8 is
* initialized.

View File

@ -5723,6 +5723,11 @@ void v8::V8::InitializeExternalStartupData(const char* natives_blob,
i::InitializeExternalStartupData(natives_blob, snapshot_blob);
}
// static
void v8::V8::InitializeExternalStartupDataFromFile(const char* snapshot_blob) {
i::InitializeExternalStartupDataFromFile(snapshot_blob);
}
const char* v8::V8::GetVersion() { return i::Version::GetVersion(); }
template <typename ObjectType>

View File

@ -3001,9 +3001,6 @@ bool Shell::SetOptions(int argc, char* argv[]) {
options.icu_locale = argv[i] + 13;
argv[i] = nullptr;
#ifdef V8_USE_EXTERNAL_STARTUP_DATA
} else if (strncmp(argv[i], "--natives_blob=", 15) == 0) {
options.natives_blob = argv[i] + 15;
argv[i] = nullptr;
} else if (strncmp(argv[i], "--snapshot_blob=", 16) == 0) {
options.snapshot_blob = argv[i] + 16;
argv[i] = nullptr;
@ -3592,9 +3589,8 @@ int Shell::Main(int argc, char* argv[]) {
}
v8::V8::InitializePlatform(g_platform.get());
v8::V8::Initialize();
if (options.natives_blob || options.snapshot_blob) {
v8::V8::InitializeExternalStartupData(options.natives_blob,
options.snapshot_blob);
if (options.snapshot_blob) {
v8::V8::InitializeExternalStartupDataFromFile(options.snapshot_blob);
} else {
v8::V8::InitializeExternalStartupData(argv[0]);
}

View File

@ -285,7 +285,6 @@ class ShellOptions {
SourceGroup* isolate_sources = nullptr;
const char* icu_data_file = nullptr;
const char* icu_locale = nullptr;
const char* natives_blob = nullptr;
const char* snapshot_blob = nullptr;
bool trace_enabled = false;
const char* trace_path = nullptr;

View File

@ -38,6 +38,10 @@ void FreeStartupData() {
DeleteStartupData(&g_snapshot);
}
// TODO(jgruber): Rename to FreeStartupData once natives support has been
// removed (https://crbug.com/v8/7624).
void FreeStartupDataSnapshotOnly() { DeleteStartupData(&g_snapshot); }
void Load(const char* blob_file, v8::StartupData* startup_data,
void (*setter_fn)(v8::StartupData*)) {
ClearStartupData(startup_data);
@ -67,7 +71,7 @@ void Load(const char* blob_file, v8::StartupData* startup_data,
}
void LoadFromFiles(const char* natives_blob, const char* snapshot_blob) {
Load(natives_blob, &g_natives, v8::V8::SetNativesDataBlob);
Load(natives_blob, &g_natives, i::V8::SetNativesBlob);
Load(snapshot_blob, &g_snapshot, v8::V8::SetSnapshotDataBlob);
atexit(&FreeStartupData);
@ -101,5 +105,12 @@ void InitializeExternalStartupData(const char* natives_blob,
#endif // V8_USE_EXTERNAL_STARTUP_DATA
}
void InitializeExternalStartupDataFromFile(const char* snapshot_blob) {
#ifdef V8_USE_EXTERNAL_STARTUP_DATA
Load(snapshot_blob, &g_snapshot, v8::V8::SetSnapshotDataBlob);
atexit(&FreeStartupDataSnapshotOnly);
#endif // V8_USE_EXTERNAL_STARTUP_DATA
}
} // namespace internal
} // namespace v8

View File

@ -21,6 +21,7 @@ void InitializeExternalStartupData(const char* directory_path);
void InitializeExternalStartupData(const char* natives_blob,
const char* snapshot_blob);
void InitializeExternalStartupDataFromFile(const char* snapshot_blob);
} // namespace internal
} // namespace v8

View File

@ -24478,280 +24478,6 @@ TEST(SealHandleScopeNested) {
}
}
static void ExtrasBindingTestRuntimeFunction(
const v8::FunctionCallbackInfo<v8::Value>& args) {
CHECK_EQ(
3,
args[0]->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust());
args.GetReturnValue().Set(v8_num(7));
}
TEST(ExtrasFunctionSource) {
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope handle_scope(isolate);
LocalContext env;
v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
// Functions defined in extras do not expose source code.
auto func = binding->Get(env.local(), v8_str("testFunctionToString"))
.ToLocalChecked()
.As<v8::Function>();
auto undefined = v8::Undefined(isolate);
auto result = func->Call(env.local(), undefined, 0, {})
.ToLocalChecked()
.As<v8::String>();
CHECK(result->StrictEquals(v8_str("function foo() { [native code] }")));
// Functions defined in extras do not show up in the stack trace.
auto wrapper = binding->Get(env.local(), v8_str("testStackTrace"))
.ToLocalChecked()
.As<v8::Function>();
CHECK(env->Global()->Set(env.local(), v8_str("wrapper"), wrapper).FromJust());
ExpectString(
"function f(x) { return wrapper(x) }"
"function g() { return new Error().stack; }"
"f(g)",
"Error\n"
" at g (<anonymous>:1:58)\n"
" at f (<anonymous>:1:24)\n"
" at <anonymous>:1:78");
}
TEST(ExtrasBindingObject) {
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope handle_scope(isolate);
LocalContext env;
// standalone.gypi ensures we include the test-extra.js file, which should
// export the tested functions.
v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
auto func = binding->Get(env.local(), v8_str("testExtraShouldReturnFive"))
.ToLocalChecked()
.As<v8::Function>();
auto undefined = v8::Undefined(isolate);
auto result = func->Call(env.local(), undefined, 0, {})
.ToLocalChecked()
.As<v8::Number>();
CHECK_EQ(5, result->Int32Value(env.local()).FromJust());
v8::Local<v8::FunctionTemplate> runtimeFunction =
v8::FunctionTemplate::New(isolate, ExtrasBindingTestRuntimeFunction);
binding->Set(env.local(), v8_str("runtime"),
runtimeFunction->GetFunction(env.local()).ToLocalChecked())
.FromJust();
func = binding->Get(env.local(), v8_str("testExtraShouldCallToRuntime"))
.ToLocalChecked()
.As<v8::Function>();
result = func->Call(env.local(), undefined, 0, {})
.ToLocalChecked()
.As<v8::Number>();
CHECK_EQ(7, result->Int32Value(env.local()).FromJust());
}
TEST(ExtrasCreatePromise) {
i::FLAG_allow_natives_syntax = true;
LocalContext context;
v8::Isolate* isolate = context->GetIsolate();
v8::HandleScope handle_scope(isolate);
LocalContext env;
v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
auto func = binding->Get(env.local(), v8_str("testCreatePromise"))
.ToLocalChecked()
.As<v8::Function>();
CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
auto promise = CompileRun(
"%PrepareFunctionForOptimization(func);\n"
"func();\n"
"func();\n"
"%OptimizeFunctionOnNextCall(func);\n"
"func()\n")
.As<v8::Promise>();
CHECK_EQ(v8::Promise::kPending, promise->State());
}
TEST(ExtrasCreatePromiseWithParent) {
i::FLAG_allow_natives_syntax = true;
LocalContext context;
v8::Isolate* isolate = context->GetIsolate();
v8::HandleScope handle_scope(isolate);
LocalContext env;
v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
auto func = binding->Get(env.local(), v8_str("testCreatePromiseWithParent"))
.ToLocalChecked()
.As<v8::Function>();
CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
auto promise = CompileRun(
"var parent = new Promise((a, b) => {});\n"
"%PrepareFunctionForOptimization(func);\n"
"func(parent);\n"
"func(parent);\n"
"%OptimizeFunctionOnNextCall(func);\n"
"func(parent)\n")
.As<v8::Promise>();
CHECK_EQ(v8::Promise::kPending, promise->State());
}
TEST(ExtrasRejectPromise) {
i::FLAG_allow_natives_syntax = true;
LocalContext context;
v8::Isolate* isolate = context->GetIsolate();
v8::HandleScope handle_scope(isolate);
LocalContext env;
v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
auto func = binding->Get(env.local(), v8_str("testRejectPromise"))
.ToLocalChecked()
.As<v8::Function>();
CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
auto rejected_promise = CompileRun(
"function newPromise() {\n"
" return new Promise((a, b) => {});\n"
"}\n"
"%PrepareFunctionForOptimization(func);\n"
"func(newPromise(), 1);\n"
"func(newPromise(), 1);\n"
"%OptimizeFunctionOnNextCall(func);\n"
"var promise = newPromise();\n"
"func(promise, 1);\n"
"promise;\n")
.As<v8::Promise>();
CHECK_EQ(v8::Promise::kRejected, rejected_promise->State());
CHECK_EQ(1, rejected_promise->Result()->Int32Value(env.local()).FromJust());
}
TEST(ExtrasResolvePromise) {
i::FLAG_allow_natives_syntax = true;
LocalContext context;
v8::Isolate* isolate = context->GetIsolate();
v8::HandleScope handle_scope(isolate);
LocalContext env;
v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
auto func = binding->Get(env.local(), v8_str("testResolvePromise"))
.ToLocalChecked()
.As<v8::Function>();
CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
auto pending_promise = CompileRun(
"function newPromise() {\n"
" return new Promise((a, b) => {});\n"
"}\n"
"%PrepareFunctionForOptimization(func);\n"
"func(newPromise(), newPromise());\n"
"func(newPromise(), newPromise());\n"
"%OptimizeFunctionOnNextCall(func);\n"
"var promise = newPromise();\n"
"func(promise, newPromise());\n"
"promise;\n")
.As<v8::Promise>();
CHECK_EQ(v8::Promise::kPending, pending_promise->State());
auto fulfilled_promise = CompileRun(
"function newPromise() {\n"
" return new Promise((a, b) => {});\n"
"}\n"
"%PrepareFunctionForOptimization(func);\n"
"func(newPromise(), 1);\n"
"func(newPromise(), 1);\n"
"%OptimizeFunctionOnNextCall(func);\n"
"var promise = newPromise();\n"
"func(promise, 1);\n"
"promise;\n")
.As<v8::Promise>();
CHECK_EQ(v8::Promise::kFulfilled, fulfilled_promise->State());
CHECK_EQ(1, fulfilled_promise->Result()->Int32Value(env.local()).FromJust());
}
TEST(ExtrasUtilsObject) {
LocalContext context;
v8::Isolate* isolate = context->GetIsolate();
v8::HandleScope handle_scope(isolate);
LocalContext env;
v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
auto func = binding->Get(env.local(), v8_str("testExtraCanUseUtils"))
.ToLocalChecked()
.As<v8::Function>();
auto undefined = v8::Undefined(isolate);
auto result = func->Call(env.local(), undefined, 0, {})
.ToLocalChecked()
.As<v8::Object>();
auto private_symbol = result->Get(env.local(), v8_str("privateSymbol"))
.ToLocalChecked()
.As<v8::Symbol>();
i::Handle<i::Symbol> ips = v8::Utils::OpenHandle(*private_symbol);
CHECK(ips->IsPrivate());
CompileRun("var result = 0; function store(x) { result = x; }");
auto store = CompileRun("store").As<v8::Function>();
auto fulfilled_promise = result->Get(env.local(), v8_str("fulfilledPromise"))
.ToLocalChecked()
.As<v8::Promise>();
fulfilled_promise->Then(env.local(), store).ToLocalChecked();
isolate->RunMicrotasks();
CHECK_EQ(1, CompileRun("result")->Int32Value(env.local()).FromJust());
auto fulfilled_promise_2 =
result->Get(env.local(), v8_str("fulfilledPromise2"))
.ToLocalChecked()
.As<v8::Promise>();
fulfilled_promise_2->Then(env.local(), store).ToLocalChecked();
isolate->RunMicrotasks();
CHECK_EQ(2, CompileRun("result")->Int32Value(env.local()).FromJust());
auto rejected_promise = result->Get(env.local(), v8_str("rejectedPromise"))
.ToLocalChecked()
.As<v8::Promise>();
rejected_promise->Catch(env.local(), store).ToLocalChecked();
isolate->RunMicrotasks();
CHECK_EQ(3, CompileRun("result")->Int32Value(env.local()).FromJust());
auto rejected_but_handled_promise =
result->Get(env.local(), v8_str("rejectedButHandledPromise"))
.ToLocalChecked()
.As<v8::Promise>();
CHECK(rejected_but_handled_promise->HasHandler());
auto promise_states = result->Get(env.local(), v8_str("promiseStates"))
.ToLocalChecked()
.As<v8::String>();
String::Utf8Value promise_states_string(isolate, promise_states);
CHECK_EQ(0, strcmp(*promise_states_string, "pending fulfilled rejected"));
auto promise_is_promise = result->Get(env.local(), v8_str("promiseIsPromise"))
.ToLocalChecked()
.As<v8::Boolean>();
CHECK_EQ(true, promise_is_promise->Value());
auto thenable_is_promise =
result->Get(env.local(), v8_str("thenableIsPromise"))
.ToLocalChecked()
.As<v8::Boolean>();
CHECK_EQ(false, thenable_is_promise->Value());
auto uncurry_this = result->Get(env.local(), v8_str("uncurryThis"))
.ToLocalChecked()
.As<v8::Boolean>();
CHECK_EQ(true, uncurry_this->Value());
}
TEST(Map) {
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope handle_scope(isolate);

View File

@ -4509,7 +4509,7 @@ UNINITIALIZED_TEST(LoadedAtStartupScripts) {
}
}
CHECK_EQ(count_by_type[i::Script::TYPE_NATIVE], 0);
CHECK_EQ(count_by_type[i::Script::TYPE_EXTENSION], 2);
CHECK_EQ(count_by_type[i::Script::TYPE_EXTENSION], 1);
CHECK_EQ(count_by_type[i::Script::TYPE_NORMAL], 1);
CHECK_EQ(count_by_type[i::Script::TYPE_WASM], 0);
CHECK_EQ(count_by_type[i::Script::TYPE_INSPECTOR], 0);

View File

@ -265,7 +265,9 @@ def BuildMetadata(sources, source_bytes, native_type):
metadata = {
"builtin_count": len(sources.modules),
"sources_declaration": SOURCES_DECLARATION % ToCArray(source_bytes),
"sources_declaration":
SOURCES_DECLARATION % ToCArray(
source_bytes if len(source_bytes) != 0 else "\0"),
"total_length": total_length,
"get_index_cases": "".join(get_index_cases),
"get_script_source_cases": "".join(get_script_source_cases),