Index: src/bootstrapper.cc |
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc |
index 8cd29b218aa9473f7468038c9ac7cbdbf48cf385..f824dced02451f45829d775338737d9ee981ef44 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(); |
+ void CreateThrowTypeErrorCallbacks( |
+ Handle<FixedArray> callbacks, |
+ Builtins::Name builtin); |
+ void CreateThrowTypeError(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 |
@@ -263,6 +267,10 @@ class Genesis BASE_EMBEDDED { |
Handle<DescriptorArray> ComputeFunctionInstanceDescriptor( |
PrototypePropertyMode prototypeMode); |
void MakeFunctionInstancePrototypeWritable(); |
+ Handle<DescriptorArray> ComputeStrictFunctionDescriptor( |
+ PrototypePropertyMode propertyMode, |
+ Handle<FixedArray> arguments, |
+ Handle<FixedArray> caller); |
static bool CompileBuiltin(int index); |
static bool CompileNative(Vector<const char> name, Handle<String> source); |
@@ -499,6 +507,113 @@ Handle<JSFunction> Genesis::CreateEmptyFunction() { |
} |
+Handle<DescriptorArray> Genesis::ComputeStrictFunctionDescriptor( |
+ 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); |
+ } |
+ CallbacksDescriptor d( |
+ *Factory::prototype_symbol(), |
+ *Factory::NewProxy(&Accessors::FunctionPrototype), |
+ attributes); |
+ descriptors->Set(4, &d); |
+ } |
+ |
+ descriptors->Sort(); |
+ return descriptors; |
+} |
+ |
+ |
+void Genesis::CreateThrowTypeErrorCallbacks( |
+ Handle<FixedArray> callbacks, |
+ Builtins::Name builtin) { |
+ // Create the ThrowTypeError function. |
+ Handle<String> name = Factory::LookupAsciiSymbol("ThrowTypeError"); |
+ Handle<JSFunction> pill = Factory::NewFunctionWithoutPrototypeStrict(name); |
+ Handle<Code> code = Handle<Code>(Builtins::builtin(builtin)); |
+ pill->set_map(global_context()->function_map_strict()); |
+ pill->set_code(*code); |
+ pill->shared()->set_code(*code); |
+ pill->shared()->DontAdaptArguments(); |
+ |
+ // Install the poison pills into the calbacks array. |
+ callbacks->set(0, *pill); |
+ callbacks->set(1, *pill); |
+ |
+ PreventExtensions(pill); |
+} |
+ |
+ |
+// ECMAScript 5th Edition, 13.2.3 |
+void Genesis::CreateThrowTypeError(Handle<JSFunction> empty) { |
+ // Create the pill callbacks arrays. The get/set callacks are installed |
+ // after the maps get created below. |
+ Handle<FixedArray> arguments = Factory::NewFixedArray(2, TENURED); |
+ Handle<FixedArray> caller = Factory::NewFixedArray(2, TENURED); |
+ |
+ { // Allocate map for the strict mode function instances. |
+ Handle<Map> map = Factory::NewMap(JS_FUNCTION_TYPE, JSFunction::kSize); |
+ global_context()->set_function_instance_map_strict(*map); |
+ Handle<DescriptorArray> descriptors = ComputeStrictFunctionDescriptor( |
+ ADD_WRITEABLE_PROTOTYPE, arguments, caller); |
+ map->set_instance_descriptors(*descriptors); |
+ map->set_function_with_prototype(true); |
+ map->set_prototype(*empty); |
+ } |
+ |
+ { // Allocate map for the prototype-less strict mode instances. |
+ Handle<Map> map = Factory::NewMap(JS_FUNCTION_TYPE, JSFunction::kSize); |
+ global_context()->set_function_without_prototype_map_strict(*map); |
+ Handle<DescriptorArray> descriptors = ComputeStrictFunctionDescriptor( |
+ DONT_ADD_PROTOTYPE, arguments, caller); |
+ map->set_instance_descriptors(*descriptors); |
+ map->set_function_with_prototype(false); |
+ map->set_prototype(*empty); |
+ } |
+ |
+ { // Allocate map for the strict mode functions. |
+ Handle<Map> map = Factory::NewMap(JS_FUNCTION_TYPE, JSFunction::kSize); |
+ global_context()->set_function_map_strict(*map); |
+ Handle<DescriptorArray> descriptors = ComputeStrictFunctionDescriptor( |
+ ADD_READONLY_PROTOTYPE, arguments, caller); |
+ map->set_instance_descriptors(*descriptors); |
+ map->set_function_with_prototype(true); |
+ map->set_prototype(*empty); |
+ } |
+ |
+ CreateThrowTypeErrorCallbacks(arguments, Builtins::StrictFunctionArguments); |
+ CreateThrowTypeErrorCallbacks(caller, Builtins::StrictFunctionCaller); |
+} |
+ |
+ |
static void AddToWeakGlobalContextList(Context* context) { |
ASSERT(context->IsGlobalContext()); |
#ifdef DEBUG |
@@ -1813,12 +1928,37 @@ void Genesis::MakeFunctionInstancePrototypeWritable() { |
// 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); |
+ { // function_map |
+ 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); |
+ } |
+ |
+ { // function_map_strict |
+ // Extract arguments and caller from the original strict function map. |
+ Handle<Map> old_map(global_context()->function_map_strict()); |
+ Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors()); |
+ int arguments_index = old_descriptors->Search(*Factory::arguments_symbol()); |
+ int caller_index = old_descriptors->Search(*Factory::caller_symbol()); |
+ ASSERT(arguments_index != DescriptorArray::kNotFound); |
+ ASSERT(caller_index != DescriptorArray::kNotFound); |
+ Handle<FixedArray> arguments( |
+ FixedArray::cast(old_descriptors->GetValue(arguments_index))); |
+ Handle<FixedArray> caller( |
+ FixedArray::cast(old_descriptors->GetValue(caller_index))); |
+ |
+ // Create the map with writeable prototype for strict mode functions. |
+ Handle<Map> map = Factory::NewMap(JS_FUNCTION_TYPE, JSFunction::kSize); |
+ global_context()->set_function_map_strict(*map); |
+ Handle<DescriptorArray> descriptors = ComputeStrictFunctionDescriptor( |
+ ADD_WRITEABLE_PROTOTYPE, arguments, caller); |
+ map->set_instance_descriptors(*descriptors); |
+ map->set_function_with_prototype(true); |
+ map->set_prototype(old_map->prototype()); |
+ } |
} |
@@ -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(); |
+ CreateThrowTypeError(empty_function); |
Handle<GlobalObject> inner_global; |
Handle<JSGlobalProxy> global_proxy = |
CreateNewGlobals(global_template, global_object, &inner_global); |