| Index: src/ia32/codegen-ia32.cc
|
| ===================================================================
|
| --- src/ia32/codegen-ia32.cc (revision 7180)
|
| +++ src/ia32/codegen-ia32.cc (working copy)
|
| @@ -733,11 +733,14 @@
|
|
|
| ArgumentsAllocationMode CodeGenerator::ArgumentsMode() {
|
| if (scope()->arguments() == NULL) return NO_ARGUMENTS_ALLOCATION;
|
| - ASSERT(scope()->arguments_shadow() != NULL);
|
| +
|
| + // In strict mode there is no need for shadow arguments.
|
| + ASSERT(scope()->arguments_shadow() != NULL || scope()->is_strict_mode());
|
| +
|
| // We don't want to do lazy arguments allocation for functions that
|
| // have heap-allocated contexts, because it interfers with the
|
| // uninitialized const tracking in the context objects.
|
| - return (scope()->num_heap_slots() > 0)
|
| + return (scope()->num_heap_slots() > 0 || scope()->is_strict_mode())
|
| ? EAGER_ARGUMENTS_ALLOCATION
|
| : LAZY_ARGUMENTS_ALLOCATION;
|
| }
|
| @@ -764,8 +767,11 @@
|
|
|
| Variable* arguments = scope()->arguments();
|
| Variable* shadow = scope()->arguments_shadow();
|
| +
|
| ASSERT(arguments != NULL && arguments->AsSlot() != NULL);
|
| - ASSERT(shadow != NULL && shadow->AsSlot() != NULL);
|
| + ASSERT((shadow != NULL && shadow->AsSlot() != NULL) ||
|
| + scope()->is_strict_mode());
|
| +
|
| JumpTarget done;
|
| bool skip_arguments = false;
|
| if (mode == LAZY_ARGUMENTS_ALLOCATION && !initial) {
|
| @@ -788,7 +794,9 @@
|
| StoreToSlot(arguments->AsSlot(), NOT_CONST_INIT);
|
| if (mode == LAZY_ARGUMENTS_ALLOCATION) done.Bind();
|
| }
|
| - StoreToSlot(shadow->AsSlot(), NOT_CONST_INIT);
|
| + if (shadow != NULL) {
|
| + StoreToSlot(shadow->AsSlot(), NOT_CONST_INIT);
|
| + }
|
| return frame_->Pop();
|
| }
|
|
|
| @@ -3530,7 +3538,8 @@
|
| frame_->EmitPush(esi); // The context is the first argument.
|
| frame_->EmitPush(Immediate(pairs));
|
| frame_->EmitPush(Immediate(Smi::FromInt(is_eval() ? 1 : 0)));
|
| - Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 3);
|
| + frame_->EmitPush(Immediate(Smi::FromInt(strict_mode_flag())));
|
| + Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 4);
|
| // Return value is ignored.
|
| }
|
|
|
| @@ -5263,7 +5272,8 @@
|
| // by initialization.
|
| value = frame_->CallRuntime(Runtime::kInitializeConstContextSlot, 3);
|
| } else {
|
| - value = frame_->CallRuntime(Runtime::kStoreContextSlot, 3);
|
| + frame_->Push(Smi::FromInt(strict_mode_flag()));
|
| + value = frame_->CallRuntime(Runtime::kStoreContextSlot, 4);
|
| }
|
| // Storing a variable must keep the (new) value on the expression
|
| // stack. This is necessary for compiling chained assignment
|
| @@ -5369,10 +5379,20 @@
|
|
|
| void CodeGenerator::VisitLiteral(Literal* node) {
|
| Comment cmnt(masm_, "[ Literal");
|
| - if (in_safe_int32_mode()) {
|
| - frame_->PushUntaggedElement(node->handle());
|
| + if (frame_->ConstantPoolOverflowed()) {
|
| + Result temp = allocator_->Allocate();
|
| + ASSERT(temp.is_valid());
|
| + if (in_safe_int32_mode()) {
|
| + temp.set_untagged_int32(true);
|
| + }
|
| + __ Set(temp.reg(), Immediate(node->handle()));
|
| + frame_->Push(&temp);
|
| } else {
|
| - frame_->Push(node->handle());
|
| + if (in_safe_int32_mode()) {
|
| + frame_->PushUntaggedElement(node->handle());
|
| + } else {
|
| + frame_->Push(node->handle());
|
| + }
|
| }
|
| }
|
|
|
| @@ -5617,8 +5637,9 @@
|
| Load(property->key());
|
| Load(property->value());
|
| if (property->emit_store()) {
|
| + frame_->Push(Smi::FromInt(NONE)); // PropertyAttributes
|
| // Ignore the result.
|
| - Result ignored = frame_->CallRuntime(Runtime::kSetProperty, 3);
|
| + Result ignored = frame_->CallRuntime(Runtime::kSetProperty, 4);
|
| } else {
|
| frame_->Drop(3);
|
| }
|
| @@ -8249,8 +8270,8 @@
|
| Variable* variable = node->expression()->AsVariableProxy()->AsVariable();
|
| if (variable != NULL) {
|
| // Delete of an unqualified identifier is disallowed in strict mode
|
| - // so this code can only be reached in non-strict mode.
|
| - ASSERT(strict_mode_flag() == kNonStrictMode);
|
| + // but "delete this" is.
|
| + ASSERT(strict_mode_flag() == kNonStrictMode || variable->is_this());
|
| Slot* slot = variable->AsSlot();
|
| if (variable->is_global()) {
|
| LoadGlobal();
|
| @@ -8259,7 +8280,6 @@
|
| Result answer = frame_->InvokeBuiltin(Builtins::DELETE,
|
| CALL_FUNCTION, 3);
|
| frame_->Push(&answer);
|
| - return;
|
|
|
| } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
|
| // Call the runtime to delete from the context holding the named
|
| @@ -8270,13 +8290,11 @@
|
| frame_->EmitPush(Immediate(variable->name()));
|
| Result answer = frame_->CallRuntime(Runtime::kDeleteContextSlot, 2);
|
| frame_->Push(&answer);
|
| - return;
|
| + } else {
|
| + // Default: Result of deleting non-global, not dynamically
|
| + // introduced variables is false.
|
| + frame_->Push(Factory::false_value());
|
| }
|
| -
|
| - // Default: Result of deleting non-global, not dynamically
|
| - // introduced variables is false.
|
| - frame_->Push(Factory::false_value());
|
| -
|
| } else {
|
| // Default: Result of deleting expressions is true.
|
| Load(node->expression()); // may have side-effects
|
| @@ -8318,6 +8336,7 @@
|
| switch (op) {
|
| case Token::SUB: {
|
| __ neg(value.reg());
|
| + frame_->Push(&value);
|
| if (node->no_negative_zero()) {
|
| // -MIN_INT is MIN_INT with the overflow flag set.
|
| unsafe_bailout_->Branch(overflow);
|
| @@ -8330,17 +8349,18 @@
|
| }
|
| case Token::BIT_NOT: {
|
| __ not_(value.reg());
|
| + frame_->Push(&value);
|
| break;
|
| }
|
| case Token::ADD: {
|
| // Unary plus has no effect on int32 values.
|
| + frame_->Push(&value);
|
| break;
|
| }
|
| default:
|
| UNREACHABLE();
|
| break;
|
| }
|
| - frame_->Push(&value);
|
| } else {
|
| Load(node->expression());
|
| bool can_overwrite = node->expression()->ResultOverwriteAllowed();
|
| @@ -9476,11 +9496,13 @@
|
| DeferredReferenceSetKeyedValue(Register value,
|
| Register key,
|
| Register receiver,
|
| - Register scratch)
|
| + Register scratch,
|
| + StrictModeFlag strict_mode)
|
| : value_(value),
|
| key_(key),
|
| receiver_(receiver),
|
| - scratch_(scratch) {
|
| + scratch_(scratch),
|
| + strict_mode_(strict_mode) {
|
| set_comment("[ DeferredReferenceSetKeyedValue");
|
| }
|
|
|
| @@ -9494,6 +9516,7 @@
|
| Register receiver_;
|
| Register scratch_;
|
| Label patch_site_;
|
| + StrictModeFlag strict_mode_;
|
| };
|
|
|
|
|
| @@ -9552,7 +9575,9 @@
|
| }
|
|
|
| // Call the IC stub.
|
| - Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
|
| + Handle<Code> ic(Builtins::builtin(
|
| + (strict_mode_ == kStrictMode) ? Builtins::KeyedStoreIC_Initialize_Strict
|
| + : Builtins::KeyedStoreIC_Initialize));
|
| __ call(ic, RelocInfo::CODE_TARGET);
|
| // The delta from the start of the map-compare instruction to the
|
| // test instruction. We use masm_-> directly here instead of the
|
| @@ -9917,7 +9942,8 @@
|
| new DeferredReferenceSetKeyedValue(result.reg(),
|
| key.reg(),
|
| receiver.reg(),
|
| - tmp.reg());
|
| + tmp.reg(),
|
| + strict_mode_flag());
|
|
|
| // Check that the receiver is not a smi.
|
| __ test(receiver.reg(), Immediate(kSmiTagMask));
|
| @@ -9935,12 +9961,6 @@
|
| __ CmpObjectType(receiver.reg(), JS_ARRAY_TYPE, tmp.reg());
|
| deferred->Branch(not_equal);
|
|
|
| - // Check that the key is within bounds. Both the key and the length of
|
| - // the JSArray are smis. Use unsigned comparison to handle negative keys.
|
| - __ cmp(key.reg(),
|
| - FieldOperand(receiver.reg(), JSArray::kLengthOffset));
|
| - deferred->Branch(above_equal);
|
| -
|
| // Get the elements array from the receiver and check that it is not a
|
| // dictionary.
|
| __ mov(tmp.reg(),
|
| @@ -9967,13 +9987,21 @@
|
| Immediate(Factory::fixed_array_map()));
|
| deferred->Branch(not_equal);
|
|
|
| + // Check that the key is within bounds. Both the key and the length of
|
| + // the JSArray are smis (because the fixed array check above ensures the
|
| + // elements are in fast case). Use unsigned comparison to handle negative
|
| + // keys.
|
| + __ cmp(key.reg(),
|
| + FieldOperand(receiver.reg(), JSArray::kLengthOffset));
|
| + deferred->Branch(above_equal);
|
| +
|
| // Store the value.
|
| __ mov(FixedArrayElementOperand(tmp.reg(), key.reg()), result.reg());
|
| __ IncrementCounter(&Counters::keyed_store_inline, 1);
|
|
|
| deferred->BindExit();
|
| } else {
|
| - result = frame()->CallKeyedStoreIC();
|
| + result = frame()->CallKeyedStoreIC(strict_mode_flag());
|
| // Make sure that we do not have a test instruction after the
|
| // call. A test instruction after the call is used to
|
| // indicate that we have generated an inline version of the
|
|
|