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