| Index: src/arm/codegen-arm.cc
|
| ===================================================================
|
| --- src/arm/codegen-arm.cc (revision 7180)
|
| +++ src/arm/codegen-arm.cc (working copy)
|
| @@ -581,11 +581,13 @@
|
|
|
| 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;
|
| }
|
| @@ -619,7 +621,9 @@
|
| 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;
|
| if (mode == LAZY_ARGUMENTS_ALLOCATION && !initial) {
|
| // We have to skip storing into the arguments slot if it has
|
| @@ -633,7 +637,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);
|
| + }
|
| }
|
|
|
|
|
| @@ -1942,8 +1948,9 @@
|
| frame_->EmitPush(cp);
|
| frame_->EmitPush(Operand(pairs));
|
| frame_->EmitPush(Operand(Smi::FromInt(is_eval() ? 1 : 0)));
|
| + frame_->EmitPush(Operand(Smi::FromInt(strict_mode_flag())));
|
|
|
| - frame_->CallRuntime(Runtime::kDeclareGlobals, 3);
|
| + frame_->CallRuntime(Runtime::kDeclareGlobals, 4);
|
| // The result is discarded.
|
| }
|
|
|
| @@ -3291,7 +3298,8 @@
|
| // context slot followed by initialization.
|
| frame_->CallRuntime(Runtime::kInitializeConstContextSlot, 3);
|
| } else {
|
| - frame_->CallRuntime(Runtime::kStoreContextSlot, 3);
|
| + frame_->EmitPush(Operand(Smi::FromInt(strict_mode_flag())));
|
| + frame_->CallRuntime(Runtime::kStoreContextSlot, 4);
|
| }
|
| // Storing a variable must keep the (new) value on the expression
|
| // stack. This is necessary for compiling assignment expressions.
|
| @@ -3643,7 +3651,8 @@
|
| Load(key);
|
| Load(value);
|
| if (property->emit_store()) {
|
| - frame_->CallRuntime(Runtime::kSetProperty, 3);
|
| + frame_->EmitPush(Operand(Smi::FromInt(NONE))); // PropertyAttributes
|
| + frame_->CallRuntime(Runtime::kSetProperty, 4);
|
| } else {
|
| frame_->Drop(3);
|
| }
|
| @@ -5180,11 +5189,11 @@
|
|
|
| // Set the bit in the map to indicate that it has been checked safe for
|
| // default valueOf and set true result.
|
| - __ ldr(scratch1_, FieldMemOperand(map_result_, Map::kBitField2Offset));
|
| + __ ldrb(scratch1_, FieldMemOperand(map_result_, Map::kBitField2Offset));
|
| __ orr(scratch1_,
|
| scratch1_,
|
| Operand(1 << Map::kStringWrapperSafeForDefaultValueOf));
|
| - __ str(scratch1_, FieldMemOperand(map_result_, Map::kBitField2Offset));
|
| + __ strb(scratch1_, FieldMemOperand(map_result_, Map::kBitField2Offset));
|
| __ mov(map_result_, Operand(1));
|
| __ jmp(exit_label());
|
| __ bind(&false_result);
|
| @@ -5585,8 +5594,8 @@
|
| // Fetch the map and check if array is in fast case.
|
| // Check that object doesn't require security checks and
|
| // has no indexed interceptor.
|
| - __ CompareObjectType(object, tmp1, tmp2, FIRST_JS_OBJECT_TYPE);
|
| - deferred->Branch(lt);
|
| + __ CompareObjectType(object, tmp1, tmp2, JS_ARRAY_TYPE);
|
| + deferred->Branch(ne);
|
| __ ldrb(tmp2, FieldMemOperand(tmp1, Map::kBitFieldOffset));
|
| __ tst(tmp2, Operand(KeyedLoadIC::kSlowCaseBitFieldMask));
|
| deferred->Branch(ne);
|
| @@ -5668,7 +5677,8 @@
|
| ASSERT_EQ(args->length(), 1);
|
| Load(args->at(0));
|
| if (CpuFeatures::IsSupported(VFP3)) {
|
| - TranscendentalCacheStub stub(TranscendentalCache::SIN);
|
| + TranscendentalCacheStub stub(TranscendentalCache::SIN,
|
| + TranscendentalCacheStub::TAGGED);
|
| frame_->SpillAllButCopyTOSToR0();
|
| frame_->CallStub(&stub, 1);
|
| } else {
|
| @@ -5682,7 +5692,8 @@
|
| ASSERT_EQ(args->length(), 1);
|
| Load(args->at(0));
|
| if (CpuFeatures::IsSupported(VFP3)) {
|
| - TranscendentalCacheStub stub(TranscendentalCache::COS);
|
| + TranscendentalCacheStub stub(TranscendentalCache::COS,
|
| + TranscendentalCacheStub::TAGGED);
|
| frame_->SpillAllButCopyTOSToR0();
|
| frame_->CallStub(&stub, 1);
|
| } else {
|
| @@ -5696,7 +5707,8 @@
|
| ASSERT_EQ(args->length(), 1);
|
| Load(args->at(0));
|
| if (CpuFeatures::IsSupported(VFP3)) {
|
| - TranscendentalCacheStub stub(TranscendentalCache::LOG);
|
| + TranscendentalCacheStub stub(TranscendentalCache::LOG,
|
| + TranscendentalCacheStub::TAGGED);
|
| frame_->SpillAllButCopyTOSToR0();
|
| frame_->CallStub(&stub, 1);
|
| } else {
|
| @@ -5862,8 +5874,8 @@
|
|
|
| } else 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();
|
| @@ -6686,8 +6698,12 @@
|
| public:
|
| DeferredReferenceSetKeyedValue(Register value,
|
| Register key,
|
| - Register receiver)
|
| - : value_(value), key_(key), receiver_(receiver) {
|
| + Register receiver,
|
| + StrictModeFlag strict_mode)
|
| + : value_(value),
|
| + key_(key),
|
| + receiver_(receiver),
|
| + strict_mode_(strict_mode) {
|
| set_comment("[ DeferredReferenceSetKeyedValue");
|
| }
|
|
|
| @@ -6697,6 +6713,7 @@
|
| Register value_;
|
| Register key_;
|
| Register receiver_;
|
| + StrictModeFlag strict_mode_;
|
| };
|
|
|
|
|
| @@ -6718,7 +6735,9 @@
|
| { Assembler::BlockConstPoolScope block_const_pool(masm_);
|
| // Call keyed store IC. It has the arguments value, key and receiver in r0,
|
| // r1 and r2.
|
| - 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 call must be followed by a nop instruction to indicate that the
|
| // keyed store has been inlined.
|
| @@ -6736,8 +6755,12 @@
|
| public:
|
| DeferredReferenceSetNamedValue(Register value,
|
| Register receiver,
|
| - Handle<String> name)
|
| - : value_(value), receiver_(receiver), name_(name) {
|
| + Handle<String> name,
|
| + StrictModeFlag strict_mode)
|
| + : value_(value),
|
| + receiver_(receiver),
|
| + name_(name),
|
| + strict_mode_(strict_mode) {
|
| set_comment("[ DeferredReferenceSetNamedValue");
|
| }
|
|
|
| @@ -6747,6 +6770,7 @@
|
| Register value_;
|
| Register receiver_;
|
| Handle<String> name_;
|
| + StrictModeFlag strict_mode_;
|
| };
|
|
|
|
|
| @@ -6766,7 +6790,9 @@
|
| { Assembler::BlockConstPoolScope block_const_pool(masm_);
|
| // Call keyed store IC. It has the arguments value, key and receiver in r0,
|
| // r1 and r2.
|
| - Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
| + Handle<Code> ic(Builtins::builtin(
|
| + (strict_mode_ == kStrictMode) ? Builtins::StoreIC_Initialize_Strict
|
| + : Builtins::StoreIC_Initialize));
|
| __ Call(ic, RelocInfo::CODE_TARGET);
|
| // The call must be followed by a nop instruction to indicate that the
|
| // named store has been inlined.
|
| @@ -6955,7 +6981,8 @@
|
| Register receiver = r1;
|
|
|
| DeferredReferenceSetNamedValue* deferred =
|
| - new DeferredReferenceSetNamedValue(value, receiver, name);
|
| + new DeferredReferenceSetNamedValue(
|
| + value, receiver, name, strict_mode_flag());
|
|
|
| // Check that the receiver is a heap object.
|
| __ tst(receiver, Operand(kSmiTagMask));
|
| @@ -7126,7 +7153,6 @@
|
| scratch1, scratch2);
|
|
|
|
|
| -
|
| // Load the value, key and receiver from the stack.
|
| bool value_is_harmless = frame_->KnownSmiAt(0);
|
| if (wb_info == NEVER_NEWSPACE) value_is_harmless = true;
|
| @@ -7143,7 +7169,8 @@
|
|
|
| // The deferred code expects value, key and receiver in registers.
|
| DeferredReferenceSetKeyedValue* deferred =
|
| - new DeferredReferenceSetKeyedValue(value, key, receiver);
|
| + new DeferredReferenceSetKeyedValue(
|
| + value, key, receiver, strict_mode_flag());
|
|
|
| // Check that the value is a smi. As this inlined code does not set the
|
| // write barrier it is only possible to store smi values.
|
| @@ -7173,12 +7200,6 @@
|
| __ CompareObjectType(receiver, scratch1, scratch1, JS_ARRAY_TYPE);
|
| deferred->Branch(ne);
|
|
|
| - // 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.
|
| - __ ldr(scratch1, FieldMemOperand(receiver, JSArray::kLengthOffset));
|
| - __ cmp(scratch1, key);
|
| - deferred->Branch(ls); // Unsigned less equal.
|
| -
|
| // Get the elements array from the receiver.
|
| __ ldr(scratch1, FieldMemOperand(receiver, JSObject::kElementsOffset));
|
| if (!value_is_harmless && wb_info != LIKELY_SMI) {
|
| @@ -7193,6 +7214,7 @@
|
| }
|
| // Check that the elements array is not a dictionary.
|
| __ ldr(scratch2, FieldMemOperand(scratch1, JSObject::kMapOffset));
|
| +
|
| // The following instructions are the part of the inlined store keyed
|
| // property code which can be patched. Therefore the exact number of
|
| // instructions generated need to be fixed, so the constant pool is blocked
|
| @@ -7212,6 +7234,14 @@
|
| __ cmp(scratch2, scratch3);
|
| deferred->Branch(ne);
|
|
|
| + // 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.
|
| + __ ldr(scratch3, FieldMemOperand(receiver, JSArray::kLengthOffset));
|
| + __ cmp(scratch3, key);
|
| + deferred->Branch(ls); // Unsigned less equal.
|
| +
|
| // Store the value.
|
| __ add(scratch1, scratch1,
|
| Operand(FixedArray::kHeaderSize - kHeapObjectTag));
|
| @@ -7228,7 +7258,7 @@
|
|
|
| deferred->BindExit();
|
| } else {
|
| - frame()->CallKeyedStoreIC();
|
| + frame()->CallKeyedStoreIC(strict_mode_flag());
|
| }
|
| }
|
|
|
|
|