| Index: src/bootstrapper.cc
|
| diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
|
| index 8cd29b218aa9473f7468038c9ac7cbdbf48cf385..d0ecb856ab4a8918b4f9dc83743d7531ff216efa 100644
|
| --- a/src/bootstrapper.cc
|
| +++ b/src/bootstrapper.cc
|
| @@ -207,6 +207,10 @@ class Genesis BASE_EMBEDDED {
|
| void CreateRoots();
|
| // Creates the empty function. Used for creating a context from scratch.
|
| Handle<JSFunction> CreateEmptyFunction();
|
| + // Creates the ThrowTypeError function. ECMA 5th Ed. 13.2.3
|
| + Handle<JSFunction> CreateThrowTypeErrorFunction(Builtins::Name builtin);
|
| +
|
| + void CreateStrictModeFunctionMaps(Handle<JSFunction> empty);
|
| // 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
|
| @@ -260,10 +264,24 @@ class Genesis BASE_EMBEDDED {
|
| ADD_READONLY_PROTOTYPE,
|
| ADD_WRITEABLE_PROTOTYPE
|
| };
|
| +
|
| + Handle<Map> CreateFunctionMap(PrototypePropertyMode prototype_mode);
|
| +
|
| Handle<DescriptorArray> ComputeFunctionInstanceDescriptor(
|
| PrototypePropertyMode prototypeMode);
|
| void MakeFunctionInstancePrototypeWritable();
|
|
|
| + Handle<Map> CreateStrictModeFunctionMap(
|
| + PrototypePropertyMode prototype_mode,
|
| + Handle<JSFunction> empty_function,
|
| + Handle<FixedArray> arguments_callbacks,
|
| + Handle<FixedArray> caller_callbacks);
|
| +
|
| + Handle<DescriptorArray> ComputeStrictFunctionInstanceDescriptor(
|
| + PrototypePropertyMode propertyMode,
|
| + Handle<FixedArray> arguments,
|
| + Handle<FixedArray> caller);
|
| +
|
| static bool CompileBuiltin(int index);
|
| static bool CompileNative(Vector<const char> name, Handle<String> source);
|
| static bool CompileScriptCached(Vector<const char> name,
|
| @@ -274,7 +292,14 @@ class Genesis BASE_EMBEDDED {
|
| bool use_runtime_context);
|
|
|
| Handle<Context> result_;
|
| - Handle<JSFunction> empty_function_;
|
| +
|
| + // 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<Map> function_instance_map_writable_prototype_;
|
| + Handle<Map> strict_mode_function_instance_map_writable_prototype_;
|
| +
|
| BootstrapperActive active_;
|
| friend class Bootstrapper;
|
| };
|
| @@ -359,89 +384,79 @@ static Handle<JSFunction> InstallFunction(Handle<JSObject> target,
|
|
|
| Handle<DescriptorArray> Genesis::ComputeFunctionInstanceDescriptor(
|
| PrototypePropertyMode prototypeMode) {
|
| - Handle<DescriptorArray> result = Factory::empty_descriptor_array();
|
| + Handle<DescriptorArray> descriptors =
|
| + Factory::NewDescriptorArray(prototypeMode == DONT_ADD_PROTOTYPE ? 4 : 5);
|
| + PropertyAttributes attributes =
|
| + static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
|
|
|
| + { // Add length.
|
| + Handle<Proxy> proxy = Factory::NewProxy(&Accessors::FunctionLength);
|
| + CallbacksDescriptor d(*Factory::length_symbol(), *proxy, attributes);
|
| + descriptors->Set(0, &d);
|
| + }
|
| + { // Add name.
|
| + Handle<Proxy> proxy = Factory::NewProxy(&Accessors::FunctionName);
|
| + CallbacksDescriptor d(*Factory::name_symbol(), *proxy, attributes);
|
| + descriptors->Set(1, &d);
|
| + }
|
| + { // Add arguments.
|
| + Handle<Proxy> proxy = Factory::NewProxy(&Accessors::FunctionArguments);
|
| + CallbacksDescriptor d(*Factory::arguments_symbol(), *proxy, attributes);
|
| + descriptors->Set(2, &d);
|
| + }
|
| + { // Add caller.
|
| + Handle<Proxy> proxy = Factory::NewProxy(&Accessors::FunctionCaller);
|
| + CallbacksDescriptor d(*Factory::caller_symbol(), *proxy, attributes);
|
| + descriptors->Set(3, &d);
|
| + }
|
| if (prototypeMode != DONT_ADD_PROTOTYPE) {
|
| - PropertyAttributes attributes = static_cast<PropertyAttributes>(
|
| - DONT_ENUM |
|
| - DONT_DELETE |
|
| - (prototypeMode == ADD_READONLY_PROTOTYPE ? READ_ONLY : 0));
|
| - result =
|
| - Factory::CopyAppendProxyDescriptor(
|
| - result,
|
| - Factory::prototype_symbol(),
|
| - Factory::NewProxy(&Accessors::FunctionPrototype),
|
| - attributes);
|
| + // Add prototype.
|
| + if (prototypeMode == ADD_WRITEABLE_PROTOTYPE) {
|
| + attributes = static_cast<PropertyAttributes>(attributes & ~READ_ONLY);
|
| + }
|
| + Handle<Proxy> proxy = Factory::NewProxy(&Accessors::FunctionPrototype);
|
| + CallbacksDescriptor d(*Factory::prototype_symbol(), *proxy, attributes);
|
| + descriptors->Set(4, &d);
|
| }
|
| + descriptors->Sort();
|
| + return descriptors;
|
| +}
|
|
|
| - PropertyAttributes attributes =
|
| - static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
|
| - // Add length.
|
| - result =
|
| - Factory::CopyAppendProxyDescriptor(
|
| - result,
|
| - Factory::length_symbol(),
|
| - Factory::NewProxy(&Accessors::FunctionLength),
|
| - attributes);
|
| -
|
| - // Add name.
|
| - result =
|
| - Factory::CopyAppendProxyDescriptor(
|
| - result,
|
| - Factory::name_symbol(),
|
| - Factory::NewProxy(&Accessors::FunctionName),
|
| - attributes);
|
| -
|
| - // Add arguments.
|
| - result =
|
| - Factory::CopyAppendProxyDescriptor(
|
| - result,
|
| - Factory::arguments_symbol(),
|
| - Factory::NewProxy(&Accessors::FunctionArguments),
|
| - attributes);
|
| -
|
| - // Add caller.
|
| - result =
|
| - Factory::CopyAppendProxyDescriptor(
|
| - result,
|
| - Factory::caller_symbol(),
|
| - Factory::NewProxy(&Accessors::FunctionCaller),
|
| - attributes);
|
|
|
| - return result;
|
| +Handle<Map> Genesis::CreateFunctionMap(PrototypePropertyMode prototype_mode) {
|
| + Handle<Map> map = Factory::NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
|
| + Handle<DescriptorArray> descriptors =
|
| + ComputeFunctionInstanceDescriptor(prototype_mode);
|
| + map->set_instance_descriptors(*descriptors);
|
| + map->set_function_with_prototype(prototype_mode != DONT_ADD_PROTOTYPE);
|
| + return map;
|
| }
|
|
|
|
|
| Handle<JSFunction> Genesis::CreateEmptyFunction() {
|
| - // Allocate the map for function instances.
|
| - Handle<Map> fm = Factory::NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
|
| - global_context()->set_function_instance_map(*fm);
|
| + // 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<DescriptorArray> function_map_descriptors =
|
| - ComputeFunctionInstanceDescriptor(ADD_WRITEABLE_PROTOTYPE);
|
| - fm->set_instance_descriptors(*function_map_descriptors);
|
| - fm->set_function_with_prototype(true);
|
| + global_context()->set_function_instance_map(
|
| + *CreateFunctionMap(ADD_WRITEABLE_PROTOTYPE));
|
|
|
| // Functions with this map will not have a 'prototype' property, and
|
| // can not be used as constructors.
|
| - Handle<Map> function_without_prototype_map =
|
| - Factory::NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
|
| global_context()->set_function_without_prototype_map(
|
| - *function_without_prototype_map);
|
| - Handle<DescriptorArray> function_without_prototype_map_descriptors =
|
| - ComputeFunctionInstanceDescriptor(DONT_ADD_PROTOTYPE);
|
| - function_without_prototype_map->set_instance_descriptors(
|
| - *function_without_prototype_map_descriptors);
|
| - function_without_prototype_map->set_function_with_prototype(false);
|
| + *CreateFunctionMap(DONT_ADD_PROTOTYPE));
|
|
|
| - // Allocate the function map first and then patch the prototype later
|
| - fm = Factory::NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
|
| - global_context()->set_function_map(*fm);
|
| - function_map_descriptors =
|
| - ComputeFunctionInstanceDescriptor(ADD_READONLY_PROTOTYPE);
|
| - fm->set_instance_descriptors(*function_map_descriptors);
|
| - fm->set_function_with_prototype(true);
|
| + // 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.
|
| + global_context()->set_function_map(
|
| + *CreateFunctionMap(ADD_READONLY_PROTOTYPE));
|
| +
|
| + // The final map for functions. Writeable prototype.
|
| + // This map is installed in MakeFunctionInstancePrototypeWritable.
|
| + function_instance_map_writable_prototype_ =
|
| + CreateFunctionMap(ADD_WRITEABLE_PROTOTYPE);
|
|
|
| Handle<String> object_name = Handle<String>(Heap::Object_symbol());
|
|
|
| @@ -469,7 +484,7 @@ Handle<JSFunction> Genesis::CreateEmptyFunction() {
|
| // 262 15.3.4.
|
| Handle<String> symbol = Factory::LookupAsciiSymbol("Empty");
|
| Handle<JSFunction> empty_function =
|
| - Factory::NewFunctionWithoutPrototype(symbol);
|
| + Factory::NewFunctionWithoutPrototype(symbol, kNonStrictMode);
|
|
|
| // --- E m p t y ---
|
| Handle<Code> code =
|
| @@ -483,22 +498,149 @@ Handle<JSFunction> Genesis::CreateEmptyFunction() {
|
| empty_function->shared()->set_start_position(0);
|
| empty_function->shared()->set_end_position(source->length());
|
| empty_function->shared()->DontAdaptArguments();
|
| +
|
| + // Set prototypes for the function maps.
|
| global_context()->function_map()->set_prototype(*empty_function);
|
| global_context()->function_instance_map()->set_prototype(*empty_function);
|
| global_context()->function_without_prototype_map()->
|
| set_prototype(*empty_function);
|
| + function_instance_map_writable_prototype_->set_prototype(*empty_function);
|
|
|
| // Allocate the function map first and then patch the prototype later
|
| + Handle<Map> function_without_prototype_map(
|
| + global_context()->function_without_prototype_map());
|
| Handle<Map> empty_fm = Factory::CopyMapDropDescriptors(
|
| function_without_prototype_map);
|
| empty_fm->set_instance_descriptors(
|
| - *function_without_prototype_map_descriptors);
|
| + function_without_prototype_map->instance_descriptors());
|
| empty_fm->set_prototype(global_context()->object_function()->prototype());
|
| empty_function->set_map(*empty_fm);
|
| return empty_function;
|
| }
|
|
|
|
|
| +Handle<DescriptorArray> Genesis::ComputeStrictFunctionInstanceDescriptor(
|
| + PrototypePropertyMode prototypeMode,
|
| + Handle<FixedArray> arguments,
|
| + Handle<FixedArray> caller) {
|
| + Handle<DescriptorArray> descriptors =
|
| + Factory::NewDescriptorArray(prototypeMode == DONT_ADD_PROTOTYPE ? 4 : 5);
|
| + PropertyAttributes attributes = static_cast<PropertyAttributes>(
|
| + DONT_ENUM | DONT_DELETE | READ_ONLY);
|
| +
|
| + { // length
|
| + Handle<Proxy> proxy = Factory::NewProxy(&Accessors::FunctionLength);
|
| + CallbacksDescriptor d(*Factory::length_symbol(), *proxy, attributes);
|
| + descriptors->Set(0, &d);
|
| + }
|
| + { // name
|
| + Handle<Proxy> proxy = Factory::NewProxy(&Accessors::FunctionName);
|
| + CallbacksDescriptor d(*Factory::name_symbol(), *proxy, attributes);
|
| + descriptors->Set(1, &d);
|
| + }
|
| + { // arguments
|
| + CallbacksDescriptor d(*Factory::arguments_symbol(), *arguments, attributes);
|
| + descriptors->Set(2, &d);
|
| + }
|
| + { // caller
|
| + CallbacksDescriptor d(*Factory::caller_symbol(), *caller, attributes);
|
| + descriptors->Set(3, &d);
|
| + }
|
| +
|
| + // prototype
|
| + if (prototypeMode != DONT_ADD_PROTOTYPE) {
|
| + if (prototypeMode == ADD_WRITEABLE_PROTOTYPE) {
|
| + attributes = static_cast<PropertyAttributes>(attributes & ~READ_ONLY);
|
| + }
|
| + Handle<Proxy> proxy = Factory::NewProxy(&Accessors::FunctionPrototype);
|
| + CallbacksDescriptor d(*Factory::prototype_symbol(), *proxy, attributes);
|
| + descriptors->Set(4, &d);
|
| + }
|
| +
|
| + descriptors->Sort();
|
| + return descriptors;
|
| +}
|
| +
|
| +
|
| +// ECMAScript 5th Edition, 13.2.3
|
| +Handle<JSFunction> Genesis::CreateThrowTypeErrorFunction(
|
| + Builtins::Name builtin) {
|
| + Handle<String> name = Factory::LookupAsciiSymbol("ThrowTypeError");
|
| + Handle<JSFunction> throw_type_error =
|
| + Factory::NewFunctionWithoutPrototype(name, kStrictMode);
|
| + Handle<Code> code = Handle<Code>(Builtins::builtin(builtin));
|
| +
|
| + throw_type_error->set_map(global_context()->strict_mode_function_map());
|
| + throw_type_error->set_code(*code);
|
| + throw_type_error->shared()->set_code(*code);
|
| + throw_type_error->shared()->DontAdaptArguments();
|
| +
|
| + PreventExtensions(throw_type_error);
|
| +
|
| + return throw_type_error;
|
| +}
|
| +
|
| +
|
| +Handle<Map> Genesis::CreateStrictModeFunctionMap(
|
| + PrototypePropertyMode prototype_mode,
|
| + Handle<JSFunction> empty_function,
|
| + Handle<FixedArray> arguments_callbacks,
|
| + Handle<FixedArray> caller_callbacks) {
|
| + Handle<Map> map = Factory::NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
|
| + Handle<DescriptorArray> descriptors =
|
| + ComputeStrictFunctionInstanceDescriptor(prototype_mode,
|
| + arguments_callbacks,
|
| + caller_callbacks);
|
| + map->set_instance_descriptors(*descriptors);
|
| + map->set_function_with_prototype(prototype_mode != DONT_ADD_PROTOTYPE);
|
| + map->set_prototype(*empty_function);
|
| + return map;
|
| +}
|
| +
|
| +
|
| +void Genesis::CreateStrictModeFunctionMaps(Handle<JSFunction> empty) {
|
| + // Create the callbacks arrays for ThrowTypeError functions.
|
| + // The get/set callacks are filled in after the maps are created below.
|
| + Handle<FixedArray> arguments = Factory::NewFixedArray(2, TENURED);
|
| + Handle<FixedArray> caller = Factory::NewFixedArray(2, TENURED);
|
| +
|
| + // Allocate map for the strict mode function instances.
|
| + global_context()->set_strict_mode_function_instance_map(
|
| + *CreateStrictModeFunctionMap(
|
| + ADD_WRITEABLE_PROTOTYPE, empty, arguments, caller));
|
| +
|
| + // Allocate map for the prototype-less strict mode instances.
|
| + global_context()->set_strict_mode_function_without_prototype_map(
|
| + *CreateStrictModeFunctionMap(
|
| + DONT_ADD_PROTOTYPE, empty, arguments, caller));
|
| +
|
| + // Allocate map for the strict mode functions. This map is temporary, used
|
| + // only for processing of builtins.
|
| + // Later the map is replaced with writable prototype map, allocated below.
|
| + global_context()->set_strict_mode_function_map(
|
| + *CreateStrictModeFunctionMap(
|
| + ADD_READONLY_PROTOTYPE, empty, arguments, caller));
|
| +
|
| + // The final map for the strict mode functions. Writeable prototype.
|
| + // This map is installed in MakeFunctionInstancePrototypeWritable.
|
| + strict_mode_function_instance_map_writable_prototype_ =
|
| + CreateStrictModeFunctionMap(
|
| + ADD_WRITEABLE_PROTOTYPE, empty, arguments, caller);
|
| +
|
| + // Create the ThrowTypeError function instances.
|
| + Handle<JSFunction> arguments_throw =
|
| + CreateThrowTypeErrorFunction(Builtins::StrictFunctionArguments);
|
| + Handle<JSFunction> caller_throw =
|
| + CreateThrowTypeErrorFunction(Builtins::StrictFunctionCaller);
|
| +
|
| + // Complete the callback fixed arrays.
|
| + arguments->set(0, *arguments_throw);
|
| + arguments->set(1, *arguments_throw);
|
| + caller->set(0, *caller_throw);
|
| + caller->set(1, *caller_throw);
|
| +}
|
| +
|
| +
|
| static void AddToWeakGlobalContextList(Context* context) {
|
| ASSERT(context->IsGlobalContext());
|
| #ifdef DEBUG
|
| @@ -1809,16 +1951,17 @@ void Genesis::TransferObject(Handle<JSObject> from, Handle<JSObject> to) {
|
|
|
|
|
| void Genesis::MakeFunctionInstancePrototypeWritable() {
|
| - // Make a new function map so all future functions
|
| - // will have settable and enumerable prototype properties.
|
| - HandleScope scope;
|
| -
|
| - Handle<DescriptorArray> function_map_descriptors =
|
| - ComputeFunctionInstanceDescriptor(ADD_WRITEABLE_PROTOTYPE);
|
| - Handle<Map> fm = Factory::CopyMapDropDescriptors(Top::function_map());
|
| - fm->set_instance_descriptors(*function_map_descriptors);
|
| - fm->set_function_with_prototype(true);
|
| - Top::context()->global_context()->set_function_map(*fm);
|
| + // The maps with writable prototype are created in CreateEmptyFunction
|
| + // and CreateStrictModeFunctionMaps respectively. Initially the maps are
|
| + // created with read-only prototype for JS builtins processing.
|
| + ASSERT(!function_instance_map_writable_prototype_.is_null());
|
| + ASSERT(!strict_mode_function_instance_map_writable_prototype_.is_null());
|
| +
|
| + // Replace function instance maps to make prototype writable.
|
| + global_context()->set_function_map(
|
| + *function_instance_map_writable_prototype_);
|
| + global_context()->set_strict_mode_function_map(
|
| + *strict_mode_function_instance_map_writable_prototype_);
|
| }
|
|
|
|
|
| @@ -1841,9 +1984,6 @@ Genesis::Genesis(Handle<Object> global_object,
|
| AddToWeakGlobalContextList(*global_context_);
|
| Top::set_context(*global_context_);
|
| i::Counters::contexts_created_by_snapshot.Increment();
|
| - JSFunction* empty_function =
|
| - JSFunction::cast(global_context_->function_map()->prototype());
|
| - empty_function_ = Handle<JSFunction>(empty_function);
|
| Handle<GlobalObject> inner_global;
|
| Handle<JSGlobalProxy> global_proxy =
|
| CreateNewGlobals(global_template,
|
| @@ -1858,6 +1998,7 @@ Genesis::Genesis(Handle<Object> global_object,
|
| // We get here if there was no context snapshot.
|
| CreateRoots();
|
| Handle<JSFunction> empty_function = CreateEmptyFunction();
|
| + CreateStrictModeFunctionMaps(empty_function);
|
| Handle<GlobalObject> inner_global;
|
| Handle<JSGlobalProxy> global_proxy =
|
| CreateNewGlobals(global_template, global_object, &inner_global);
|
|
|