Revision: 7252
Author:   [email protected]
Date:     Thu Mar 17 13:28:41 2011
Log: Implement strict mode ThrowTypeError functions for arguments object.
* Reverse order of arguments in-object fields for length and callee.
* Introduce arguments ThrowTypeError functions (caller/callee).
* Create strict mode arguments boilerplate object.
* Strict mode "new arguments object" stub.
* Runtime arguments object allocation.
* Update es5conform test expectations.

Review URL: http://codereview.chromium.org/6698015/
http://code.google.com/p/v8/source/detail?r=7252

Modified:
 /branches/bleeding_edge/src/arm/code-stubs-arm.cc
 /branches/bleeding_edge/src/arm/codegen-arm.cc
 /branches/bleeding_edge/src/arm/codegen-arm.h
 /branches/bleeding_edge/src/arm/full-codegen-arm.cc
 /branches/bleeding_edge/src/bootstrapper.cc
 /branches/bleeding_edge/src/builtins.cc
 /branches/bleeding_edge/src/builtins.h
 /branches/bleeding_edge/src/code-stubs.h
 /branches/bleeding_edge/src/codegen-inl.h
 /branches/bleeding_edge/src/codegen.cc
 /branches/bleeding_edge/src/contexts.h
 /branches/bleeding_edge/src/heap.cc
 /branches/bleeding_edge/src/heap.h
 /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc
 /branches/bleeding_edge/src/ia32/codegen-ia32.cc
 /branches/bleeding_edge/src/ia32/codegen-ia32.h
 /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc
 /branches/bleeding_edge/src/messages.js
 /branches/bleeding_edge/src/runtime.cc
 /branches/bleeding_edge/src/x64/code-stubs-x64.cc
 /branches/bleeding_edge/src/x64/codegen-x64.cc
 /branches/bleeding_edge/src/x64/codegen-x64.h
 /branches/bleeding_edge/src/x64/full-codegen-x64.cc
 /branches/bleeding_edge/test/es5conform/es5conform.status
 /branches/bleeding_edge/test/mjsunit/strict-mode.js

=======================================
--- /branches/bleeding_edge/src/arm/code-stubs-arm.cc Thu Mar 17 13:28:30 2011 +++ /branches/bleeding_edge/src/arm/code-stubs-arm.cc Thu Mar 17 13:28:41 2011
@@ -4788,7 +4788,7 @@
   __ mov(r1, Operand(r1, LSR, kSmiTagSize));
   __ add(r1, r1, Operand(FixedArray::kHeaderSize / kPointerSize));
   __ bind(&add_arguments_object);
-  __ add(r1, r1, Operand(Heap::kArgumentsObjectSize / kPointerSize));
+  __ add(r1, r1, Operand(GetArgumentsObjectSize() / kPointerSize));

   // Do the allocation of both objects in one go.
   __ AllocateInNewSpace(
@@ -4800,23 +4800,28 @@
       static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS));

   // Get the arguments boilerplate from the current (global) context.
-  int offset = Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX);
   __ ldr(r4, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
   __ ldr(r4, FieldMemOperand(r4, GlobalObject::kGlobalContextOffset));
-  __ ldr(r4, MemOperand(r4, offset));
+  __ ldr(r4, MemOperand(r4,
+ Context::SlotOffset(GetArgumentsBoilerplateIndex())));

   // Copy the JS object part.
   __ CopyFields(r0, r4, r3.bit(), JSObject::kHeaderSize / kPointerSize);

-  // Setup the callee in-object property.
-  STATIC_ASSERT(Heap::arguments_callee_index == 0);
-  __ ldr(r3, MemOperand(sp, 2 * kPointerSize));
-  __ str(r3, FieldMemOperand(r0, JSObject::kHeaderSize));
+  if (type_ == NEW_NON_STRICT) {
+    // Setup the callee in-object property.
+    STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1);
+    __ ldr(r3, MemOperand(sp, 2 * kPointerSize));
+    const int kCalleeOffset = JSObject::kHeaderSize +
+                              Heap::kArgumentsCalleeIndex * kPointerSize;
+    __ str(r3, FieldMemOperand(r0, kCalleeOffset));
+  }

   // Get the length (smi tagged) and set that as an in-object property too.
-  STATIC_ASSERT(Heap::arguments_length_index == 1);
+  STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
   __ ldr(r1, MemOperand(sp, 0 * kPointerSize));
-  __ str(r1, FieldMemOperand(r0, JSObject::kHeaderSize + kPointerSize));
+  __ str(r1, FieldMemOperand(r0, JSObject::kHeaderSize +
+ Heap::kArgumentsLengthIndex * kPointerSize));

   // If there are no actual arguments, we're done.
   Label done;
@@ -4828,7 +4833,7 @@

   // Setup the elements pointer in the allocated arguments object and
   // initialize the header in the elements fixed array.
-  __ add(r4, r0, Operand(Heap::kArgumentsObjectSize));
+  __ add(r4, r0, Operand(GetArgumentsObjectSize()));
   __ str(r4, FieldMemOperand(r0, JSObject::kElementsOffset));
   __ LoadRoot(r3, Heap::kFixedArrayMapRootIndex);
   __ str(r3, FieldMemOperand(r4, FixedArray::kMapOffset));
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.cc      Thu Mar 17 13:28:30 2011
+++ /branches/bleeding_edge/src/arm/codegen-arm.cc      Thu Mar 17 13:28:41 2011
@@ -601,7 +601,9 @@
     frame_->EmitPushRoot(Heap::kArgumentsMarkerRootIndex);
   } else {
     frame_->SpillAll();
-    ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
+    ArgumentsAccessStub stub(is_strict_mode()
+        ? ArgumentsAccessStub::NEW_STRICT
+        : ArgumentsAccessStub::NEW_NON_STRICT);
     __ ldr(r2, frame_->Function());
     // The receiver is below the arguments, the return address, and the
     // frame pointer on the stack.
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.h       Tue Mar 15 03:03:57 2011
+++ /branches/bleeding_edge/src/arm/codegen-arm.h       Thu Mar 17 13:28:41 2011
@@ -287,6 +287,7 @@
   // Accessors
   inline bool is_eval();
   inline Scope* scope();
+  inline bool is_strict_mode();
   inline StrictModeFlag strict_mode_flag();

   // Generating deferred code.
=======================================
--- /branches/bleeding_edge/src/arm/full-codegen-arm.cc Thu Mar 17 13:28:30 2011 +++ /branches/bleeding_edge/src/arm/full-codegen-arm.cc Thu Mar 17 13:28:41 2011
@@ -210,7 +210,9 @@
     //   function, receiver address, parameter count.
     // The stub will rewrite receiever and parameter count if the previous
     // stack frame was an arguments adapter frame.
-    ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
+    ArgumentsAccessStub stub(
+        is_strict_mode() ? ArgumentsAccessStub::NEW_STRICT
+                         : ArgumentsAccessStub::NEW_NON_STRICT);
     __ CallStub(&stub);

     Variable* arguments_shadow = scope()->arguments_shadow();
=======================================
--- /branches/bleeding_edge/src/bootstrapper.cc Thu Mar 17 13:28:17 2011
+++ /branches/bleeding_edge/src/bootstrapper.cc Thu Mar 17 13:28:41 2011
@@ -1021,12 +1021,12 @@
     Handle<JSObject> result = Factory::NewJSObject(function);

     global_context()->set_arguments_boilerplate(*result);
-    // Note: callee must be added as the first property and
-    //       length must be added as the second property.
-    SetLocalPropertyNoThrow(result, Factory::callee_symbol(),
+    // Note: length must be added as the first property and
+    //       callee must be added as the second property.
+    SetLocalPropertyNoThrow(result, Factory::length_symbol(),
                             Factory::undefined_value(),
                             DONT_ENUM);
-    SetLocalPropertyNoThrow(result, Factory::length_symbol(),
+    SetLocalPropertyNoThrow(result, Factory::callee_symbol(),
                             Factory::undefined_value(),
                             DONT_ENUM);

@@ -1034,14 +1034,85 @@
     LookupResult lookup;
     result->LocalLookup(Heap::callee_symbol(), &lookup);
     ASSERT(lookup.IsProperty() && (lookup.type() == FIELD));
-    ASSERT(lookup.GetFieldIndex() == Heap::arguments_callee_index);
+    ASSERT(lookup.GetFieldIndex() == Heap::kArgumentsCalleeIndex);

     result->LocalLookup(Heap::length_symbol(), &lookup);
     ASSERT(lookup.IsProperty() && (lookup.type() == FIELD));
-    ASSERT(lookup.GetFieldIndex() == Heap::arguments_length_index);
-
- ASSERT(result->map()->inobject_properties() > Heap::arguments_callee_index); - ASSERT(result->map()->inobject_properties() > Heap::arguments_length_index);
+    ASSERT(lookup.GetFieldIndex() == Heap::kArgumentsLengthIndex);
+
+ ASSERT(result->map()->inobject_properties() > Heap::kArgumentsCalleeIndex); + ASSERT(result->map()->inobject_properties() > Heap::kArgumentsLengthIndex);
+
+    // Check the state of the object.
+    ASSERT(result->HasFastProperties());
+    ASSERT(result->HasFastElements());
+#endif
+  }
+
+  {  // --- strict mode arguments boilerplate
+    const PropertyAttributes attributes =
+      static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
+
+    // Create the ThrowTypeError functions.
+    Handle<FixedArray> callee = Factory::NewFixedArray(2, TENURED);
+    Handle<FixedArray> caller = Factory::NewFixedArray(2, TENURED);
+
+    Handle<JSFunction> callee_throw =
+        CreateThrowTypeErrorFunction(Builtins::StrictArgumentsCallee);
+    Handle<JSFunction> caller_throw =
+        CreateThrowTypeErrorFunction(Builtins::StrictArgumentsCaller);
+
+    // Install the ThrowTypeError functions.
+    callee->set(0, *callee_throw);
+    callee->set(1, *callee_throw);
+    caller->set(0, *caller_throw);
+    caller->set(1, *caller_throw);
+
+    // Create the descriptor array for the arguments object.
+    Handle<DescriptorArray> descriptors = Factory::NewDescriptorArray(3);
+    {  // length
+      FieldDescriptor d(*Factory::length_symbol(), 0, DONT_ENUM);
+      descriptors->Set(0, &d);
+    }
+    {  // callee
+ CallbacksDescriptor d(*Factory::callee_symbol(), *callee, attributes);
+      descriptors->Set(1, &d);
+    }
+    {  // caller
+ CallbacksDescriptor d(*Factory::caller_symbol(), *caller, attributes);
+      descriptors->Set(2, &d);
+    }
+    descriptors->Sort();
+
+    // Create the map. Allocate one in-object field for length.
+    Handle<Map> map = Factory::NewMap(JS_OBJECT_TYPE,
+                                      Heap::kArgumentsObjectSizeStrict);
+    map->set_instance_descriptors(*descriptors);
+    map->set_function_with_prototype(true);
+    map->set_prototype(global_context()->object_function()->prototype());
+    map->set_pre_allocated_property_fields(1);
+    map->set_inobject_properties(1);
+
+    // Copy constructor from the non-strict arguments boilerplate.
+    map->set_constructor(
+      global_context()->arguments_boilerplate()->map()->constructor());
+
+    // Allocate the arguments boilerplate object.
+    Handle<JSObject> result = Factory::NewJSObjectFromMap(map);
+    global_context()->set_strict_mode_arguments_boilerplate(*result);
+
+    // Add length property only for strict mode boilerplate.
+    SetLocalPropertyNoThrow(result, Factory::length_symbol(),
+                            Factory::undefined_value(),
+                            DONT_ENUM);
+
+#ifdef DEBUG
+    LookupResult lookup;
+    result->LocalLookup(Heap::length_symbol(), &lookup);
+    ASSERT(lookup.IsProperty() && (lookup.type() == FIELD));
+    ASSERT(lookup.GetFieldIndex() == Heap::kArgumentsLengthIndex);
+
+ ASSERT(result->map()->inobject_properties() > Heap::kArgumentsLengthIndex);

     // Check the state of the object.
     ASSERT(result->HasFastProperties());
=======================================
--- /branches/bleeding_edge/src/builtins.cc     Thu Mar 17 13:28:17 2011
+++ /branches/bleeding_edge/src/builtins.cc     Thu Mar 17 13:28:41 2011
@@ -640,7 +640,7 @@
     }
     elms = FixedArray::cast(JSObject::cast(receiver)->elements());
     Object* len_obj = JSObject::cast(receiver)
-        ->InObjectPropertyAt(Heap::arguments_length_index);
+        ->InObjectPropertyAt(Heap::kArgumentsLengthIndex);
     if (!len_obj->IsSmi()) {
       return CallJsBuiltin("ArraySlice", args);
     }
@@ -962,6 +962,20 @@
 // Strict mode poison pills


+BUILTIN(StrictArgumentsCallee) {
+  HandleScope scope;
+  return Top::Throw(*Factory::NewTypeError("strict_arguments_callee",
+                                           HandleVector<Object>(NULL, 0)));
+}
+
+
+BUILTIN(StrictArgumentsCaller) {
+  HandleScope scope;
+  return Top::Throw(*Factory::NewTypeError("strict_arguments_caller",
+                                           HandleVector<Object>(NULL, 0)));
+}
+
+
 BUILTIN(StrictFunctionCaller) {
   HandleScope scope;
   return Top::Throw(*Factory::NewTypeError("strict_function_caller",
=======================================
--- /branches/bleeding_edge/src/builtins.h      Thu Mar 17 13:28:17 2011
+++ /branches/bleeding_edge/src/builtins.h      Thu Mar 17 13:28:41 2011
@@ -60,6 +60,8 @@
   V(HandleApiCallAsFunction, NO_EXTRA_ARGUMENTS)                    \
   V(HandleApiCallAsConstructor, NO_EXTRA_ARGUMENTS)                 \
                                                                     \
+  V(StrictArgumentsCallee, NO_EXTRA_ARGUMENTS)                      \
+  V(StrictArgumentsCaller, NO_EXTRA_ARGUMENTS)                      \
   V(StrictFunctionCaller, NO_EXTRA_ARGUMENTS)                       \
   V(StrictFunctionArguments, NO_EXTRA_ARGUMENTS)

=======================================
--- /branches/bleeding_edge/src/code-stubs.h    Thu Mar 17 13:28:30 2011
+++ /branches/bleeding_edge/src/code-stubs.h    Thu Mar 17 13:28:41 2011
@@ -659,7 +659,8 @@
  public:
   enum Type {
     READ_ELEMENT,
-    NEW_OBJECT
+    NEW_NON_STRICT,
+    NEW_STRICT
   };

   explicit ArgumentsAccessStub(Type type) : type_(type) { }
@@ -674,6 +675,18 @@
   void GenerateReadElement(MacroAssembler* masm);
   void GenerateNewObject(MacroAssembler* masm);

+  int GetArgumentsBoilerplateIndex() const {
+  return (type_ == NEW_STRICT)
+      ? Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX
+      : Context::ARGUMENTS_BOILERPLATE_INDEX;
+  }
+
+  int GetArgumentsObjectSize() const {
+    return (type_ == NEW_STRICT)
+        ? Heap::kArgumentsObjectSizeStrict
+        : Heap::kArgumentsObjectSize;
+  }
+
   const char* GetName() { return "ArgumentsAccessStub"; }

 #ifdef DEBUG
=======================================
--- /branches/bleeding_edge/src/codegen-inl.h   Fri Feb  4 10:15:49 2011
+++ /branches/bleeding_edge/src/codegen-inl.h   Thu Mar 17 13:28:41 2011
@@ -54,9 +54,13 @@
 bool CodeGenerator::is_eval() { return info_->is_eval(); }

 Scope* CodeGenerator::scope() { return info_->function()->scope(); }
+
+bool CodeGenerator::is_strict_mode() {
+  return info_->function()->strict_mode();
+}

 StrictModeFlag CodeGenerator::strict_mode_flag() {
-  return info_->function()->strict_mode() ? kStrictMode : kNonStrictMode;
+  return is_strict_mode() ? kStrictMode : kNonStrictMode;
 }

 } }  // namespace v8::internal
=======================================
--- /branches/bleeding_edge/src/codegen.cc      Fri Feb 11 04:25:41 2011
+++ /branches/bleeding_edge/src/codegen.cc      Thu Mar 17 13:28:41 2011
@@ -475,8 +475,13 @@

 void ArgumentsAccessStub::Generate(MacroAssembler* masm) {
   switch (type_) {
-    case READ_ELEMENT: GenerateReadElement(masm); break;
-    case NEW_OBJECT: GenerateNewObject(masm); break;
+    case READ_ELEMENT:
+      GenerateReadElement(masm);
+      break;
+    case NEW_NON_STRICT:
+    case NEW_STRICT:
+      GenerateNewObject(masm);
+      break;
   }
 }

=======================================
--- /branches/bleeding_edge/src/contexts.h      Thu Mar 17 13:28:17 2011
+++ /branches/bleeding_edge/src/contexts.h      Thu Mar 17 13:28:41 2011
@@ -88,6 +88,8 @@
   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) \
+  V(STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX, JSObject, \
+    strict_mode_arguments_boilerplate) \
   V(MESSAGE_LISTENERS_INDEX, JSObject, message_listeners) \
   V(MAKE_MESSAGE_FUN_INDEX, JSFunction, make_message_fun) \
   V(GET_STACK_TRACE_LINE_INDEX, JSFunction, get_stack_trace_line_fun) \
@@ -187,6 +189,7 @@
     GLOBAL_PROXY_INDEX = MIN_CONTEXT_SLOTS,
     SECURITY_TOKEN_INDEX,
     ARGUMENTS_BOILERPLATE_INDEX,
+    STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX,
     JS_ARRAY_MAP_INDEX,
     REGEXP_RESULT_MAP_INDEX,
     FUNCTION_MAP_INDEX,
=======================================
--- /branches/bleeding_edge/src/heap.cc Thu Mar 10 04:00:27 2011
+++ /branches/bleeding_edge/src/heap.cc Thu Mar 17 13:28:41 2011
@@ -138,6 +138,9 @@

 GCTracer* Heap::tracer_ = NULL;

+const int Heap::kArgumentsObjectSize;
+const int Heap::kArgumentsObjectSizeStrict;
+
 int Heap::unflattened_strings_length_ = 0;

 int Heap::always_allocate_scope_depth_ = 0;
@@ -2897,23 +2900,33 @@
 MaybeObject* Heap::AllocateArgumentsObject(Object* callee, int length) {
   // To get fast allocation and map sharing for arguments objects we
   // allocate them based on an arguments boilerplate.
+
+  JSObject* boilerplate;
+  int arguments_object_size;
+  bool strict_mode_callee = callee->IsJSFunction() &&
+ JSFunction::cast(callee)->shared()->strict_mode();
+  if (strict_mode_callee) {
+    boilerplate =
+ Top::context()->global_context()->strict_mode_arguments_boilerplate();
+    arguments_object_size = kArgumentsObjectSizeStrict;
+  } else {
+ boilerplate = Top::context()->global_context()->arguments_boilerplate();
+    arguments_object_size = kArgumentsObjectSize;
+  }

   // This calls Copy directly rather than using Heap::AllocateRaw so we
   // duplicate the check here.
   ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);

-  JSObject* boilerplate =
-      Top::context()->global_context()->arguments_boilerplate();
-
   // Check that the size of the boilerplate matches our
   // expectations. The ArgumentsAccessStub::GenerateNewObject relies
   // on the size being a known constant.
-  ASSERT(kArgumentsObjectSize == boilerplate->map()->instance_size());
+  ASSERT(arguments_object_size == boilerplate->map()->instance_size());

   // Do the allocation.
   Object* result;
   { MaybeObject* maybe_result =
-        AllocateRaw(kArgumentsObjectSize, NEW_SPACE, OLD_POINTER_SPACE);
+        AllocateRaw(arguments_object_size, NEW_SPACE, OLD_POINTER_SPACE);
     if (!maybe_result->ToObject(&result)) return maybe_result;
   }

@@ -2922,14 +2935,17 @@
   // barrier here.
   CopyBlock(HeapObject::cast(result)->address(),
             boilerplate->address(),
-            kArgumentsObjectSize);
-
-  // Set the two properties.
-  JSObject::cast(result)->InObjectPropertyAtPut(arguments_callee_index,
-                                                callee);
-  JSObject::cast(result)->InObjectPropertyAtPut(arguments_length_index,
+            JSObject::kHeaderSize);
+
+  // Set the length property.
+  JSObject::cast(result)->InObjectPropertyAtPut(kArgumentsLengthIndex,
                                                 Smi::FromInt(length),
                                                 SKIP_WRITE_BARRIER);
+  // Set the callee property for non-strict mode arguments object only.
+  if (!strict_mode_callee) {
+    JSObject::cast(result)->InObjectPropertyAtPut(kArgumentsCalleeIndex,
+                                                  callee);
+  }

   // Check the state of the object
   ASSERT(JSObject::cast(result)->HasFastProperties());
=======================================
--- /branches/bleeding_edge/src/heap.h  Thu Mar 10 04:05:31 2011
+++ /branches/bleeding_edge/src/heap.h  Thu Mar 17 13:28:41 2011
@@ -583,11 +583,16 @@
       Object* prototype,
       PretenureFlag pretenure = TENURED);

-  // Indicies for direct access into argument objects.
+  // Arguments object size.
   static const int kArgumentsObjectSize =
       JSObject::kHeaderSize + 2 * kPointerSize;
-  static const int arguments_callee_index = 0;
-  static const int arguments_length_index = 1;
+  // Strict mode arguments has no callee so it is smaller.
+  static const int kArgumentsObjectSizeStrict =
+      JSObject::kHeaderSize + 1 * kPointerSize;
+  // Indicies for direct access into argument objects.
+  static const int kArgumentsLengthIndex = 0;
+  // callee is only valid in non-strict mode.
+  static const int kArgumentsCalleeIndex = 1;

   // Allocates an arguments object - optionally with an elements array.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
=======================================
--- /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Thu Mar 17 13:28:30 2011 +++ /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Thu Mar 17 13:28:41 2011
@@ -3632,16 +3632,16 @@
   __ j(zero, &add_arguments_object);
   __ lea(ecx, Operand(ecx, times_2, FixedArray::kHeaderSize));
   __ bind(&add_arguments_object);
-  __ add(Operand(ecx), Immediate(Heap::kArgumentsObjectSize));
+  __ add(Operand(ecx), Immediate(GetArgumentsObjectSize()));

   // Do the allocation of both objects in one go.
   __ AllocateInNewSpace(ecx, eax, edx, ebx, &runtime, TAG_OBJECT);

   // Get the arguments boilerplate from the current (global) context.
-  int offset = Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX);
   __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
   __ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset));
-  __ mov(edi, Operand(edi, offset));
+  __ mov(edi, Operand(edi,
+ Context::SlotOffset(GetArgumentsBoilerplateIndex())));

   // Copy the JS object part.
   for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) {
@@ -3649,15 +3649,21 @@
     __ mov(FieldOperand(eax, i), ebx);
   }

-  // Setup the callee in-object property.
-  STATIC_ASSERT(Heap::arguments_callee_index == 0);
-  __ mov(ebx, Operand(esp, 3 * kPointerSize));
-  __ mov(FieldOperand(eax, JSObject::kHeaderSize), ebx);
+  if (type_ == NEW_NON_STRICT) {
+    // Setup the callee in-object property.
+    STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1);
+    __ mov(ebx, Operand(esp, 3 * kPointerSize));
+    __ mov(FieldOperand(eax, JSObject::kHeaderSize +
+                             Heap::kArgumentsCalleeIndex * kPointerSize),
+           ebx);
+  }

   // Get the length (smi tagged) and set that as an in-object property too.
-  STATIC_ASSERT(Heap::arguments_length_index == 1);
+  STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
   __ mov(ecx, Operand(esp, 1 * kPointerSize));
-  __ mov(FieldOperand(eax, JSObject::kHeaderSize + kPointerSize), ecx);
+  __ mov(FieldOperand(eax, JSObject::kHeaderSize +
+                           Heap::kArgumentsLengthIndex * kPointerSize),
+         ecx);

   // If there are no actual arguments, we're done.
   Label done;
@@ -3669,10 +3675,11 @@

   // Setup the elements pointer in the allocated arguments object and
   // initialize the header in the elements fixed array.
-  __ lea(edi, Operand(eax, Heap::kArgumentsObjectSize));
+  __ lea(edi, Operand(eax, GetArgumentsObjectSize()));
   __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi);
   __ mov(FieldOperand(edi, FixedArray::kMapOffset),
          Immediate(Factory::fixed_array_map()));
+
   __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx);
   // Untag the length for the loop below.
   __ SmiUntag(ecx);
=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.cc Thu Mar 17 13:28:30 2011 +++ /branches/bleeding_edge/src/ia32/codegen-ia32.cc Thu Mar 17 13:28:41 2011
@@ -753,7 +753,9 @@
     // allocated yet.
     frame_->Push(Factory::arguments_marker());
   } else {
-    ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
+    ArgumentsAccessStub stub(is_strict_mode()
+        ? ArgumentsAccessStub::NEW_STRICT
+        : ArgumentsAccessStub::NEW_NON_STRICT);
     frame_->PushFunction();
     frame_->PushReceiverSlotAddress();
     frame_->Push(Smi::FromInt(scope()->num_parameters()));
=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.h     Fri Feb  4 10:15:49 2011
+++ /branches/bleeding_edge/src/ia32/codegen-ia32.h     Thu Mar 17 13:28:41 2011
@@ -365,6 +365,7 @@
   // Accessors
   inline bool is_eval();
   inline Scope* scope();
+  inline bool is_strict_mode();
   inline StrictModeFlag strict_mode_flag();

   // Generating deferred code.
=======================================
--- /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Thu Mar 17 13:28:30 2011 +++ /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Thu Mar 17 13:28:41 2011
@@ -197,7 +197,9 @@
     //   function, receiver address, parameter count.
     // The stub will rewrite receiver and parameter count if the previous
     // stack frame was an arguments adapter frame.
-    ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
+    ArgumentsAccessStub stub(
+        is_strict_mode() ? ArgumentsAccessStub::NEW_STRICT
+                         : ArgumentsAccessStub::NEW_NON_STRICT);
     __ CallStub(&stub);

     Variable* arguments_shadow = scope()->arguments_shadow();
=======================================
--- /branches/bleeding_edge/src/messages.js     Thu Mar 17 13:28:17 2011
+++ /branches/bleeding_edge/src/messages.js     Thu Mar 17 13:28:41 2011
@@ -230,6 +230,8 @@
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_arguments_callee: ["Cannot access property 'callee' of strict mode arguments"], + strict_arguments_caller: ["Cannot access property 'caller' of strict mode arguments"], strict_function_caller: ["Cannot access property 'caller' of a strict mode function"], strict_function_arguments: ["Cannot access property 'arguments' of a strict mode function"],
     };
=======================================
--- /branches/bleeding_edge/src/runtime.cc      Thu Mar 17 13:28:17 2011
+++ /branches/bleeding_edge/src/runtime.cc      Thu Mar 17 13:28:41 2011
@@ -4380,7 +4380,15 @@

   // Handle special arguments properties.
   if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
-  if (key->Equals(Heap::callee_symbol())) return frame->function();
+  if (key->Equals(Heap::callee_symbol())) {
+    Object* function = frame->function();
+    if (function->IsJSFunction() &&
+        JSFunction::cast(function)->shared()->strict_mode()) {
+      return Top::Throw(*Factory::NewTypeError("strict_arguments_callee",
+ HandleVector<Object>(NULL, 0)));
+    }
+    return function;
+  }

   // Lookup in the initial Object.prototype object.
   return Top::initial_object_prototype()->GetProperty(*key);
=======================================
--- /branches/bleeding_edge/src/x64/code-stubs-x64.cc Thu Mar 17 13:28:30 2011 +++ /branches/bleeding_edge/src/x64/code-stubs-x64.cc Thu Mar 17 13:28:41 2011
@@ -2338,16 +2338,16 @@
   __ j(zero, &add_arguments_object);
   __ leal(rcx, Operand(rcx, times_pointer_size, FixedArray::kHeaderSize));
   __ bind(&add_arguments_object);
-  __ addl(rcx, Immediate(Heap::kArgumentsObjectSize));
+  __ addl(rcx, Immediate(GetArgumentsObjectSize()));

   // Do the allocation of both objects in one go.
   __ AllocateInNewSpace(rcx, rax, rdx, rbx, &runtime, TAG_OBJECT);

   // Get the arguments boilerplate from the current (global) context.
-  int offset = Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX);
   __ movq(rdi, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
   __ movq(rdi, FieldOperand(rdi, GlobalObject::kGlobalContextOffset));
-  __ movq(rdi, Operand(rdi, offset));
+  __ movq(rdi, Operand(rdi,
+ Context::SlotOffset(GetArgumentsBoilerplateIndex())));

   // Copy the JS object part.
   STATIC_ASSERT(JSObject::kHeaderSize == 3 * kPointerSize);
@@ -2358,15 +2358,21 @@
   __ movq(FieldOperand(rax, 1 * kPointerSize), rdx);
   __ movq(FieldOperand(rax, 2 * kPointerSize), rbx);

-  // Setup the callee in-object property.
-  ASSERT(Heap::arguments_callee_index == 0);
-  __ movq(kScratchRegister, Operand(rsp, 3 * kPointerSize));
-  __ movq(FieldOperand(rax, JSObject::kHeaderSize), kScratchRegister);
+  if (type_ == NEW_NON_STRICT) {
+    // Setup the callee in-object property.
+    ASSERT(Heap::kArgumentsCalleeIndex == 1);
+    __ movq(kScratchRegister, Operand(rsp, 3 * kPointerSize));
+    __ movq(FieldOperand(rax, JSObject::kHeaderSize +
+                              Heap::kArgumentsCalleeIndex * kPointerSize),
+            kScratchRegister);
+  }

   // Get the length (smi tagged) and set that as an in-object property too.
-  ASSERT(Heap::arguments_length_index == 1);
+  ASSERT(Heap::kArgumentsLengthIndex == 0);
   __ movq(rcx, Operand(rsp, 1 * kPointerSize));
-  __ movq(FieldOperand(rax, JSObject::kHeaderSize + kPointerSize), rcx);
+  __ movq(FieldOperand(rax, JSObject::kHeaderSize +
+                            Heap::kArgumentsLengthIndex * kPointerSize),
+          rcx);

   // If there are no actual arguments, we're done.
   Label done;
@@ -2378,7 +2384,7 @@

   // Setup the elements pointer in the allocated arguments object and
   // initialize the header in the elements fixed array.
-  __ lea(rdi, Operand(rax, Heap::kArgumentsObjectSize));
+  __ lea(rdi, Operand(rax, GetArgumentsObjectSize()));
   __ movq(FieldOperand(rax, JSObject::kElementsOffset), rdi);
   __ LoadRoot(kScratchRegister, Heap::kFixedArrayMapRootIndex);
   __ movq(FieldOperand(rdi, FixedArray::kMapOffset), kScratchRegister);
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.cc      Thu Mar 17 13:28:30 2011
+++ /branches/bleeding_edge/src/x64/codegen-x64.cc      Thu Mar 17 13:28:41 2011
@@ -634,7 +634,9 @@
     // allocated yet.
     frame_->Push(Factory::arguments_marker());
   } else {
-    ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
+    ArgumentsAccessStub stub(is_strict_mode()
+        ? ArgumentsAccessStub::NEW_STRICT
+        : ArgumentsAccessStub::NEW_NON_STRICT);
     frame_->PushFunction();
     frame_->PushReceiverSlotAddress();
     frame_->Push(Smi::FromInt(scope()->num_parameters()));
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.h       Fri Feb 25 05:22:38 2011
+++ /branches/bleeding_edge/src/x64/codegen-x64.h       Thu Mar 17 13:28:41 2011
@@ -357,6 +357,7 @@
   // Accessors
   inline bool is_eval();
   inline Scope* scope();
+  inline bool is_strict_mode();
   inline StrictModeFlag strict_mode_flag();

   // Generating deferred code.
=======================================
--- /branches/bleeding_edge/src/x64/full-codegen-x64.cc Thu Mar 17 13:28:30 2011 +++ /branches/bleeding_edge/src/x64/full-codegen-x64.cc Thu Mar 17 13:28:41 2011
@@ -198,7 +198,9 @@
     //   function, receiver address, parameter count.
     // The stub will rewrite receiver and parameter count if the previous
     // stack frame was an arguments adapter frame.
-    ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
+    ArgumentsAccessStub stub(
+        is_strict_mode() ? ArgumentsAccessStub::NEW_STRICT
+                         : ArgumentsAccessStub::NEW_NON_STRICT);
     __ CallStub(&stub);

     Variable* arguments_shadow = scope()->arguments_shadow();
=======================================
--- /branches/bleeding_edge/test/es5conform/es5conform.status Mon Mar 7 11:23:46 2011 +++ /branches/bleeding_edge/test/es5conform/es5conform.status Thu Mar 17 13:28:41 2011
@@ -239,15 +239,11 @@
 # Incorrect test - need double escape in eval.
 chapter07/7.8/7.8.4/7.8.4-1-s: FAIL

-# Accessing caller property of Arguments object throws TypeError in strict mode
-chapter10/10.6/10.6-13-b-1-s: FAIL
-# arguments.caller exists in strict mode
-chapter10/10.6/10.6-13-b-2-s: FAIL
 # arguments.caller is non-configurable in strict mode
+# Invalid test case. Checks for "writable == true" and presence of "put"..
 chapter10/10.6/10.6-13-b-3-s: FAIL
-# Accessing callee property of Arguments object throws TypeError in strict mode
-chapter10/10.6/10.6-13-c-1-s: FAIL
 # arguments.callee is non-configurable in strict mode
+# Invalid test case. Checks for "put" property accessor.
 chapter10/10.6/10.6-13-c-3-s: FAIL

# simple assignment throws TypeError if LeftHandSide is a property reference
=======================================
--- /branches/bleeding_edge/test/mjsunit/strict-mode.js Thu Mar 17 13:28:17 2011 +++ /branches/bleeding_edge/test/mjsunit/strict-mode.js Thu Mar 17 13:28:41 2011
@@ -978,20 +978,7 @@
 })();


-(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 CheckPillDescriptor(func, name) {

   function CheckPill(pill) {
     assertEquals("function", typeof pill);
@@ -1005,13 +992,28 @@
     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);
-  }
+  var descriptor = Object.getOwnPropertyDescriptor(func, name);
+  CheckPill(descriptor.get)
+  CheckPill(descriptor.set);
+  assertFalse(descriptor.enumerable);
+  assertFalse(descriptor.configurable);
+}
+
+
+(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);

   CheckPillDescriptor(strict, "caller");
   CheckPillDescriptor(strict, "arguments");
@@ -1041,3 +1043,41 @@
   assertEquals(o.accessor, "accessor_value");
   assertEquals(o.property, "property_value");
 })();
+
+
+(function TestStrictArgumentPills() {
+  function strict() {
+    "use strict";
+    return arguments;
+  }
+
+  var args = strict();
+  CheckPillDescriptor(args, "caller");
+  CheckPillDescriptor(args, "callee");
+
+  args = strict(17, "value", strict);
+  assertEquals(17, args[0])
+  assertEquals("value", args[1])
+  assertEquals(strict, args[2]);
+  CheckPillDescriptor(args, "caller");
+  CheckPillDescriptor(args, "callee");
+
+  function outer() {
+    "use strict";
+    function inner() {
+      return arguments;
+    }
+    return inner;
+  }
+
+  var args = outer()();
+  CheckPillDescriptor(args, "caller");
+  CheckPillDescriptor(args, "callee");
+
+  args = outer()(17, "value", strict);
+  assertEquals(17, args[0])
+  assertEquals("value", args[1])
+  assertEquals(strict, args[2]);
+  CheckPillDescriptor(args, "caller");
+  CheckPillDescriptor(args, "callee");
+})();

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to