Strict mode ThrowTypeError functions for
authormmaly@chromium.org <mmaly@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 17 Mar 2011 20:28:17 +0000 (20:28 +0000)
committermmaly@chromium.org <mmaly@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 17 Mar 2011 20:28:17 +0000 (20:28 +0000)
- function.caller
- function.arguments

Review URL: http://codereview.chromium.org/6694044/

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7250 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

21 files changed:
src/arm/codegen-arm.cc
src/arm/full-codegen-arm.cc
src/arm/lithium-codegen-arm.cc
src/bootstrapper.cc
src/builtins.cc
src/builtins.h
src/contexts.h
src/factory.cc
src/factory.h
src/handles.cc
src/handles.h
src/ia32/codegen-ia32.cc
src/ia32/full-codegen-ia32.cc
src/ia32/lithium-codegen-ia32.cc
src/messages.js
src/objects.cc
src/runtime.cc
src/x64/codegen-x64.cc
src/x64/full-codegen-x64.cc
src/x64/lithium-codegen-x64.cc
test/mjsunit/strict-mode.js

index 364f652..e6334ab 100644 (file)
@@ -3114,9 +3114,10 @@ void CodeGenerator::InstantiateFunction(
     bool pretenure) {
   // Use the fast case closure allocation code that allocates in new
   // space for nested functions that don't need literals cloning.
-  if (scope()->is_function_scope() &&
+  if (!pretenure &&
+      scope()->is_function_scope() &&
       function_info->num_literals() == 0 &&
-      !pretenure) {
+      !function_info->strict_mode()) {  // Strict mode functions use slow path.
     FastNewClosureStub stub;
     frame_->EmitPush(Operand(function_info));
     frame_->SpillAll();
index 74c38c2..ac97bdc 100644 (file)
@@ -1084,9 +1084,10 @@ void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
   // doesn't just get a copy of the existing unoptimized code.
   if (!FLAG_always_opt &&
       !FLAG_prepare_always_opt &&
+      !pretenure &&
       scope()->is_function_scope() &&
       info->num_literals() == 0 &&
-      !pretenure) {
+      !info->strict_mode()) {  // Strict mode functions use slow path.
     FastNewClosureStub stub;
     __ mov(r0, Operand(info));
     __ push(r0);
index a2d1df0..2b1fe35 100644 (file)
@@ -3726,7 +3726,8 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
   // space for nested functions that don't need literals cloning.
   Handle<SharedFunctionInfo> shared_info = instr->shared_info();
   bool pretenure = instr->hydrogen()->pretenure();
-  if (shared_info->num_literals() == 0 && !pretenure) {
+  if (!pretenure && shared_info->num_literals() == 0 &&
+      !shared_info->strict_mode()) {  // Strict mode functions use slow path.
     FastNewClosureStub stub;
     __ mov(r1, Operand(shared_info));
     __ push(r1);
index 8cd29b2..d0ecb85 100644 (file)
@@ -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);
index 01e8deb..a51b01d 100644 (file)
@@ -959,6 +959,24 @@ BUILTIN(ArrayConcat) {
 
 
 // -----------------------------------------------------------------------------
+// Strict mode poison pills
+
+
+BUILTIN(StrictFunctionCaller) {
+  HandleScope scope;
+  return Top::Throw(*Factory::NewTypeError("strict_function_caller",
+                                            HandleVector<Object>(NULL, 0)));
+}
+
+
+BUILTIN(StrictFunctionArguments) {
+  HandleScope scope;
+  return Top::Throw(*Factory::NewTypeError("strict_function_arguments",
+                                            HandleVector<Object>(NULL, 0)));
+}
+
+
+// -----------------------------------------------------------------------------
 //
 
 
index 5ea4665..dd628a4 100644 (file)
@@ -58,7 +58,10 @@ enum BuiltinExtraArguments {
   V(FastHandleApiCall, NO_EXTRA_ARGUMENTS)                          \
   V(HandleApiCallConstruct, NEEDS_CALLED_FUNCTION)                  \
   V(HandleApiCallAsFunction, NO_EXTRA_ARGUMENTS)                    \
-  V(HandleApiCallAsConstructor, NO_EXTRA_ARGUMENTS)
+  V(HandleApiCallAsConstructor, NO_EXTRA_ARGUMENTS)                 \
+                                                                    \
+  V(StrictFunctionCaller, NO_EXTRA_ARGUMENTS)                       \
+  V(StrictFunctionArguments, NO_EXTRA_ARGUMENTS)
 
 
 // Define list of builtins implemented in assembly.
index d0d54d1..47bba2e 100644 (file)
@@ -78,8 +78,13 @@ enum ContextLookupFlags {
   V(INSTANTIATE_FUN_INDEX, JSFunction, instantiate_fun) \
   V(CONFIGURE_INSTANCE_FUN_INDEX, JSFunction, configure_instance_fun) \
   V(FUNCTION_MAP_INDEX, Map, function_map) \
+  V(STRICT_MODE_FUNCTION_MAP_INDEX, Map, strict_mode_function_map) \
   V(FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX, Map, function_without_prototype_map) \
+  V(STRICT_MODE_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX, Map, \
+    strict_mode_function_without_prototype_map) \
   V(FUNCTION_INSTANCE_MAP_INDEX, Map, function_instance_map) \
+  V(STRICT_MODE_FUNCTION_INSTANCE_MAP_INDEX, Map, \
+    strict_mode_function_instance_map) \
   V(JS_ARRAY_MAP_INDEX, Map, js_array_map)\
   V(REGEXP_RESULT_MAP_INDEX, Map, regexp_result_map)\
   V(ARGUMENTS_BOILERPLATE_INDEX, JSObject, arguments_boilerplate) \
@@ -185,8 +190,11 @@ class Context: public FixedArray {
     JS_ARRAY_MAP_INDEX,
     REGEXP_RESULT_MAP_INDEX,
     FUNCTION_MAP_INDEX,
+    STRICT_MODE_FUNCTION_MAP_INDEX,
     FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX,
+    STRICT_MODE_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX,
     FUNCTION_INSTANCE_MAP_INDEX,
+    STRICT_MODE_FUNCTION_INSTANCE_MAP_INDEX,
     INITIAL_OBJECT_PROTOTYPE_INDEX,
     BOOLEAN_FUNCTION_INDEX,
     NUMBER_FUNCTION_INDEX,
index e848b57..1ac501f 100644 (file)
@@ -351,7 +351,12 @@ Handle<JSFunction> Factory::NewFunctionFromSharedFunctionInfo(
     Handle<Context> context,
     PretenureFlag pretenure) {
   Handle<JSFunction> result = BaseNewFunctionFromSharedFunctionInfo(
-      function_info, Top::function_map(), pretenure);
+      function_info,
+      function_info->strict_mode()
+          ? Top::strict_mode_function_map()
+          : Top::function_map(),
+      pretenure);
+
   result->set_context(*context);
   int number_of_literals = function_info->num_literals();
   Handle<FixedArray> literals =
@@ -584,7 +589,8 @@ Handle<JSFunction> Factory::NewFunctionWithPrototype(Handle<String> name,
 
 Handle<JSFunction> Factory::NewFunctionWithoutPrototype(Handle<String> name,
                                                         Handle<Code> code) {
-  Handle<JSFunction> function = NewFunctionWithoutPrototype(name);
+  Handle<JSFunction> function = NewFunctionWithoutPrototype(name,
+                                                            kNonStrictMode);
   function->shared()->set_code(*code);
   function->set_code(*code);
   ASSERT(!function->has_initial_map());
@@ -809,18 +815,24 @@ Handle<JSFunction> Factory::NewFunction(Handle<String> name,
 
 
 Handle<JSFunction> Factory::NewFunctionWithoutPrototypeHelper(
-    Handle<String> name) {
+    Handle<String> name,
+    StrictModeFlag strict_mode) {
   Handle<SharedFunctionInfo> function_share = NewSharedFunctionInfo(name);
+  Handle<Map> map = strict_mode == kStrictMode
+      ? Top::strict_mode_function_without_prototype_map()
+      : Top::function_without_prototype_map();
   CALL_HEAP_FUNCTION(Heap::AllocateFunction(
-                         *Top::function_without_prototype_map(),
+                         *map,
                          *function_share,
                          *the_hole_value()),
                      JSFunction);
 }
 
 
-Handle<JSFunction> Factory::NewFunctionWithoutPrototype(Handle<String> name) {
-  Handle<JSFunction> fun = NewFunctionWithoutPrototypeHelper(name);
+Handle<JSFunction> Factory::NewFunctionWithoutPrototype(
+    Handle<String> name,
+    StrictModeFlag strict_mode) {
+  Handle<JSFunction> fun = NewFunctionWithoutPrototypeHelper(name, strict_mode);
   fun->set_context(Top::context()->global_context());
   return fun;
 }
index e03e98b..1b9d940 100644 (file)
@@ -231,7 +231,9 @@ class Factory : public AllStatic {
   static Handle<JSFunction> NewFunction(Handle<String> name,
                                         Handle<Object> prototype);
 
-  static Handle<JSFunction> NewFunctionWithoutPrototype(Handle<String> name);
+  static Handle<JSFunction> NewFunctionWithoutPrototype(
+      Handle<String> name,
+      StrictModeFlag strict_mode);
 
   static Handle<JSFunction> NewFunction(Handle<Object> super, bool is_global);
 
@@ -407,7 +409,8 @@ class Factory : public AllStatic {
                                               Handle<Object> prototype);
 
   static Handle<JSFunction> NewFunctionWithoutPrototypeHelper(
-      Handle<String> name);
+      Handle<String> name,
+      StrictModeFlag strict_mode);
 
   static Handle<DescriptorArray> CopyAppendCallbackDescriptors(
       Handle<DescriptorArray> array,
index 2923f98..65cbd1a 100644 (file)
@@ -362,6 +362,11 @@ Handle<Object> SetPrototype(Handle<JSObject> obj, Handle<Object> value) {
 }
 
 
+Handle<Object> PreventExtensions(Handle<JSObject> object) {
+  CALL_HEAP_FUNCTION(object->PreventExtensions(), Object);
+}
+
+
 Handle<Object> GetHiddenProperties(Handle<JSObject> obj,
                                    bool create_if_needed) {
   Object* holder = obj->BypassGlobalProxy();
index 58db989..667d5ca 100644 (file)
@@ -370,6 +370,7 @@ Handle<JSGlobalProxy> ReinitializeJSGlobalProxy(
 Handle<Object> SetPrototype(Handle<JSFunction> function,
                             Handle<Object> prototype);
 
+Handle<Object> PreventExtensions(Handle<JSObject> object);
 
 // Does lazy compilation of the given function. Returns true on success and
 // false if the compilation resulted in a stack overflow.
index f1d4cac..03ca275 100644 (file)
@@ -4916,9 +4916,10 @@ Result CodeGenerator::InstantiateFunction(
 
   // Use the fast case closure allocation code that allocates in new
   // space for nested functions that don't need literals cloning.
-  if (scope()->is_function_scope() &&
+  if (!pretenure &&
+      scope()->is_function_scope() &&
       function_info->num_literals() == 0 &&
-      !pretenure) {
+      !function_info->strict_mode()) {  // Strict mode functions use slow path.
     FastNewClosureStub stub;
     frame()->EmitPush(Immediate(function_info));
     return frame()->CallStub(&stub, 1);
index cf593db..7371555 100644 (file)
@@ -1017,9 +1017,10 @@ void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
   // doesn't just get a copy of the existing unoptimized code.
   if (!FLAG_always_opt &&
       !FLAG_prepare_always_opt &&
+      !pretenure &&
       scope()->is_function_scope() &&
       info->num_literals() == 0 &&
-      !pretenure) {
+      !info->strict_mode()) {   // Strict mode functions go through slow path.
     FastNewClosureStub stub;
     __ push(Immediate(info));
     __ CallStub(&stub);
index b583f79..66ca532 100644 (file)
@@ -3739,7 +3739,8 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
   // space for nested functions that don't need literals cloning.
   Handle<SharedFunctionInfo> shared_info = instr->shared_info();
   bool pretenure = instr->hydrogen()->pretenure();
-  if (shared_info->num_literals() == 0 && !pretenure) {
+  if (!pretenure && shared_info->num_literals() == 0 &&
+      !shared_info->strict_mode()) {
     FastNewClosureStub stub;
     __ push(Immediate(shared_info));
     CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
index 2c94912..3adca7f 100644 (file)
@@ -230,6 +230,8 @@ function FormatMessage(message) {
       strict_function:              ["In strict mode code, functions can only be declared at top level or immediately within another function." ],
       strict_read_only_property:    ["Cannot assign to read only property '", "%0", "' of ", "%1"],
       strict_cannot_assign:         ["Cannot assign to read only '", "%0", "' in strict mode"],
+      strict_function_caller:       ["Cannot access property 'caller' of a strict mode function"],
+      strict_function_arguments:    ["Cannot access property 'arguments' of a strict mode function"],
     };
   }
   var message_type = %MessageGetType(message);
index 6e47946..a4e07d2 100644 (file)
@@ -5536,12 +5536,21 @@ MaybeObject* JSFunction::SetPrototype(Object* value) {
 
 
 Object* JSFunction::RemovePrototype() {
-  if (map() == context()->global_context()->function_without_prototype_map()) {
+  Context* global_context = context()->global_context();
+  Map* no_prototype_map = shared()->strict_mode()
+      ? global_context->strict_mode_function_without_prototype_map()
+      : global_context->function_without_prototype_map();
+
+  if (map() == no_prototype_map) {
     // Be idempotent.
     return this;
   }
-  ASSERT(map() == context()->global_context()->function_map());
-  set_map(context()->global_context()->function_without_prototype_map());
+
+  ASSERT(!shared()->strict_mode() ||
+         map() == global_context->strict_mode_function_map());
+  ASSERT(shared()->strict_mode() || map() == global_context->function_map());
+
+  set_map(no_prototype_map);
   set_prototype_or_initial_map(Heap::the_hole_value());
   return this;
 }
index 9349dc5..fb58346 100644 (file)
@@ -8045,11 +8045,14 @@ static MaybeObject* Runtime_SetNewFunctionAttributes(Arguments args) {
   HandleScope scope;
   ASSERT(args.length() == 1);
   CONVERT_ARG_CHECKED(JSFunction, func, 0);
-  ASSERT(func->map()->instance_type() ==
-         Top::function_instance_map()->instance_type());
-  ASSERT(func->map()->instance_size() ==
-         Top::function_instance_map()->instance_size());
-  func->set_map(*Top::function_instance_map());
+
+  Handle<Map> map = func->shared()->strict_mode()
+                        ? Top::strict_mode_function_instance_map()
+                        : Top::function_instance_map();
+
+  ASSERT(func->map()->instance_type() == map->instance_type());
+  ASSERT(func->map()->instance_size() == map->instance_size());
+  func->set_map(*map);
   return *func;
 }
 
index 21c90a1..10aa451 100644 (file)
@@ -4260,9 +4260,10 @@ void CodeGenerator::InstantiateFunction(
 
   // Use the fast case closure allocation code that allocates in new
   // space for nested functions that don't need literals cloning.
-  if (scope()->is_function_scope() &&
+  if (!pretenure &&
+      scope()->is_function_scope() &&
       function_info->num_literals() == 0 &&
-      !pretenure) {
+      !function_info->strict_mode()) {  // Strict mode functions use slow path.
     FastNewClosureStub stub;
     frame_->Push(function_info);
     Result answer = frame_->CallStub(&stub, 1);
index 4cea0cc..cd3a999 100644 (file)
@@ -1039,9 +1039,10 @@ void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
   // doesn't just get a copy of the existing unoptimized code.
   if (!FLAG_always_opt &&
       !FLAG_prepare_always_opt &&
+      !pretenure &&
       scope()->is_function_scope() &&
       info->num_literals() == 0 &&
-      !pretenure) {
+      !info->strict_mode()) {  // Strict mode functions use slow path.
     FastNewClosureStub stub;
     __ Push(info);
     __ CallStub(&stub);
index fe9bd3e..b15aef6 100644 (file)
@@ -3539,7 +3539,8 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
   // space for nested functions that don't need literals cloning.
   Handle<SharedFunctionInfo> shared_info = instr->shared_info();
   bool pretenure = instr->hydrogen()->pretenure();
-  if (shared_info->num_literals() == 0 && !pretenure) {
+  if (!pretenure && shared_info->num_literals() == 0 &&
+      !shared_info->strict_mode()) {
     FastNewClosureStub stub;
     __ Push(shared_info);
     CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
index 2064162..0a51180 100644 (file)
@@ -976,3 +976,68 @@ repeat(10, function() { testAssignToUndefined(false); });
   assertEquals(["c", "d", "a", "b"], strict("a", "b"));
   assertEquals(["c", "d", "c", "d"], nonstrict("a", "b"));
 })();
+
+
+(function TestStrictFunctionPills() {
+  function strict() {
+    "use strict";
+  }
+  assertThrows(function() { strict.caller; }, TypeError);
+  assertThrows(function() { strict.arguments; }, TypeError);
+
+  var another = new Function("'use strict'");
+  assertThrows(function() { another.caller; }, TypeError);
+  assertThrows(function() { another.arguments; }, TypeError);
+
+  var third = (function() { "use strict"; return function() {}; })();
+  assertThrows(function() { third.caller; }, TypeError);
+  assertThrows(function() { third.arguments; }, TypeError);
+
+  function CheckPill(pill) {
+    assertEquals("function", typeof pill);
+    assertInstanceof(pill, Function);
+    assertThrows(function() { pill.property = "value"; }, TypeError);
+    assertThrows(pill, TypeError);
+    assertEquals(pill.prototype, (function(){}).prototype);
+    var d = Object.getOwnPropertyDescriptor(pill, "prototype");
+    assertFalse(d.writable);
+    assertFalse(d.configurable);
+    assertFalse(d.enumerable);
+  }
+
+  function CheckPillDescriptor(func, name) {
+    var descriptor = Object.getOwnPropertyDescriptor(func, name);
+    CheckPill(descriptor.get)
+    CheckPill(descriptor.set);
+    assertFalse(descriptor.enumerable);
+    assertFalse(descriptor.configurable);
+  }
+
+  CheckPillDescriptor(strict, "caller");
+  CheckPillDescriptor(strict, "arguments");
+  CheckPillDescriptor(another, "caller");
+  CheckPillDescriptor(another, "arguments");
+  CheckPillDescriptor(third, "caller");
+  CheckPillDescriptor(third, "arguments");
+})();
+
+
+(function TestStrictFunctionWritablePrototype() {
+  "use strict";
+  function TheClass() {
+  }
+  assertThrows(function() { TheClass.caller; }, TypeError);
+  assertThrows(function() { TheClass.arguments; }, TypeError);
+
+  // Strict functions must have writable prototype.
+  TheClass.prototype = {
+    func: function() { return "func_value"; },
+    get accessor() { return "accessor_value"; },
+    property: "property_value",
+  };
+
+  var o = new TheClass();
+  assertEquals(o.func(), "func_value");
+  assertEquals(o.accessor, "accessor_value");
+  assertEquals(o.property, "property_value");
+})();