// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following // disclaimer in the documentation and/or other materials provided // with the distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "v8.h" #include "accessors.h" #include "api.h" #include "bootstrapper.h" #include "compiler.h" #include "debug.h" #include "execution.h" #include "global-handles.h" #include "isolate-inl.h" #include "macro-assembler.h" #include "natives.h" #include "objects-visiting.h" #include "platform.h" #include "snapshot.h" #include "extensions/externalize-string-extension.h" #include "extensions/gc-extension.h" #include "extensions/statistics-extension.h" namespace v8 { namespace internal { NativesExternalStringResource::NativesExternalStringResource( Bootstrapper* bootstrapper, const char* source, size_t length) : data_(source), length_(length) { if (bootstrapper->delete_these_non_arrays_on_tear_down_ == NULL) { bootstrapper->delete_these_non_arrays_on_tear_down_ = new List(2); } // The resources are small objects and we only make a fixed number of // them, but let's clean them up on exit for neatness. bootstrapper->delete_these_non_arrays_on_tear_down_-> Add(reinterpret_cast(this)); } Bootstrapper::Bootstrapper() : nesting_(0), extensions_cache_(Script::TYPE_EXTENSION), delete_these_non_arrays_on_tear_down_(NULL), delete_these_arrays_on_tear_down_(NULL) { } Handle Bootstrapper::NativesSourceLookup(int index) { ASSERT(0 <= index && index < Natives::GetBuiltinsCount()); Isolate* isolate = Isolate::Current(); Factory* factory = isolate->factory(); Heap* heap = isolate->heap(); if (heap->natives_source_cache()->get(index)->IsUndefined()) { // We can use external strings for the natives. Vector source = Natives::GetRawScriptSource(index); NativesExternalStringResource* resource = new NativesExternalStringResource(this, source.start(), source.length()); Handle source_code = factory->NewExternalStringFromAscii(resource); heap->natives_source_cache()->set(index, *source_code); } Handle cached_source(heap->natives_source_cache()->get(index)); return Handle::cast(cached_source); } void Bootstrapper::Initialize(bool create_heap_objects) { extensions_cache_.Initialize(create_heap_objects); GCExtension::Register(); ExternalizeStringExtension::Register(); StatisticsExtension::Register(); } char* Bootstrapper::AllocateAutoDeletedArray(int bytes) { char* memory = new char[bytes]; if (memory != NULL) { if (delete_these_arrays_on_tear_down_ == NULL) { delete_these_arrays_on_tear_down_ = new List(2); } delete_these_arrays_on_tear_down_->Add(memory); } return memory; } void Bootstrapper::TearDown() { if (delete_these_non_arrays_on_tear_down_ != NULL) { int len = delete_these_non_arrays_on_tear_down_->length(); ASSERT(len < 20); // Don't use this mechanism for unbounded allocations. for (int i = 0; i < len; i++) { delete delete_these_non_arrays_on_tear_down_->at(i); delete_these_non_arrays_on_tear_down_->at(i) = NULL; } delete delete_these_non_arrays_on_tear_down_; delete_these_non_arrays_on_tear_down_ = NULL; } if (delete_these_arrays_on_tear_down_ != NULL) { int len = delete_these_arrays_on_tear_down_->length(); ASSERT(len < 1000); // Don't use this mechanism for unbounded allocations. for (int i = 0; i < len; i++) { delete[] delete_these_arrays_on_tear_down_->at(i); delete_these_arrays_on_tear_down_->at(i) = NULL; } delete delete_these_arrays_on_tear_down_; delete_these_arrays_on_tear_down_ = NULL; } extensions_cache_.Initialize(false); // Yes, symmetrical } class Genesis BASE_EMBEDDED { public: Genesis(Isolate* isolate, Handle global_object, v8::Handle global_template, v8::ExtensionConfiguration* extensions); ~Genesis() { } Handle result() { return result_; } Genesis* previous() { return previous_; } Isolate* isolate() const { return isolate_; } Factory* factory() const { return isolate_->factory(); } Heap* heap() const { return isolate_->heap(); } private: Handle native_context_; Isolate* isolate_; // There may be more than one active genesis object: When GC is // triggered during environment creation there may be weak handle // processing callbacks which may create new environments. Genesis* previous_; 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 GetThrowTypeErrorFunction(); void CreateStrictModeFunctionMaps(Handle empty); // Make the "arguments" and "caller" properties throw a TypeError on access. void PoisonArgumentsAndCaller(Handle map); // Creates the global objects using the global 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::Handle global_template, Handle global_object, Handle* global_proxy_out); // 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 inner_global, Handle global_proxy); // Similarly, we want to use the inner global that has been created by the // templates passed through the API. The inner global from the snapshot is // detached from the other objects in the snapshot. void HookUpInnerGlobal(Handle inner_global); // New context initialization. Used for creating a context from scratch. bool InitializeGlobal(Handle inner_global, Handle empty_function); void InitializeExperimentalGlobal(); // Installs the contents of the native .js files on the global objects. // Used for creating a context from scratch. void InstallNativeFunctions(); void InstallExperimentalNativeFunctions(); bool InstallNatives(); bool InstallExperimentalNatives(); void InstallBuiltinFunctionIds(); void InstallJSFunctionResultCaches(); void InitializeNormalizedMapCaches(); enum ExtensionTraversalState { UNVISITED, VISITED, INSTALLED }; class ExtensionStates { public: ExtensionStates(); ExtensionTraversalState get_state(RegisteredExtension* extension); void set_state(RegisteredExtension* extension, ExtensionTraversalState state); private: 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 InstallExtension(const char* name, ExtensionStates* extension_states); static bool InstallExtension(v8::RegisteredExtension* current, ExtensionStates* extension_states); static void InstallSpecialObjects(Handle native_context); bool InstallJSBuiltins(Handle builtins); bool ConfigureApiObject(Handle object, Handle object_template); bool ConfigureGlobalObjects(v8::Handle global_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); enum PrototypePropertyMode { DONT_ADD_PROTOTYPE, ADD_READONLY_PROTOTYPE, ADD_WRITEABLE_PROTOTYPE }; Handle CreateFunctionMap(PrototypePropertyMode prototype_mode); void SetFunctionInstanceDescriptor(Handle map, PrototypePropertyMode prototypeMode); void MakeFunctionInstancePrototypeWritable(); Handle CreateStrictModeFunctionMap( PrototypePropertyMode prototype_mode, Handle empty_function); void SetStrictFunctionInstanceDescriptor(Handle map, PrototypePropertyMode propertyMode); static bool CompileBuiltin(Isolate* isolate, int index); static bool CompileExperimentalBuiltin(Isolate* isolate, int index); static bool CompileNative(Vector name, Handle source); static bool CompileScriptCached(Vector name, Handle source, SourceCodeCache* cache, v8::Extension* extension, Handle top_context, bool use_runtime_context); Handle result_; // Function instance maps. Function literal maps are created initially with // a read only prototype for the processing of JS builtins. Later the function // instance maps are replaced in order to make prototype writable. // These are the final, writable prototype, maps. Handle function_instance_map_writable_prototype_; Handle strict_mode_function_instance_map_writable_prototype_; Handle throw_type_error_function; BootstrapperActive active_; friend class Bootstrapper; }; void Bootstrapper::Iterate(ObjectVisitor* v) { extensions_cache_.Iterate(v); v->Synchronize(VisitorSynchronization::kExtensions); } Handle Bootstrapper::CreateEnvironment( Isolate* isolate, Handle global_object, v8::Handle global_template, v8::ExtensionConfiguration* extensions) { HandleScope scope; Handle env; Genesis genesis(isolate, global_object, global_template, extensions); env = genesis.result(); if (!env.is_null()) { if (InstallExtensions(env, extensions)) { return env; } } return Handle(); } static void SetObjectPrototype(Handle object, Handle proto) { // object.__proto__ = proto; Factory* factory = object->GetIsolate()->factory(); Handle old_to_map = Handle(object->map()); Handle new_to_map = factory->CopyMap(old_to_map); new_to_map->set_prototype(*proto); object->set_map(*new_to_map); } void Bootstrapper::DetachGlobal(Handle env) { Factory* factory = env->GetIsolate()->factory(); Handle global_proxy(JSGlobalProxy::cast(env->global_proxy())); global_proxy->set_native_context(*factory->null_value()); SetObjectPrototype(global_proxy, factory->null_value()); env->set_global_proxy(env->global_object()); env->global_object()->set_global_receiver(env->global_object()); } void Bootstrapper::ReattachGlobal(Handle env, Handle global_proxy) { env->global_object()->set_global_receiver(*global_proxy); env->set_global_proxy(*global_proxy); SetObjectPrototype(global_proxy, Handle(env->global_object())); global_proxy->set_native_context(*env); } static Handle InstallFunction(Handle target, const char* name, InstanceType type, int instance_size, Handle prototype, Builtins::Name call, bool is_ecma_native) { Isolate* isolate = target->GetIsolate(); Factory* factory = isolate->factory(); Handle symbol = factory->LookupUtf8Symbol(name); Handle call_code = Handle(isolate->builtins()->builtin(call)); Handle function = prototype.is_null() ? factory->NewFunctionWithoutPrototype(symbol, call_code) : factory->NewFunctionWithPrototype(symbol, type, instance_size, prototype, call_code, is_ecma_native); PropertyAttributes attributes; if (target->IsJSBuiltinsObject()) { attributes = static_cast(DONT_ENUM | DONT_DELETE | READ_ONLY); } else { attributes = DONT_ENUM; } CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes( target, symbol, function, attributes)); if (is_ecma_native) { function->shared()->set_instance_class_name(*symbol); } function->shared()->set_native(true); return function; } void Genesis::SetFunctionInstanceDescriptor( Handle map, PrototypePropertyMode prototypeMode) { int size = (prototypeMode == DONT_ADD_PROTOTYPE) ? 4 : 5; Handle descriptors(factory()->NewDescriptorArray(0, size)); DescriptorArray::WhitenessWitness witness(*descriptors); Handle length(factory()->NewForeign(&Accessors::FunctionLength)); Handle name(factory()->NewForeign(&Accessors::FunctionName)); Handle args(factory()->NewForeign(&Accessors::FunctionArguments)); Handle caller(factory()->NewForeign(&Accessors::FunctionCaller)); Handle prototype; if (prototypeMode != DONT_ADD_PROTOTYPE) { prototype = factory()->NewForeign(&Accessors::FunctionPrototype); } PropertyAttributes attribs = static_cast( DONT_ENUM | DONT_DELETE | READ_ONLY); map->set_instance_descriptors(*descriptors); { // Add length. CallbacksDescriptor d(*factory()->length_symbol(), *length, attribs); map->AppendDescriptor(&d, witness); } { // Add name. CallbacksDescriptor d(*factory()->name_symbol(), *name, attribs); map->AppendDescriptor(&d, witness); } { // Add arguments. CallbacksDescriptor d(*factory()->arguments_symbol(), *args, attribs); map->AppendDescriptor(&d, witness); } { // Add caller. CallbacksDescriptor d(*factory()->caller_symbol(), *caller, attribs); map->AppendDescriptor(&d, witness); } if (prototypeMode != DONT_ADD_PROTOTYPE) { // Add prototype. if (prototypeMode == ADD_WRITEABLE_PROTOTYPE) { attribs = static_cast(attribs & ~READ_ONLY); } CallbacksDescriptor d(*factory()->prototype_symbol(), *prototype, attribs); map->AppendDescriptor(&d, witness); } } Handle Genesis::CreateFunctionMap(PrototypePropertyMode prototype_mode) { Handle map = factory()->NewMap(JS_FUNCTION_TYPE, JSFunction::kSize); SetFunctionInstanceDescriptor(map, prototype_mode); map->set_function_with_prototype(prototype_mode != DONT_ADD_PROTOTYPE); return map; } 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. // Please note that the prototype property for function instances must be // writable. Handle function_instance_map = CreateFunctionMap(ADD_WRITEABLE_PROTOTYPE); native_context()->set_function_instance_map(*function_instance_map); // Functions with this map will not have a 'prototype' property, and // can not be used as constructors. Handle function_without_prototype_map = CreateFunctionMap(DONT_ADD_PROTOTYPE); native_context()->set_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 = CreateFunctionMap(ADD_READONLY_PROTOTYPE); native_context()->set_function_map(*function_map); // The final map for functions. Writeable prototype. // This map is installed in MakeFunctionInstancePrototypeWritable. function_instance_map_writable_prototype_ = CreateFunctionMap(ADD_WRITEABLE_PROTOTYPE); Factory* factory = isolate->factory(); Heap* heap = isolate->heap(); Handle object_name = Handle(heap->Object_symbol()); { // --- O b j e c t --- Handle object_fun = factory->NewFunction(object_name, factory->null_value()); Handle object_function_map = factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); object_fun->set_initial_map(*object_function_map); object_function_map->set_constructor(*object_fun); native_context()->set_object_function(*object_fun); // Allocate a new prototype for the object function. Handle prototype = factory->NewJSObject( isolate->object_function(), TENURED); native_context()->set_initial_object_prototype(*prototype); SetPrototype(object_fun, prototype); } // Allocate the empty function as the prototype for function ECMAScript // 262 15.3.4. Handle symbol = factory->LookupOneByteSymbol(STATIC_ASCII_VECTOR("Empty")); Handle empty_function = factory->NewFunctionWithoutPrototype(symbol, CLASSIC_MODE); // --- E m p t y --- Handle code = Handle(isolate->builtins()->builtin( Builtins::kEmptyFunction)); empty_function->set_code(*code); empty_function->shared()->set_code(*code); Handle source = factory->NewStringFromOneByte(STATIC_ASCII_VECTOR("() {}")); Handle