Chromium Code Reviews| Index: src/bootstrapper.cc |
| diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc |
| index f3dd682871b74964a4afd0860aed1381c49c1944..084596161efa728c5335110daefdbaaed9adb523 100644 |
| --- a/src/bootstrapper.cc |
| +++ b/src/bootstrapper.cc |
| @@ -217,7 +217,7 @@ class Genesis BASE_EMBEDDED { |
| HARMONY_SHIPPING(DECLARE_FEATURE_INITIALIZATION) |
| #undef DECLARE_FEATURE_INITIALIZATION |
| - Handle<JSFunction> InstallInternalArray(Handle<JSBuiltinsObject> builtins, |
| + Handle<JSFunction> InstallInternalArray(Handle<JSObject> target, |
| const char* name, |
| ElementsKind elements_kind); |
| bool InstallNatives(); |
| @@ -233,6 +233,8 @@ class Genesis BASE_EMBEDDED { |
| void InstallJSFunctionResultCaches(); |
| void InitializeNormalizedMapCaches(); |
| + void RemoveExportObjects(); |
| + |
| enum ExtensionTraversalState { |
| UNVISITED, VISITED, INSTALLED |
| }; |
| @@ -307,19 +309,15 @@ class Genesis BASE_EMBEDDED { |
| FunctionMode function_mode); |
| void SetStrongFunctionInstanceDescriptor(Handle<Map> map); |
| - static bool CompileBuiltin(Isolate* isolate, int index); |
| + static bool CompileBuiltin(Isolate* isolate, int index, |
| + Handle<JSObject> shared); |
| static bool CompileExperimentalBuiltin(Isolate* isolate, int index); |
| static bool CompileExtraBuiltin(Isolate* isolate, int index); |
| - static bool CompileNative(Isolate* isolate, |
| - Vector<const char> name, |
| - Handle<String> source); |
| - static bool CompileScriptCached(Isolate* isolate, |
| - Vector<const char> name, |
| - Handle<String> source, |
| - SourceCodeCache* cache, |
| - v8::Extension* extension, |
| - Handle<Context> top_context, |
| - bool use_runtime_context); |
| + static bool CompileNative(Isolate* isolate, Vector<const char> name, |
| + Handle<String> source, int argc, |
| + Handle<Object> argv[]); |
| + |
| + static bool CompileExtension(Isolate* isolate, v8::Extension* extension); |
| Isolate* isolate_; |
| Handle<Context> result_; |
| @@ -1441,34 +1439,45 @@ void Genesis::InitializeExperimentalGlobal() { |
| } |
| -bool Genesis::CompileBuiltin(Isolate* isolate, int index) { |
| +bool Genesis::CompileBuiltin(Isolate* isolate, int index, |
| + Handle<JSObject> shared) { |
| Vector<const char> name = Natives::GetScriptName(index); |
| Handle<String> source_code = |
| isolate->bootstrapper()->SourceLookup<Natives>(index); |
| - return CompileNative(isolate, name, source_code); |
| + Handle<Object> global = isolate->global_object(); |
| + Handle<Object> exports = isolate->builtin_exports_object(); |
| + Handle<Object> args[] = {global, shared, exports}; |
| + return CompileNative(isolate, name, source_code, arraysize(args), args); |
| } |
| bool Genesis::CompileExperimentalBuiltin(Isolate* isolate, int index) { |
| + HandleScope scope(isolate); |
| Vector<const char> name = ExperimentalNatives::GetScriptName(index); |
| Handle<String> source_code = |
| isolate->bootstrapper()->SourceLookup<ExperimentalNatives>(index); |
| - return CompileNative(isolate, name, source_code); |
| + Handle<Object> global = isolate->global_object(); |
| + Handle<Object> exports = isolate->builtin_exports_object(); |
| + Handle<Object> args[] = {global, exports}; |
| + return CompileNative(isolate, name, source_code, arraysize(args), args); |
| } |
| bool Genesis::CompileExtraBuiltin(Isolate* isolate, int index) { |
| + HandleScope scope(isolate); |
| Vector<const char> name = ExtraNatives::GetScriptName(index); |
| Handle<String> source_code = |
| isolate->bootstrapper()->SourceLookup<ExtraNatives>(index); |
| - return CompileNative(isolate, name, source_code); |
| + Handle<Object> global = isolate->global_object(); |
| + Handle<Object> exports = isolate->builtin_exports_object(); |
| + Handle<Object> args[] = {global, exports}; |
| + return CompileNative(isolate, name, source_code, arraysize(args), args); |
| } |
| -bool Genesis::CompileNative(Isolate* isolate, |
| - Vector<const char> name, |
| - Handle<String> source) { |
| - HandleScope scope(isolate); |
| +bool Genesis::CompileNative(Isolate* isolate, Vector<const char> name, |
| + Handle<String> source, int argc, |
| + Handle<Object> argv[]) { |
| SuppressDebug compiling_natives(isolate->debug()); |
| // During genesis, the boilerplate for stack overflow won't work until the |
| // environment has been at least partially initialized. Add a stack check |
| @@ -1476,78 +1485,72 @@ bool Genesis::CompileNative(Isolate* isolate, |
| StackLimitCheck check(isolate); |
| if (check.HasOverflowed()) return false; |
| - bool result = CompileScriptCached(isolate, |
| - name, |
| - source, |
| - NULL, |
| - NULL, |
| - Handle<Context>(isolate->context()), |
| - true); |
| - DCHECK(isolate->has_pending_exception() != result); |
| - if (!result) isolate->clear_pending_exception(); |
| - return result; |
| + Handle<Context> context(isolate->context()); |
| + |
| + Handle<String> script_name = |
| + isolate->factory()->NewStringFromUtf8(name).ToHandleChecked(); |
| + Handle<SharedFunctionInfo> function_info = Compiler::CompileScript( |
| + source, script_name, 0, 0, false, false, Handle<Object>(), context, NULL, |
| + NULL, ScriptCompiler::kNoCompileOptions, NATIVES_CODE, false); |
| + |
| + DCHECK(context->IsNativeContext()); |
| + |
| + Handle<Context> runtime_context(context->runtime_context()); |
| + Handle<JSBuiltinsObject> receiver(context->builtins()); |
| + Handle<JSFunction> fun = |
| + isolate->factory()->NewFunctionFromSharedFunctionInfo(function_info, |
| + runtime_context); |
| + |
| + // For non-extension scripts, run script to get the function wrapper. |
| + Handle<Object> wrapper; |
| + if (!Execution::Call(isolate, fun, receiver, 0, NULL).ToHandle(&wrapper)) { |
| + return false; |
| + } |
| + // Then run the function wrapper. |
| + return !Execution::Call(isolate, Handle<JSFunction>::cast(wrapper), receiver, |
| + argc, argv).is_null(); |
| } |
| -bool Genesis::CompileScriptCached(Isolate* isolate, |
| - Vector<const char> name, |
| - Handle<String> source, |
| - SourceCodeCache* cache, |
| - v8::Extension* extension, |
| - Handle<Context> top_context, |
| - bool use_runtime_context) { |
| +bool Genesis::CompileExtension(Isolate* isolate, v8::Extension* extension) { |
| Factory* factory = isolate->factory(); |
| HandleScope scope(isolate); |
| Handle<SharedFunctionInfo> function_info; |
| + Handle<String> source = |
| + isolate->factory() |
| + ->NewExternalStringFromOneByte(extension->source()) |
| + .ToHandleChecked(); |
| + DCHECK(source->IsOneByteRepresentation()); |
| + |
| // If we can't find the function in the cache, we compile a new |
| // function and insert it into the cache. |
| - if (cache == NULL || !cache->Lookup(name, &function_info)) { |
| - DCHECK(source->IsOneByteRepresentation()); |
| + Vector<const char> name = CStrVector(extension->name()); |
| + SourceCodeCache* cache = isolate->bootstrapper()->extensions_cache(); |
| + Handle<Context> context(isolate->context()); |
| + DCHECK(context->IsNativeContext()); |
| + |
| + if (!cache->Lookup(name, &function_info)) { |
| Handle<String> script_name = |
| factory->NewStringFromUtf8(name).ToHandleChecked(); |
| function_info = Compiler::CompileScript( |
| - source, script_name, 0, 0, false, false, Handle<Object>(), top_context, |
| - extension, NULL, ScriptCompiler::kNoCompileOptions, |
| - use_runtime_context ? NATIVES_CODE : NOT_NATIVES_CODE, false); |
| + source, script_name, 0, 0, false, false, Handle<Object>(), context, |
| + extension, NULL, ScriptCompiler::kNoCompileOptions, NOT_NATIVES_CODE, |
| + false); |
| if (function_info.is_null()) return false; |
| - if (cache != NULL) cache->Add(name, function_info); |
| + cache->Add(name, function_info); |
| } |
| // Set up the function context. Conceptually, we should clone the |
| // function before overwriting the context but since we're in a |
| // single-threaded environment it is not strictly necessary. |
| - DCHECK(top_context->IsNativeContext()); |
| - Handle<Context> context = |
| - Handle<Context>(use_runtime_context |
| - ? Handle<Context>(top_context->runtime_context()) |
| - : top_context); |
| Handle<JSFunction> fun = |
| factory->NewFunctionFromSharedFunctionInfo(function_info, context); |
| // Call function using either the runtime object or the global |
| // object as the receiver. Provide no parameters. |
| - Handle<Object> receiver = |
| - Handle<Object>(use_runtime_context |
| - ? top_context->builtins() |
| - : top_context->global_object(), |
| - isolate); |
| - MaybeHandle<Object> result; |
| - if (extension == NULL) { |
| - // For non-extension scripts, run script to get the function wrapper. |
| - Handle<Object> wrapper; |
| - if (!Execution::Call(isolate, fun, receiver, 0, NULL).ToHandle(&wrapper)) { |
| - return false; |
| - } |
| - // Then run the function wrapper. |
| - Handle<Object> global_obj(top_context->global_object(), isolate); |
| - Handle<Object> args[] = {global_obj}; |
| - result = Execution::Call(isolate, Handle<JSFunction>::cast(wrapper), |
| - receiver, arraysize(args), args); |
| - } else { |
| - result = Execution::Call(isolate, fun, receiver, 0, NULL); |
| - } |
| - return !result.is_null(); |
| + Handle<Object> receiver = isolate->global_object(); |
| + return !Execution::Call(isolate, fun, receiver, 0, NULL).is_null(); |
| } |
| @@ -1818,10 +1821,9 @@ void Genesis::InitializeGlobal_harmony_tostring() { |
| } |
| -Handle<JSFunction> Genesis::InstallInternalArray( |
| - Handle<JSBuiltinsObject> builtins, |
| - const char* name, |
| - ElementsKind elements_kind) { |
| +Handle<JSFunction> Genesis::InstallInternalArray(Handle<JSObject> target, |
| + const char* name, |
| + ElementsKind elements_kind) { |
| // --- I n t e r n a l A r r a y --- |
| // An array constructor on the builtins object that works like |
| // the public Array constructor, except that its prototype |
| @@ -1830,9 +1832,9 @@ Handle<JSFunction> Genesis::InstallInternalArray( |
| // must not be leaked to user code. |
| Handle<JSObject> prototype = |
| factory()->NewJSObject(isolate()->object_function(), TENURED); |
| - Handle<JSFunction> array_function = InstallFunction( |
| - builtins, name, JS_ARRAY_TYPE, JSArray::kSize, |
| - prototype, Builtins::kInternalArrayCode); |
| + Handle<JSFunction> array_function = |
| + InstallFunction(target, name, JS_ARRAY_TYPE, JSArray::kSize, prototype, |
| + Builtins::kInternalArrayCode); |
| InternalArrayConstructorStub internal_array_constructor_stub(isolate()); |
| Handle<Code> code = internal_array_constructor_stub.GetCode(); |
| @@ -1910,6 +1912,27 @@ bool Genesis::InstallNatives() { |
| native_context()->set_runtime_context(*context); |
| + // Set up shared object to set up cross references between native scripts. |
| + // "shared" is used for cross references between native scripts that are part |
| + // of the snapshot. "builtin_exports" is used for experimental natives. |
| + Handle<JSObject> shared = |
| + factory()->NewJSObject(isolate()->object_function()); |
| + JSObject::NormalizeProperties(shared, CLEAR_INOBJECT_PROPERTIES, 16, |
| + "container to share between native scripts"); |
| + Handle<JSObject> builtin_exports = |
| + factory()->NewJSObject(isolate()->object_function()); |
| + JSObject::NormalizeProperties(builtin_exports, CLEAR_INOBJECT_PROPERTIES, 16, |
| + "container to export to experimental natives"); |
| + native_context()->set_builtin_exports_object(*builtin_exports); |
| + |
| + if (FLAG_expose_natives_as != nullptr) { |
| + Handle<String> shared_key = factory()->NewStringFromAsciiChecked("shared"); |
| + Handle<String> builtin_exports_key = |
| + factory()->NewStringFromAsciiChecked("builtin_exports"); |
| + JSObject::AddProperty(builtins, shared_key, shared, NONE); |
| + JSObject::AddProperty(builtins, builtin_exports_key, builtin_exports, NONE); |
| + } |
| + |
| { // -- S c r i p t |
| // Builtin functions for Script. |
| Handle<JSFunction> script_fun = InstallFunction( |
| @@ -2082,13 +2105,13 @@ bool Genesis::InstallNatives() { |
| // through a common bottleneck that would make the SMI_ONLY -> FAST_ELEMENT |
| // transition easy to trap. Moreover, they rarely are smi-only. |
| { |
| - Handle<JSFunction> array_function = |
| - InstallInternalArray(builtins, "InternalArray", FAST_HOLEY_ELEMENTS); |
| + HandleScope scope(isolate()); |
| + Handle<JSObject> builtin_exports = |
| + Handle<JSObject>::cast(isolate()->builtin_exports_object()); |
| + Handle<JSFunction> array_function = InstallInternalArray( |
| + builtin_exports, "InternalArray", FAST_HOLEY_ELEMENTS); |
| native_context()->set_internal_array_function(*array_function); |
| - } |
| - |
| - { |
| - InstallInternalArray(builtins, "InternalPackedArray", FAST_ELEMENTS); |
| + InstallInternalArray(builtin_exports, "InternalPackedArray", FAST_ELEMENTS); |
| } |
| { // -- S e t I t e r a t o r |
| @@ -2181,13 +2204,15 @@ bool Genesis::InstallNatives() { |
| #undef INSTALL_PUBLIC_SYMBOL |
| } |
| - // Install natives. |
| + // Install natives. Everything exported to experimental natives are also |
|
Jakob Kummerow
2015/05/11 15:25:26
nit: "everything [...] is"
|
| + // shared to regular natives. |
| + TransferNamedProperties(builtin_exports, shared); |
| int i = Natives::GetDebuggerCount(); |
| - if (!CompileBuiltin(isolate(), i)) return false; |
| + if (!CompileBuiltin(isolate(), i, shared)) return false; |
| if (!InstallJSBuiltins(builtins)) return false; |
| for (++i; i < Natives::GetBuiltinsCount(); ++i) { |
| - if (!CompileBuiltin(isolate(), i)) return false; |
| + if (!CompileBuiltin(isolate(), i, shared)) return false; |
| } |
| InstallNativeFunctions(); |
| @@ -2391,6 +2416,11 @@ bool Genesis::InstallExtraNatives() { |
| } |
| +void Genesis::RemoveExportObjects() { |
| + native_context_->set_builtin_exports_object(Smi::FromInt(0)); |
| +} |
| + |
| + |
| static void InstallBuiltinFunctionId(Handle<JSObject> holder, |
| const char* function_name, |
| BuiltinFunctionId id) { |
| @@ -2653,17 +2683,7 @@ bool Genesis::InstallExtension(Isolate* isolate, |
| } |
| } |
| // We do not expect this to throw an exception. Change this if it does. |
| - Handle<String> source_code = |
| - isolate->factory() |
| - ->NewExternalStringFromOneByte(extension->source()) |
| - .ToHandleChecked(); |
| - bool result = CompileScriptCached(isolate, |
| - CStrVector(extension->name()), |
| - source_code, |
| - isolate->bootstrapper()->extensions_cache(), |
| - extension, |
| - Handle<Context>(isolate->context()), |
| - false); |
| + bool result = CompileExtension(isolate, extension); |
| DCHECK(isolate->has_pending_exception() != result); |
| if (!result) { |
| // We print out the name of the extension that fail to install. |
| @@ -2914,8 +2934,10 @@ Genesis::Genesis(Isolate* isolate, |
| // We can only de-serialize a context if the isolate was initialized from |
| // a snapshot. Otherwise we have to build the context from scratch. |
| + // Also create a context from scratch to expose natives, if required by flag. |
| Handle<FixedArray> outdated_contexts; |
| - if (!isolate->initialized_from_snapshot() || |
| + if (FLAG_expose_natives_as != nullptr || |
| + !isolate->initialized_from_snapshot() || |
| !Snapshot::NewContextFromSnapshot(isolate, global_proxy, |
| &outdated_contexts) |
| .ToHandle(&native_context_)) { |
| @@ -2971,6 +2993,9 @@ Genesis::Genesis(Isolate* isolate, |
| InitializeExperimentalGlobal(); |
| if (!InstallExperimentalNatives()) return; |
| if (!InstallExtraNatives()) return; |
| + |
| + // Exports are no longer needed. |
| + RemoveExportObjects(); |
| } |
| // The serializer cannot serialize typed arrays. Reset those typed arrays |