Add the concept of a V8 extras exports object

Exposed to the extras as extrasExports (on the builtins object), on
which they can put things that should be accessible from C++. Exposed
to C++ through the V8 API as v8::Context::GetExtrasExportsObject().

Adding a test (in test-api.cc) required adding a simple extra,
test-extra.js, which we build into the standalone builds.

R=yangguo@chromium.org, jochen@chromium.org
BUG=

Review URL: https://codereview.chromium.org/1128113006

Cr-Commit-Position: refs/heads/master@{#28317}
This commit is contained in:
domenic 2015-05-08 05:06:35 -07:00 committed by Commit bot
parent 297bb0ca8b
commit ad547cea05
10 changed files with 73 additions and 2 deletions

View File

@ -100,6 +100,9 @@
'msan%': '<(msan)',
'tsan%': '<(tsan)',
# Add a simple extra solely for the purpose of the cctests
'v8_extra_library_files': ['../test/cctest/test-extra.js'],
# .gyp files or targets should set v8_code to 1 if they build V8 specific
# code, as opposed to external code. This variable is used to control such
# things as the set of warnings to enable, and whether warnings are treated

View File

@ -6370,6 +6370,12 @@ class V8_EXPORT Context {
*/
V8_INLINE Local<Value> GetEmbedderData(int index);
/**
* Gets the exports object used by V8 extras. Extra natives get a reference
* to this object and can use it to export functionality.
*/
Local<Object> GetExtrasExportsObject();
/**
* Sets the embedder data with the given index, growing the data as
* needed. Note that index 0 currently has a special meaning for Chrome's

View File

@ -5492,6 +5492,14 @@ void Context::DetachGlobal() {
}
Local<v8::Object> Context::GetExtrasExportsObject() {
i::Handle<i::Context> context = Utils::OpenHandle(this);
i::Isolate* isolate = context->GetIsolate();
i::Handle<i::JSObject> exports(context->extras_exports_object(), isolate);
return Utils::ToLocal(exports);
}
void Context::AllowCodeGenerationFromStrings(bool allow) {
i::Handle<i::Context> context = Utils::OpenHandle(this);
i::Isolate* isolate = context->GetIsolate();

View File

@ -201,6 +201,7 @@ class Genesis BASE_EMBEDDED {
void InitializeGlobal(Handle<GlobalObject> global_object,
Handle<JSFunction> empty_function);
void InitializeExperimentalGlobal();
void InitializeExtrasExportsObject();
// Installs the contents of the native .js files on the global objects.
// Used for creating a context from scratch.
void InstallNativeFunctions();
@ -1441,6 +1442,20 @@ void Genesis::InitializeExperimentalGlobal() {
}
void Genesis::InitializeExtrasExportsObject() {
Handle<JSObject> exports =
factory()->NewJSObject(isolate()->object_function(), TENURED);
native_context()->set_extras_exports_object(*exports);
Handle<JSBuiltinsObject> builtins(native_context()->builtins());
Handle<String> exports_string =
factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("extrasExports"));
Runtime::SetObjectProperty(isolate(), builtins, exports_string, exports,
STRICT).Assert();
}
bool Genesis::CompileBuiltin(Isolate* isolate, int index) {
Vector<const char> name = Natives::GetScriptName(index);
Handle<String> source_code =
@ -2962,6 +2977,7 @@ Genesis::Genesis(Isolate* isolate,
// them after they have already been deserialized would also fail.
if (!isolate->serializer_enabled()) {
InitializeExperimentalGlobal();
InitializeExtrasExportsObject();
if (!InstallExperimentalNatives()) return;
if (!InstallExtraNatives()) return;
}

View File

@ -185,7 +185,8 @@ enum BindingFlags {
V(MAP_ITERATOR_MAP_INDEX, Map, map_iterator_map) \
V(SET_ITERATOR_MAP_INDEX, Map, set_iterator_map) \
V(ARRAY_VALUES_ITERATOR_INDEX, JSFunction, array_values_iterator) \
V(SCRIPT_CONTEXT_TABLE_INDEX, ScriptContextTable, script_context_table)
V(SCRIPT_CONTEXT_TABLE_INDEX, ScriptContextTable, script_context_table) \
V(EXTRAS_EXPORTS_OBJECT_INDEX, JSObject, extras_exports_object)
// A table of all script contexts. Every loaded top-level script with top-level
@ -422,6 +423,7 @@ class Context: public FixedArray {
SCRIPT_CONTEXT_TABLE_INDEX,
MAP_CACHE_INDEX,
TO_LENGTH_FUN_INDEX,
EXTRAS_EXPORTS_OBJECT_INDEX,
// Properties from here are treated as weak references by the full GC.
// Scavenge treats them as strong references.

View File

@ -364,6 +364,12 @@ RUNTIME_FUNCTION(Runtime_NativeScriptsCount) {
}
RUNTIME_FUNCTION(Runtime_NativeExtrasCount) {
DCHECK(args.length() == 0);
return Smi::FromInt(ExtraNatives::GetBuiltinsCount());
}
// Returns V8 version as a string.
RUNTIME_FUNCTION(Runtime_GetV8Version) {
HandleScope scope(isolate);

View File

@ -592,6 +592,7 @@ namespace internal {
F(Abort, 1, 1) \
F(AbortJS, 1, 1) \
F(NativeScriptsCount, 0, 1) \
F(NativeExtrasCount, 0, 1) \
F(GetV8Version, 0, 1) \
F(DisassembleFunction, 1, 1) \
F(TraceEnter, 0, 1) \

View File

@ -21029,3 +21029,21 @@ TEST(SealHandleScopeNested) {
USE(obj);
}
}
TEST(ExtrasExportsObject) {
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope handle_scope(isolate);
LocalContext env;
// standalone.gypi ensures we include the test-extra.js file, which should
// add the testExtraShouldReturnFive export
v8::Local<v8::Object> exports = env->GetExtrasExportsObject();
auto func =
exports->Get(v8_str("testExtraShouldReturnFive")).As<v8::Function>();
auto undefined = v8::Undefined(isolate);
auto result = func->Call(undefined, 0, {}).As<v8::Number>();
CHECK(result->Value() == 5.0);
}

11
test/cctest/test-extra.js Normal file
View File

@ -0,0 +1,11 @@
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
(function () {
'use strict';
extrasExports.testExtraShouldReturnFive = function () {
return 5;
};
})();

View File

@ -66,7 +66,7 @@ for (i = 0; i < scripts.length; i++) {
}
// This has to be updated if the number of native scripts change.
assertEquals(%NativeScriptsCount(), named_native_count);
assertEquals(%NativeScriptsCount() + %NativeExtrasCount(), named_native_count);
// Only the 'gc' extension is loaded.
assertEquals(1, extension_count);
// This script and mjsunit.js has been loaded. If using d8, d8 loads