// Copyright 2014 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. #include "src/bootstrapper.h" #include "src/accessors.h" #include "src/api-natives.h" #include "src/base/ieee754.h" #include "src/code-stubs.h" #include "src/compiler.h" #include "src/extensions/externalize-string-extension.h" #include "src/extensions/free-buffer-extension.h" #include "src/extensions/gc-extension.h" #include "src/extensions/ignition-statistics-extension.h" #include "src/extensions/statistics-extension.h" #include "src/extensions/trigger-failure-extension.h" #include "src/heap/heap.h" #include "src/isolate-inl.h" #include "src/snapshot/natives.h" #include "src/snapshot/snapshot.h" #include "src/wasm/wasm-js.h" namespace v8 { namespace internal { Bootstrapper::Bootstrapper(Isolate* isolate) : isolate_(isolate), nesting_(0), extensions_cache_(Script::TYPE_EXTENSION) {} template Handle Bootstrapper::SourceLookup(int index) { DCHECK(0 <= index && index < Source::GetBuiltinsCount()); Heap* heap = isolate_->heap(); if (Source::GetSourceCache(heap)->get(index)->IsUndefined(isolate_)) { // We can use external strings for the natives. Vector source = Source::GetScriptSource(index); NativesExternalStringResource* resource = new NativesExternalStringResource(source.start(), source.length()); Handle source_code = isolate_->factory()->NewNativeSourceString(resource); // Mark this external string with a special map. DCHECK(source_code->is_short()); Source::GetSourceCache(heap)->set(index, *source_code); } Handle cached_source(Source::GetSourceCache(heap)->get(index), isolate_); return Handle::cast(cached_source); } template Handle Bootstrapper::SourceLookup(int index); template Handle Bootstrapper::SourceLookup( int index); template Handle Bootstrapper::SourceLookup( int index); template Handle Bootstrapper::SourceLookup(int index); void Bootstrapper::Initialize(bool create_heap_objects) { extensions_cache_.Initialize(isolate_, create_heap_objects); } static const char* GCFunctionName() { bool flag_given = FLAG_expose_gc_as != NULL && strlen(FLAG_expose_gc_as) != 0; return flag_given ? FLAG_expose_gc_as : "gc"; } v8::Extension* Bootstrapper::free_buffer_extension_ = NULL; v8::Extension* Bootstrapper::gc_extension_ = NULL; v8::Extension* Bootstrapper::externalize_string_extension_ = NULL; v8::Extension* Bootstrapper::statistics_extension_ = NULL; v8::Extension* Bootstrapper::trigger_failure_extension_ = NULL; v8::Extension* Bootstrapper::ignition_statistics_extension_ = NULL; void Bootstrapper::InitializeOncePerProcess() { free_buffer_extension_ = new FreeBufferExtension; v8::RegisterExtension(free_buffer_extension_); gc_extension_ = new GCExtension(GCFunctionName()); v8::RegisterExtension(gc_extension_); externalize_string_extension_ = new ExternalizeStringExtension; v8::RegisterExtension(externalize_string_extension_); statistics_extension_ = new StatisticsExtension; v8::RegisterExtension(statistics_extension_); trigger_failure_extension_ = new TriggerFailureExtension; v8::RegisterExtension(trigger_failure_extension_); ignition_statistics_extension_ = new IgnitionStatisticsExtension; v8::RegisterExtension(ignition_statistics_extension_); } void Bootstrapper::TearDownExtensions() { delete free_buffer_extension_; free_buffer_extension_ = NULL; delete gc_extension_; gc_extension_ = NULL; delete externalize_string_extension_; externalize_string_extension_ = NULL; delete statistics_extension_; statistics_extension_ = NULL; delete trigger_failure_extension_; trigger_failure_extension_ = NULL; delete ignition_statistics_extension_; ignition_statistics_extension_ = NULL; } void DeleteNativeSources(Object* maybe_array) { if (maybe_array->IsFixedArray()) { FixedArray* array = FixedArray::cast(maybe_array); Isolate* isolate = array->GetIsolate(); for (int i = 0; i < array->length(); i++) { Object* natives_source = array->get(i); if (!natives_source->IsUndefined(isolate)) { const NativesExternalStringResource* resource = reinterpret_cast( ExternalOneByteString::cast(natives_source)->resource()); delete resource; } } } } void Bootstrapper::TearDown() { DeleteNativeSources(Natives::GetSourceCache(isolate_->heap())); DeleteNativeSources(ExperimentalNatives::GetSourceCache(isolate_->heap())); DeleteNativeSources(ExtraNatives::GetSourceCache(isolate_->heap())); DeleteNativeSources( ExperimentalExtraNatives::GetSourceCache(isolate_->heap())); extensions_cache_.Initialize(isolate_, false); // Yes, symmetrical } class Genesis BASE_EMBEDDED { public: Genesis(Isolate* isolate, MaybeHandle maybe_global_proxy, v8::Local global_proxy_template, v8::ExtensionConfiguration* extensions, size_t context_snapshot_index, GlobalContextType context_type); Genesis(Isolate* isolate, MaybeHandle maybe_global_proxy, v8::Local global_proxy_template); ~Genesis() { } Isolate* isolate() const { return isolate_; } Factory* factory() const { return isolate_->factory(); } Heap* heap() const { return isolate_->heap(); } Handle result() { return result_; } Handle global_proxy() { return global_proxy_; } private: Handle native_context() { return native_context_; } // Creates some basic objects. Used for creating a context from scratch. void CreateRoots(); // Creates the empty function. Used for creating a context from scratch. Handle CreateEmptyFunction(Isolate* isolate); // Creates the ThrowTypeError function. ECMA 5th Ed. 13.2.3 Handle GetRestrictedFunctionPropertiesThrower(); Handle GetStrictArgumentsPoisonFunction(); Handle GetThrowTypeErrorIntrinsic(Builtins::Name builtin_name); void CreateStrictModeFunctionMaps(Handle empty); void CreateIteratorMaps(Handle empty); void CreateAsyncFunctionMaps(Handle empty); void CreateJSProxyMaps(); // Make the "arguments" and "caller" properties throw a TypeError on access. void AddRestrictedFunctionProperties(Handle empty); // Creates the global objects using the global proxy and the template passed // in through the API. We call this regardless of whether we are building a // context from scratch or using a deserialized one from the partial snapshot // but in the latter case we don't use the objects it produces directly, as // we have to used the deserialized ones that are linked together with the // rest of the context snapshot. Handle CreateNewGlobals( v8::Local global_proxy_template, Handle global_proxy); // Hooks the given global proxy into the context. If the context was created // by deserialization then this will unhook the global proxy that was // deserialized, leaving the GC to pick it up. void HookUpGlobalProxy(Handle global_object, Handle global_proxy); // Similarly, we want to use the global that has been created by the templates // passed through the API. The global from the snapshot is detached from the // other objects in the snapshot. void HookUpGlobalObject(Handle global_object); // The native context has a ScriptContextTable that store declarative bindings // made in script scopes. Add a "this" binding to that table pointing to the // global proxy. void InstallGlobalThisBinding(); // New context initialization. Used for creating a context from scratch. void InitializeGlobal(Handle global_object, Handle empty_function, GlobalContextType context_type); void InitializeExperimentalGlobal(); // Depending on the situation, expose and/or get rid of the utils object. void ConfigureUtilsObject(GlobalContextType context_type); #define DECLARE_FEATURE_INITIALIZATION(id, descr) \ void InitializeGlobal_##id(); HARMONY_INPROGRESS(DECLARE_FEATURE_INITIALIZATION) HARMONY_STAGED(DECLARE_FEATURE_INITIALIZATION) HARMONY_SHIPPING(DECLARE_FEATURE_INITIALIZATION) #undef DECLARE_FEATURE_INITIALIZATION Handle InstallArrayBuffer(Handle target, const char* name, Builtins::Name call, BuiltinFunctionId id); Handle InstallInternalArray(Handle target, const char* name, ElementsKind elements_kind); bool InstallNatives(GlobalContextType context_type); void InstallTypedArray(const char* name, ElementsKind elements_kind, Handle* fun); bool InstallExperimentalNatives(); bool InstallExtraNatives(); bool InstallExperimentalExtraNatives(); bool InstallDebuggerNatives(); void InstallBuiltinFunctionIds(); void InstallExperimentalBuiltinFunctionIds(); void InitializeNormalizedMapCaches(); enum ExtensionTraversalState { UNVISITED, VISITED, INSTALLED }; class ExtensionStates { public: ExtensionStates(); ExtensionTraversalState get_state(RegisteredExtension* extension); void set_state(RegisteredExtension* extension, ExtensionTraversalState state); private: base::HashMap map_; DISALLOW_COPY_AND_ASSIGN(ExtensionStates); }; // Used both for deserialized and from-scratch contexts to add the extensions // provided. static bool InstallExtensions(Handle native_context, v8::ExtensionConfiguration* extensions); static bool InstallAutoExtensions(Isolate* isolate, ExtensionStates* extension_states); static bool InstallRequestedExtensions(Isolate* isolate, v8::ExtensionConfiguration* extensions, ExtensionStates* extension_states); static bool InstallExtension(Isolate* isolate, const char* name, ExtensionStates* extension_states); static bool InstallExtension(Isolate* isolate, v8::RegisteredExtension* current, ExtensionStates* extension_states); static bool InstallSpecialObjects(Handle native_context); bool ConfigureApiObject(Handle object, Handle object_template); bool ConfigureGlobalObjects( v8::Local global_proxy_template); // Migrates all properties from the 'from' object to the 'to' // object and overrides the prototype in 'to' with the one from // 'from'. void TransferObject(Handle from, Handle to); void TransferNamedProperties(Handle from, Handle to); void TransferIndexedProperties(Handle from, Handle to); void MakeFunctionInstancePrototypeWritable(); void SetStrictFunctionInstanceDescriptor(Handle map, FunctionMode function_mode); static bool CallUtilsFunction(Isolate* isolate, const char* name); static bool CompileExtension(Isolate* isolate, v8::Extension* extension); Isolate* isolate_; Handle result_; Handle native_context_; Handle global_proxy_; // Function maps. Function maps are created initially with a read only // prototype for the processing of JS builtins. Later the function maps are // replaced in order to make prototype writable. These are the final, writable // prototype, maps. Handle sloppy_function_map_writable_prototype_; Handle strict_function_map_writable_prototype_; Handle strict_poison_function_; Handle restricted_function_properties_thrower_; BootstrapperActive active_; friend class Bootstrapper; }; void Bootstrapper::Iterate(ObjectVisitor* v) { extensions_cache_.Iterate(v); v->Synchronize(VisitorSynchronization::kExtensions); } Handle Bootstrapper::CreateEnvironment( MaybeHandle maybe_global_proxy, v8::Local global_proxy_template, v8::ExtensionConfiguration* extensions, size_t context_snapshot_index, GlobalContextType context_type) { HandleScope scope(isolate_); Genesis genesis(isolate_, maybe_global_proxy, global_proxy_template, extensions, context_snapshot_index, context_type); Handle env = genesis.result(); if (env.is_null() || !InstallExtensions(env, extensions)) { return Handle(); } return scope.CloseAndEscape(env); } Handle Bootstrapper::NewRemoteContext( MaybeHandle maybe_global_proxy, v8::Local global_proxy_template) { HandleScope scope(isolate_); Genesis genesis(isolate_, maybe_global_proxy, global_proxy_template); Handle global_proxy = genesis.global_proxy(); if (global_proxy.is_null()) return Handle(); return scope.CloseAndEscape(global_proxy); } void Bootstrapper::DetachGlobal(Handle env) { env->GetIsolate()->counters()->errors_thrown_per_context()->AddSample( env->GetErrorsThrown()); Factory* factory = env->GetIsolate()->factory(); Handle global_proxy(JSGlobalProxy::cast(env->global_proxy())); global_proxy->set_native_context(*factory->null_value()); JSObject::ForceSetPrototype(global_proxy, factory->null_value()); global_proxy->map()->SetConstructor(*factory->null_value()); if (FLAG_track_detached_contexts) { env->GetIsolate()->AddDetachedContext(env); } } namespace { void InstallFunction(Handle target, Handle property_name, Handle function, Handle function_name, PropertyAttributes attributes = DONT_ENUM) { JSObject::AddProperty(target, property_name, function, attributes); if (target->IsJSGlobalObject()) { function->shared()->set_instance_class_name(*function_name); } function->shared()->set_native(true); } void InstallFunction(Handle target, Handle function, Handle name, PropertyAttributes attributes = DONT_ENUM) { Handle name_string = Name::ToFunctionName(name).ToHandleChecked(); InstallFunction(target, name, function, name_string, attributes); } Handle InstallGetter(Handle target, Handle property_name, Handle getter, PropertyAttributes attributes = DONT_ENUM) { Handle setter = target->GetIsolate()->factory()->undefined_value(); JSObject::DefineAccessor(target, property_name, getter, setter, attributes) .Check(); getter->shared()->set_native(true); return getter; } Handle CreateFunction(Isolate* isolate, Handle name, InstanceType type, int instance_size, MaybeHandle maybe_prototype, Builtins::Name call, bool strict_function_map = false) { Factory* factory = isolate->factory(); Handle call_code(isolate->builtins()->builtin(call)); Handle prototype; return maybe_prototype.ToHandle(&prototype) ? factory->NewFunction(name, call_code, prototype, type, instance_size, strict_function_map) : factory->NewFunctionWithoutPrototype(name, call_code, strict_function_map); } Handle InstallFunction(Handle target, Handle name, InstanceType type, int instance_size, MaybeHandle maybe_prototype, Builtins::Name call, PropertyAttributes attributes, bool strict_function_map = false) { Handle name_string = Name::ToFunctionName(name).ToHandleChecked(); Handle function = CreateFunction(target->GetIsolate(), name_string, type, instance_size, maybe_prototype, call, strict_function_map); InstallFunction(target, name, function, name_string, attributes); return function; } Handle InstallFunction(Handle target, const char* name, InstanceType type, int instance_size, MaybeHandle maybe_prototype, Builtins::Name call, bool strict_function_map = false) { Factory* const factory = target->GetIsolate()->factory(); PropertyAttributes attributes = DONT_ENUM; return InstallFunction(target, factory->InternalizeUtf8String(name), type, instance_size, maybe_prototype, call, attributes, strict_function_map); } Handle SimpleCreateFunction(Isolate* isolate, Handle name, Builtins::Name call, int len, bool adapt) { Handle fun = CreateFunction(isolate, name, JS_OBJECT_TYPE, JSObject::kHeaderSize, MaybeHandle(), call); if (adapt) { fun->shared()->set_internal_formal_parameter_count(len); } else { fun->shared()->DontAdaptArguments(); } fun->shared()->set_length(len); return fun; } Handle SimpleInstallFunction(Handle base, Handle name, Builtins::Name call, int len, bool adapt, PropertyAttributes attrs = DONT_ENUM) { Handle fun = SimpleCreateFunction(base->GetIsolate(), name, call, len, adapt); InstallFunction(base, fun, name, attrs); return fun; } Handle SimpleInstallFunction(Handle base, const char* name, Builtins::Name call, int len, bool adapt, PropertyAttributes attrs = DONT_ENUM) { Factory* const factory = base->GetIsolate()->factory(); return SimpleInstallFunction(base, factory->InternalizeUtf8String(name), call, len, adapt, attrs); } Handle SimpleInstallFunction(Handle base, const char* name, Builtins::Name call, int len, bool adapt, BuiltinFunctionId id) { Handle fun = SimpleInstallFunction(base, name, call, len, adapt); fun->shared()->set_builtin_function_id(id); return fun; } Handle SimpleInstallGetter(Handle base, Handle name, Builtins::Name call, bool adapt) { Isolate* const isolate = base->GetIsolate(); Handle fun_name = Name::ToFunctionName(name, isolate->factory()->get_string()) .ToHandleChecked(); Handle fun = SimpleCreateFunction(isolate, fun_name, call, 0, adapt); InstallGetter(base, name, fun); return fun; } Handle SimpleInstallGetter(Handle base, Handle name, Builtins::Name call, bool adapt, BuiltinFunctionId id) { Handle fun = SimpleInstallGetter(base, name, call, adapt); fun->shared()->set_builtin_function_id(id); return fun; } } // namespace Handle Genesis::CreateEmptyFunction(Isolate* isolate) { // Allocate the map for function instances. Maps are allocated first and their // prototypes patched later, once empty function is created. // Functions with this map will not have a 'prototype' property, and // can not be used as constructors. Handle function_without_prototype_map = factory()->CreateSloppyFunctionMap(FUNCTION_WITHOUT_PROTOTYPE); native_context()->set_sloppy_function_without_prototype_map( *function_without_prototype_map); // Allocate the function map. This map is temporary, used only for processing // of builtins. // Later the map is replaced with writable prototype map, allocated below. Handle function_map = factory()->CreateSloppyFunctionMap(FUNCTION_WITH_READONLY_PROTOTYPE); native_context()->set_sloppy_function_map(*function_map); native_context()->set_sloppy_function_with_readonly_prototype_map( *function_map); // The final map for functions. Writeable prototype. // This map is installed in MakeFunctionInstancePrototypeWritable. sloppy_function_map_writable_prototype_ = factory()->CreateSloppyFunctionMap(FUNCTION_WITH_WRITEABLE_PROTOTYPE); Factory* factory = isolate->factory(); Handle object_name = factory->Object_string(); Handle object_function_prototype; { // --- O b j e c t --- Handle object_fun = factory->NewFunction(object_name); int unused = JSObject::kInitialGlobalObjectUnusedPropertiesCount; int instance_size = JSObject::kHeaderSize + kPointerSize * unused; Handle object_function_map = factory->NewMap(JS_OBJECT_TYPE, instance_size); object_function_map->SetInObjectProperties(unused); JSFunction::SetInitialMap(object_fun, object_function_map, isolate->factory()->null_value()); object_function_map->set_unused_property_fields(unused); native_context()->set_object_function(*object_fun); // Allocate a new prototype for the object function. object_function_prototype = factory->NewJSObject(isolate->object_function(), TENURED); Handle map = Map::Copy(handle(object_function_prototype->map()), "EmptyObjectPrototype"); map->set_is_prototype_map(true); // Ban re-setting Object.prototype.__proto__ to prevent Proxy security bug map->set_immutable_proto(true); object_function_prototype->set_map(*map); native_context()->set_initial_object_prototype(*object_function_prototype); // For bootstrapping set the array prototype to be the same as the object // prototype, otherwise the missing initial_array_prototype will cause // assertions during startup. native_context()->set_initial_array_prototype(*object_function_prototype); Accessors::FunctionSetPrototype(object_fun, object_function_prototype) .Assert(); } // Allocate the empty function as the prototype for function - ES6 19.2.3 Handle code(isolate->builtins()->EmptyFunction()); Handle empty_function = factory->NewFunctionWithoutPrototype(factory->empty_string(), code); // Allocate the function map first and then patch the prototype later Handle empty_function_map = factory->CreateSloppyFunctionMap(FUNCTION_WITHOUT_PROTOTYPE); DCHECK(!empty_function_map->is_dictionary_map()); Map::SetPrototype(empty_function_map, object_function_prototype); empty_function_map->set_is_prototype_map(true); empty_function->set_map(*empty_function_map); // --- E m p t y --- Handle source = factory->NewStringFromStaticChars("() {}"); Handle