| Index: src/x64/codegen-x64.cc
|
| ===================================================================
|
| --- src/x64/codegen-x64.cc (revision 7180)
|
| +++ src/x64/codegen-x64.cc (working copy)
|
| @@ -1,4 +1,4 @@
|
| -// Copyright 2010 the V8 project authors. All rights reserved.
|
| +// Copyright 2011 the V8 project authors. All rights reserved.
|
| // Redistribution and use in source and binary forms, with or without
|
| // modification, are permitted provided that the following conditions are
|
| // met:
|
| @@ -615,11 +615,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;
|
| }
|
| @@ -647,7 +649,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;
|
| bool skip_arguments = false;
|
| if (mode == LAZY_ARGUMENTS_ALLOCATION && !initial) {
|
| @@ -670,7 +674,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();
|
| }
|
|
|
| @@ -764,7 +770,7 @@
|
| __ AbortIfNotNumber(value.reg());
|
| }
|
| // Smi => false iff zero.
|
| - __ SmiCompare(value.reg(), Smi::FromInt(0));
|
| + __ Cmp(value.reg(), Smi::FromInt(0));
|
| if (value.is_smi()) {
|
| value.Unuse();
|
| dest->Split(not_zero);
|
| @@ -792,7 +798,7 @@
|
| dest->false_target()->Branch(equal);
|
|
|
| // Smi => false iff zero.
|
| - __ SmiCompare(value.reg(), Smi::FromInt(0));
|
| + __ Cmp(value.reg(), Smi::FromInt(0));
|
| dest->false_target()->Branch(equal);
|
| Condition is_smi = masm_->CheckSmi(value.reg());
|
| dest->true_target()->Branch(is_smi);
|
| @@ -1034,7 +1040,7 @@
|
| true, overwrite_mode);
|
| } else {
|
| // Set the flags based on the operation, type and loop nesting level.
|
| - // Bit operations always assume they likely operate on Smis. Still only
|
| + // Bit operations always assume they likely operate on smis. Still only
|
| // generate the inline Smi check code if this operation is part of a loop.
|
| // For all other operations only inline the Smi check code for likely smis
|
| // if the operation is part of a loop.
|
| @@ -2106,7 +2112,7 @@
|
| if (cc == equal) {
|
| Label comparison_done;
|
| __ SmiCompare(FieldOperand(left_side.reg(), String::kLengthOffset),
|
| - Smi::FromInt(1));
|
| + Smi::FromInt(1));
|
| __ j(not_equal, &comparison_done);
|
| uint8_t char_value =
|
| static_cast<uint8_t>(String::cast(*right_val)->Get(0));
|
| @@ -2292,7 +2298,7 @@
|
| // CompareStub and the inline code both support all values of cc.
|
| }
|
| // Implement comparison against a constant Smi, inlining the case
|
| - // where both sides are Smis.
|
| + // where both sides are smis.
|
| left_side->ToRegister();
|
| Register left_reg = left_side->reg();
|
| Smi* constant_smi = Smi::cast(*right_side->handle());
|
| @@ -2302,7 +2308,6 @@
|
| __ AbortIfNotSmi(left_reg);
|
| }
|
| // Test smi equality and comparison by signed int comparison.
|
| - // Both sides are smis, so we can use an Immediate.
|
| __ SmiCompare(left_reg, constant_smi);
|
| left_side->Unuse();
|
| right_side->Unuse();
|
| @@ -2312,7 +2317,7 @@
|
| JumpTarget is_smi;
|
| if (cc == equal) {
|
| // We can do the equality comparison before the smi check.
|
| - __ SmiCompare(left_reg, constant_smi);
|
| + __ Cmp(left_reg, constant_smi);
|
| dest->true_target()->Branch(equal);
|
| Condition left_is_smi = masm_->CheckSmi(left_reg);
|
| dest->false_target()->Branch(left_is_smi);
|
| @@ -2573,8 +2578,8 @@
|
| // adaptor frame below it.
|
| Label invoke, adapted;
|
| __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
|
| - __ SmiCompare(Operand(rdx, StandardFrameConstants::kContextOffset),
|
| - Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
|
| + __ Cmp(Operand(rdx, StandardFrameConstants::kContextOffset),
|
| + Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
|
| __ j(equal, &adapted);
|
|
|
| // No arguments adaptor frame. Copy fixed number of arguments.
|
| @@ -2751,7 +2756,8 @@
|
| frame_->EmitPush(rsi); // The context is the first argument.
|
| frame_->EmitPush(kScratchRegister);
|
| frame_->EmitPush(Smi::FromInt(is_eval() ? 1 : 0));
|
| - Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 3);
|
| + frame_->EmitPush(Smi::FromInt(strict_mode_flag()));
|
| + Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 4);
|
| // Return value is ignored.
|
| }
|
|
|
| @@ -3854,7 +3860,7 @@
|
| __ movq(rbx, rax);
|
|
|
| // If the property has been removed while iterating, we just skip it.
|
| - __ SmiCompare(rbx, Smi::FromInt(0));
|
| + __ Cmp(rbx, Smi::FromInt(0));
|
| node->continue_target()->Branch(equal);
|
|
|
| end_del_check.Bind();
|
| @@ -4609,7 +4615,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
|
| @@ -4922,8 +4929,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);
|
| }
|
| @@ -6201,15 +6209,15 @@
|
|
|
| // Skip the arguments adaptor frame if it exists.
|
| Label check_frame_marker;
|
| - __ SmiCompare(Operand(fp.reg(), StandardFrameConstants::kContextOffset),
|
| - Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
|
| + __ Cmp(Operand(fp.reg(), StandardFrameConstants::kContextOffset),
|
| + Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
|
| __ j(not_equal, &check_frame_marker);
|
| __ movq(fp.reg(), Operand(fp.reg(), StandardFrameConstants::kCallerFPOffset));
|
|
|
| // Check the marker in the calling frame.
|
| __ bind(&check_frame_marker);
|
| - __ SmiCompare(Operand(fp.reg(), StandardFrameConstants::kMarkerOffset),
|
| - Smi::FromInt(StackFrame::CONSTRUCT));
|
| + __ Cmp(Operand(fp.reg(), StandardFrameConstants::kMarkerOffset),
|
| + Smi::FromInt(StackFrame::CONSTRUCT));
|
| fp.Unuse();
|
| destination()->Split(equal);
|
| }
|
| @@ -6229,8 +6237,8 @@
|
|
|
| // Check if the calling frame is an arguments adaptor frame.
|
| __ movq(fp.reg(), Operand(rbp, StandardFrameConstants::kCallerFPOffset));
|
| - __ SmiCompare(Operand(fp.reg(), StandardFrameConstants::kContextOffset),
|
| - Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
|
| + __ Cmp(Operand(fp.reg(), StandardFrameConstants::kContextOffset),
|
| + Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
|
| __ j(not_equal, &exit);
|
|
|
| // Arguments adaptor case: Read the arguments length from the
|
| @@ -6789,8 +6797,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.
|
| - __ CmpObjectType(object.reg(), FIRST_JS_OBJECT_TYPE, tmp1.reg());
|
| - deferred->Branch(below);
|
| + __ CmpObjectType(object.reg(), JS_ARRAY_TYPE, tmp1.reg());
|
| + deferred->Branch(not_equal);
|
| __ testb(FieldOperand(tmp1.reg(), Map::kBitFieldOffset),
|
| Immediate(KeyedLoadIC::kSlowCaseBitFieldMask));
|
| deferred->Branch(not_zero);
|
| @@ -6832,7 +6840,7 @@
|
|
|
| Label done;
|
| __ InNewSpace(tmp1.reg(), tmp2.reg(), equal, &done);
|
| - // Possible optimization: do a check that both values are Smis
|
| + // Possible optimization: do a check that both values are smis
|
| // (or them and test against Smi mask.)
|
|
|
| __ movq(tmp2.reg(), tmp1.reg());
|
| @@ -7045,7 +7053,8 @@
|
| void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) {
|
| ASSERT_EQ(args->length(), 1);
|
| Load(args->at(0));
|
| - TranscendentalCacheStub stub(TranscendentalCache::SIN);
|
| + TranscendentalCacheStub stub(TranscendentalCache::SIN,
|
| + TranscendentalCacheStub::TAGGED);
|
| Result result = frame_->CallStub(&stub, 1);
|
| frame_->Push(&result);
|
| }
|
| @@ -7054,7 +7063,8 @@
|
| void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) {
|
| ASSERT_EQ(args->length(), 1);
|
| Load(args->at(0));
|
| - TranscendentalCacheStub stub(TranscendentalCache::COS);
|
| + TranscendentalCacheStub stub(TranscendentalCache::COS,
|
| + TranscendentalCacheStub::TAGGED);
|
| Result result = frame_->CallStub(&stub, 1);
|
| frame_->Push(&result);
|
| }
|
| @@ -7063,7 +7073,8 @@
|
| void CodeGenerator::GenerateMathLog(ZoneList<Expression*>* args) {
|
| ASSERT_EQ(args->length(), 1);
|
| Load(args->at(0));
|
| - TranscendentalCacheStub stub(TranscendentalCache::LOG);
|
| + TranscendentalCacheStub stub(TranscendentalCache::LOG,
|
| + TranscendentalCacheStub::TAGGED);
|
| Result result = frame_->CallStub(&stub, 1);
|
| frame_->Push(&result);
|
| }
|
| @@ -7254,8 +7265,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();
|
| @@ -7264,7 +7275,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
|
| @@ -7275,13 +7285,11 @@
|
| frame_->EmitPush(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
|
| @@ -7967,7 +7975,7 @@
|
| && (allocator()->count(r9) == (frame()->is_used(r9) ? 1 : 0))
|
| && (allocator()->count(r11) == (frame()->is_used(r11) ? 1 : 0))
|
| && (allocator()->count(r14) == (frame()->is_used(r14) ? 1 : 0))
|
| - && (allocator()->count(r12) == (frame()->is_used(r12) ? 1 : 0));
|
| + && (allocator()->count(r15) == (frame()->is_used(r15) ? 1 : 0));
|
| }
|
| #endif
|
|
|
| @@ -8090,8 +8098,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");
|
| }
|
|
|
| @@ -8104,6 +8116,7 @@
|
| Register key_;
|
| Register receiver_;
|
| Label patch_site_;
|
| + StrictModeFlag strict_mode_;
|
| };
|
|
|
|
|
| @@ -8155,7 +8168,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 instructions (initial movq)
|
| // to the test instruction. We use masm_-> directly here instead of the
|
| @@ -8222,7 +8237,8 @@
|
| // This is the map check instruction that will be patched (so we can't
|
| // use the double underscore macro that may insert instructions).
|
| // Initially use an invalid map to force a failure.
|
| - masm()->Move(kScratchRegister, Factory::null_value());
|
| + masm()->movq(kScratchRegister, Factory::null_value(),
|
| + RelocInfo::EMBEDDED_OBJECT);
|
| masm()->cmpq(FieldOperand(receiver.reg(), HeapObject::kMapOffset),
|
| kScratchRegister);
|
| // This branch is always a forwards branch so it's always a fixed
|
| @@ -8298,7 +8314,8 @@
|
| // the __ macro for the following two instructions because it
|
| // might introduce extra instructions.
|
| __ bind(&patch_site);
|
| - masm()->Move(kScratchRegister, Factory::null_value());
|
| + masm()->movq(kScratchRegister, Factory::null_value(),
|
| + RelocInfo::EMBEDDED_OBJECT);
|
| masm()->cmpq(FieldOperand(receiver.reg(), HeapObject::kMapOffset),
|
| kScratchRegister);
|
| // This branch is always a forwards branch so it's always a fixed size
|
| @@ -8499,7 +8516,8 @@
|
| DeferredReferenceSetKeyedValue* deferred =
|
| new DeferredReferenceSetKeyedValue(result.reg(),
|
| key.reg(),
|
| - receiver.reg());
|
| + receiver.reg(),
|
| + strict_mode_flag());
|
|
|
| // Check that the receiver is not a smi.
|
| __ JumpIfSmi(receiver.reg(), deferred->entry_label());
|
| @@ -8515,12 +8533,6 @@
|
| __ CmpObjectType(receiver.reg(), JS_ARRAY_TYPE, kScratchRegister);
|
| 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.
|
| - __ SmiCompare(FieldOperand(receiver.reg(), JSArray::kLengthOffset),
|
| - key.reg());
|
| - deferred->Branch(below_equal);
|
| -
|
| // Get the elements array from the receiver and check that it is not a
|
| // dictionary.
|
| __ movq(tmp.reg(),
|
| @@ -8550,6 +8562,14 @@
|
| kScratchRegister);
|
| 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.
|
| + __ SmiCompare(FieldOperand(receiver.reg(), JSArray::kLengthOffset),
|
| + key.reg());
|
| + deferred->Branch(below_equal);
|
| +
|
| // Store the value.
|
| SmiIndex index =
|
| masm()->SmiToIndex(kScratchRegister, key.reg(), kPointerSizeLog2);
|
| @@ -8562,7 +8582,7 @@
|
|
|
| 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
|
|
|