diff options
author | Emily Bernier <ember@google.com> | 2015-03-24 16:35:39 -0400 |
---|---|---|
committer | Emily Bernier <ember@google.com> | 2015-06-23 16:55:40 -0400 |
commit | 958fae7ec3f466955f8e5b50fa5b8d38b9e91675 (patch) | |
tree | a63ee37f93192ad427f88ed926743f6bb6014312 /src/x87 | |
parent | 57a14c9a8621270b0e6c697dce28a9c453ebe55f (diff) | |
download | android_external_v8-958fae7ec3f466955f8e5b50fa5b8d38b9e91675.tar.gz android_external_v8-958fae7ec3f466955f8e5b50fa5b8d38b9e91675.tar.bz2 android_external_v8-958fae7ec3f466955f8e5b50fa5b8d38b9e91675.zip |
Update V8 to version 4.1.0.21
This is a cherry-pick of all commits up to and including the
4.1.0.21 cherry-pick in Chromium.
Original commit message:
Version 4.1.0.21 (cherry-pick)
Merged 206e9136bde0f2b5ae8cb77afbb1e7833e5bd412
Unlink pages from the space page list after evacuation.
BUG=430201
LOG=N
R=jkummerow@chromium.org
Review URL: https://codereview.chromium.org/953813002
Cr-Commit-Position: refs/branch-heads/4.1@{#22}
Cr-Branched-From: 2e08d2a7aa9d65d269d8c57aba82eb38a8cb0a18-refs/heads/candidates@{#25353}
---
Change-Id: I8c23c7bbb70772b4858fe8a47b64fa97ee0d1f8c
Diffstat (limited to 'src/x87')
-rw-r--r-- | src/x87/assembler-x87.cc | 15 | ||||
-rw-r--r-- | src/x87/assembler-x87.h | 17 | ||||
-rw-r--r-- | src/x87/builtins-x87.cc | 41 | ||||
-rw-r--r-- | src/x87/code-stubs-x87.cc | 192 | ||||
-rw-r--r-- | src/x87/code-stubs-x87.h | 10 | ||||
-rw-r--r-- | src/x87/codegen-x87.cc | 13 | ||||
-rw-r--r-- | src/x87/debug-x87.cc | 6 | ||||
-rw-r--r-- | src/x87/deoptimizer-x87.cc | 2 | ||||
-rw-r--r-- | src/x87/disasm-x87.cc | 6 | ||||
-rw-r--r-- | src/x87/full-codegen-x87.cc | 567 | ||||
-rw-r--r-- | src/x87/interface-descriptors-x87.cc | 12 | ||||
-rw-r--r-- | src/x87/lithium-codegen-x87.cc | 178 | ||||
-rw-r--r-- | src/x87/lithium-x87.cc | 28 | ||||
-rw-r--r-- | src/x87/lithium-x87.h | 166 | ||||
-rw-r--r-- | src/x87/macro-assembler-x87.cc | 56 | ||||
-rw-r--r-- | src/x87/macro-assembler-x87.h | 27 |
16 files changed, 909 insertions, 427 deletions
diff --git a/src/x87/assembler-x87.cc b/src/x87/assembler-x87.cc index 9e1c8836..4177156e 100644 --- a/src/x87/assembler-x87.cc +++ b/src/x87/assembler-x87.cc @@ -915,24 +915,24 @@ void Assembler::rcr(Register dst, uint8_t imm8) { } -void Assembler::ror(Register dst, uint8_t imm8) { +void Assembler::ror(const Operand& dst, uint8_t imm8) { EnsureSpace ensure_space(this); DCHECK(is_uint5(imm8)); // illegal shift count if (imm8 == 1) { EMIT(0xD1); - EMIT(0xC8 | dst.code()); + emit_operand(ecx, dst); } else { EMIT(0xC1); - EMIT(0xC8 | dst.code()); + emit_operand(ecx, dst); EMIT(imm8); } } -void Assembler::ror_cl(Register dst) { +void Assembler::ror_cl(const Operand& dst) { EnsureSpace ensure_space(this); EMIT(0xD3); - EMIT(0xC8 | dst.code()); + emit_operand(ecx, dst); } @@ -1897,11 +1897,6 @@ void Assembler::setcc(Condition cc, Register reg) { } -void Assembler::Print() { - Disassembler::Decode(isolate(), stdout, buffer_, pc_); -} - - void Assembler::RecordJSReturn() { positions_recorder()->WriteRecordedPositions(); EnsureSpace ensure_space(this); diff --git a/src/x87/assembler-x87.h b/src/x87/assembler-x87.h index d37c9d77..1da632f2 100644 --- a/src/x87/assembler-x87.h +++ b/src/x87/assembler-x87.h @@ -148,6 +148,13 @@ struct X87Register { return kMaxNumAllocatableRegisters; } + + // TODO(turbofan): Proper support for float32. + static int NumAllocatableAliasedRegisters() { + return NumAllocatableRegisters(); + } + + static int ToAllocationIndex(X87Register reg) { return reg.code_; } @@ -718,8 +725,11 @@ class Assembler : public AssemblerBase { void rcl(Register dst, uint8_t imm8); void rcr(Register dst, uint8_t imm8); - void ror(Register dst, uint8_t imm8); - void ror_cl(Register dst); + + void ror(Register dst, uint8_t imm8) { ror(Operand(dst), imm8); } + void ror(const Operand& dst, uint8_t imm8); + void ror_cl(Register dst) { ror_cl(Operand(dst)); } + void ror_cl(const Operand& dst); void sar(Register dst, uint8_t imm8) { sar(Operand(dst), imm8); } void sar(const Operand& dst, uint8_t imm8); @@ -909,9 +919,6 @@ class Assembler : public AssemblerBase { // TODO(lrn): Need SFENCE for movnt? - // Debugging - void Print(); - // Check the code size generated from label to here. int SizeOfCodeGeneratedSince(Label* label) { return pc_offset() - label->pos(); diff --git a/src/x87/builtins-x87.cc b/src/x87/builtins-x87.cc index d6311752..51bb3a7c 100644 --- a/src/x87/builtins-x87.cc +++ b/src/x87/builtins-x87.cc @@ -160,18 +160,17 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, if (!is_api_function) { Label allocate; // The code below relies on these assumptions. - STATIC_ASSERT(JSFunction::kNoSlackTracking == 0); - STATIC_ASSERT(Map::ConstructionCount::kShift + - Map::ConstructionCount::kSize == 32); + STATIC_ASSERT(Map::Counter::kShift + Map::Counter::kSize == 32); // Check if slack tracking is enabled. __ mov(esi, FieldOperand(eax, Map::kBitField3Offset)); - __ shr(esi, Map::ConstructionCount::kShift); - __ j(zero, &allocate); // JSFunction::kNoSlackTracking + __ shr(esi, Map::Counter::kShift); + __ cmp(esi, Map::kSlackTrackingCounterEnd); + __ j(less, &allocate); // Decrease generous allocation count. __ sub(FieldOperand(eax, Map::kBitField3Offset), - Immediate(1 << Map::ConstructionCount::kShift)); + Immediate(1 << Map::Counter::kShift)); - __ cmp(esi, JSFunction::kFinishSlackTracking); + __ cmp(esi, Map::kSlackTrackingCounterEnd); __ j(not_equal, &allocate); __ push(eax); @@ -182,7 +181,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, __ pop(edi); __ pop(eax); - __ xor_(esi, esi); // JSFunction::kNoSlackTracking + __ mov(esi, Map::kSlackTrackingCounterEnd - 1); __ bind(&allocate); } @@ -219,8 +218,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, Label no_inobject_slack_tracking; // Check if slack tracking is enabled. - __ cmp(esi, JSFunction::kNoSlackTracking); - __ j(equal, &no_inobject_slack_tracking); + __ cmp(esi, Map::kSlackTrackingCounterEnd); + __ j(less, &no_inobject_slack_tracking); // Allocate object with a slack. __ movzx_b(esi, @@ -1002,17 +1001,21 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { __ bind(&loop); __ mov(receiver, Operand(ebp, kArgumentsOffset)); // load arguments - // Use inline caching to speed up access to arguments. if (FLAG_vector_ics) { - __ mov(VectorLoadICDescriptor::SlotRegister(), - Immediate(Smi::FromInt(0))); + // TODO(mvstanton): Vector-based ics need additional infrastructure to + // be embedded here. For now, just call the runtime. + __ push(receiver); + __ push(key); + __ CallRuntime(Runtime::kGetProperty, 2); + } else { + // Use inline caching to speed up access to arguments. + Handle<Code> ic = CodeFactory::KeyedLoadIC(masm->isolate()).code(); + __ call(ic, RelocInfo::CODE_TARGET); + // It is important 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 keyed load. In this + // case, we know that we are not generating a test instruction next. } - Handle<Code> ic = CodeFactory::KeyedLoadIC(masm->isolate()).code(); - __ call(ic, RelocInfo::CODE_TARGET); - // It is important 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 keyed load. In this - // case, we know that we are not generating a test instruction next. // Push the nth argument. __ push(eax); diff --git a/src/x87/code-stubs-x87.cc b/src/x87/code-stubs-x87.cc index d4c383be..1264dd9b 100644 --- a/src/x87/code-stubs-x87.cc +++ b/src/x87/code-stubs-x87.cc @@ -15,7 +15,7 @@ #include "src/isolate.h" #include "src/jsregexp.h" #include "src/regexp-macro-assembler.h" -#include "src/runtime.h" +#include "src/runtime/runtime.h" namespace v8 { namespace internal { @@ -333,8 +333,19 @@ void FunctionPrototypeStub::Generate(MacroAssembler* masm) { Label miss; Register receiver = LoadDescriptor::ReceiverRegister(); - NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(masm, receiver, eax, - ebx, &miss); + if (FLAG_vector_ics) { + // With careful management, we won't have to save slot and vector on + // the stack. Simply handle the possibly missing case first. + // TODO(mvstanton): this code can be more efficient. + __ cmp(FieldOperand(receiver, JSFunction::kPrototypeOrInitialMapOffset), + Immediate(isolate()->factory()->the_hole_value())); + __ j(equal, &miss); + __ TryGetFunctionPrototype(receiver, eax, ebx, &miss); + __ ret(0); + } else { + NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(masm, receiver, eax, + ebx, &miss); + } __ bind(&miss); PropertyAccessCompiler::TailCallBuiltin( masm, PropertyAccessCompiler::MissBuiltin(Code::LOAD_IC)); @@ -371,6 +382,42 @@ void LoadIndexedInterceptorStub::Generate(MacroAssembler* masm) { } +void LoadIndexedStringStub::Generate(MacroAssembler* masm) { + // Return address is on the stack. + Label miss; + + Register receiver = LoadDescriptor::ReceiverRegister(); + Register index = LoadDescriptor::NameRegister(); + Register scratch = edi; + DCHECK(!scratch.is(receiver) && !scratch.is(index)); + Register result = eax; + DCHECK(!result.is(scratch)); + DCHECK(!FLAG_vector_ics || + (!scratch.is(VectorLoadICDescriptor::VectorRegister()) && + result.is(VectorLoadICDescriptor::SlotRegister()))); + + // StringCharAtGenerator doesn't use the result register until it's passed + // the different miss possibilities. If it did, we would have a conflict + // when FLAG_vector_ics is true. + + StringCharAtGenerator char_at_generator(receiver, index, scratch, result, + &miss, // When not a string. + &miss, // When not a number. + &miss, // When index out of range. + STRING_INDEX_IS_ARRAY_INDEX, + RECEIVER_IS_STRING); + char_at_generator.GenerateFast(masm); + __ ret(0); + + StubRuntimeCallHelper call_helper; + char_at_generator.GenerateSlow(masm, call_helper); + + __ bind(&miss); + PropertyAccessCompiler::TailCallBuiltin( + masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC)); +} + + void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { // The key is in edx and the parameter count is in eax. DCHECK(edx.is(ArgumentsAccessReadDescriptor::index())); @@ -1871,6 +1918,10 @@ void CallICStub::Generate(MacroAssembler* masm) { // edi - function // edx - slot id Isolate* isolate = masm->isolate(); + const int with_types_offset = + FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex); + const int generic_offset = + FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex); Label extra_checks_or_miss, slow_start; Label slow, non_function, wrap, cont; Label have_js_function; @@ -1910,28 +1961,66 @@ void CallICStub::Generate(MacroAssembler* masm) { } __ bind(&extra_checks_or_miss); - Label miss; + Label uninitialized, miss; __ mov(ecx, FieldOperand(ebx, edx, times_half_pointer_size, FixedArray::kHeaderSize)); __ cmp(ecx, Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate))); __ j(equal, &slow_start); + + // The following cases attempt to handle MISS cases without going to the + // runtime. + if (FLAG_trace_ic) { + __ jmp(&miss); + } + __ cmp(ecx, Immediate(TypeFeedbackVector::UninitializedSentinel(isolate))); + __ j(equal, &uninitialized); + + // We are going megamorphic. If the feedback is a JSFunction, it is fine + // to handle it here. More complex cases are dealt with in the runtime. + __ AssertNotSmi(ecx); + __ CmpObjectType(ecx, JS_FUNCTION_TYPE, ecx); + __ j(not_equal, &miss); + __ mov( + FieldOperand(ebx, edx, times_half_pointer_size, FixedArray::kHeaderSize), + Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate))); + // We have to update statistics for runtime profiling. + __ sub(FieldOperand(ebx, with_types_offset), Immediate(Smi::FromInt(1))); + __ add(FieldOperand(ebx, generic_offset), Immediate(Smi::FromInt(1))); + __ jmp(&slow_start); + + __ bind(&uninitialized); + + // We are going monomorphic, provided we actually have a JSFunction. + __ JumpIfSmi(edi, &miss); + + // Goto miss case if we do not have a function. + __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); + __ j(not_equal, &miss); + + // Make sure the function is not the Array() function, which requires special + // behavior on MISS. + __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, ecx); + __ cmp(edi, ecx); __ j(equal, &miss); - if (!FLAG_trace_ic) { - // We are going megamorphic. If the feedback is a JSFunction, it is fine - // to handle it here. More complex cases are dealt with in the runtime. - __ AssertNotSmi(ecx); - __ CmpObjectType(ecx, JS_FUNCTION_TYPE, ecx); - __ j(not_equal, &miss); - __ mov(FieldOperand(ebx, edx, times_half_pointer_size, - FixedArray::kHeaderSize), - Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate))); - __ jmp(&slow_start); - } + // Update stats. + __ add(FieldOperand(ebx, with_types_offset), Immediate(Smi::FromInt(1))); + + // Store the function. + __ mov( + FieldOperand(ebx, edx, times_half_pointer_size, FixedArray::kHeaderSize), + edi); - // We are here because tracing is on or we are going monomorphic. + // Update the write barrier. + __ mov(eax, edi); + __ RecordWriteArray(ebx, eax, edx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + __ jmp(&have_js_function); + + // We are here because tracing is on or we encountered a MISS case we can't + // handle here. __ bind(&miss); GenerateMiss(masm); @@ -2437,18 +2526,18 @@ void InstanceofStub::Generate(MacroAssembler* masm) { void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { // If the receiver is a smi trigger the non-string case. - STATIC_ASSERT(kSmiTag == 0); - __ JumpIfSmi(object_, receiver_not_string_); - - // Fetch the instance type of the receiver into result register. - __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset)); - __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); - // If the receiver is not a string trigger the non-string case. - __ test(result_, Immediate(kIsNotStringMask)); - __ j(not_zero, receiver_not_string_); + if (check_mode_ == RECEIVER_IS_UNKNOWN) { + __ JumpIfSmi(object_, receiver_not_string_); + + // Fetch the instance type of the receiver into result register. + __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset)); + __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); + // If the receiver is not a string trigger the non-string case. + __ test(result_, Immediate(kIsNotStringMask)); + __ j(not_zero, receiver_not_string_); + } // If the index is non-smi trigger the non-smi case. - STATIC_ASSERT(kSmiTag == 0); __ JumpIfNotSmi(index_, &index_not_smi_); __ bind(&got_smi_index_); @@ -2817,14 +2906,61 @@ void SubStringStub::Generate(MacroAssembler* masm) { // ebx: instance type // ecx: sub string length (smi) // edx: from index (smi) - StringCharAtGenerator generator( - eax, edx, ecx, eax, &runtime, &runtime, &runtime, STRING_INDEX_IS_NUMBER); + StringCharAtGenerator generator(eax, edx, ecx, eax, &runtime, &runtime, + &runtime, STRING_INDEX_IS_NUMBER, + RECEIVER_IS_STRING); generator.GenerateFast(masm); __ ret(3 * kPointerSize); generator.SkipSlow(masm, &runtime); } +void ToNumberStub::Generate(MacroAssembler* masm) { + // The ToNumber stub takes one argument in eax. + Label not_smi; + __ JumpIfNotSmi(eax, ¬_smi, Label::kNear); + __ Ret(); + __ bind(¬_smi); + + Label not_heap_number; + __ CompareMap(eax, masm->isolate()->factory()->heap_number_map()); + __ j(not_equal, ¬_heap_number, Label::kNear); + __ Ret(); + __ bind(¬_heap_number); + + Label not_string, slow_string; + __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edi); + // eax: object + // edi: object map + __ j(above_equal, ¬_string, Label::kNear); + // Check if string has a cached array index. + __ test(FieldOperand(eax, String::kHashFieldOffset), + Immediate(String::kContainsCachedArrayIndexMask)); + __ j(not_zero, &slow_string, Label::kNear); + __ mov(eax, FieldOperand(eax, String::kHashFieldOffset)); + __ IndexFromHash(eax, eax); + __ Ret(); + __ bind(&slow_string); + __ pop(ecx); // Pop return address. + __ push(eax); // Push argument. + __ push(ecx); // Push return address. + __ TailCallRuntime(Runtime::kStringToNumber, 1, 1); + __ bind(¬_string); + + Label not_oddball; + __ CmpInstanceType(edi, ODDBALL_TYPE); + __ j(not_equal, ¬_oddball, Label::kNear); + __ mov(eax, FieldOperand(eax, Oddball::kToNumberOffset)); + __ Ret(); + __ bind(¬_oddball); + + __ pop(ecx); // Pop return address. + __ push(eax); // Push argument. + __ push(ecx); // Push return address. + __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION); +} + + void StringHelper::GenerateFlatOneByteStringEquals(MacroAssembler* masm, Register left, Register right, diff --git a/src/x87/code-stubs-x87.h b/src/x87/code-stubs-x87.h index 03ff477f..a079b6f3 100644 --- a/src/x87/code-stubs-x87.h +++ b/src/x87/code-stubs-x87.h @@ -76,7 +76,7 @@ class NameDictionaryLookupStub: public PlatformCodeStub { Register r0, Register r1); - virtual bool SometimesSetsUpAFrame() { return false; } + bool SometimesSetsUpAFrame() OVERRIDE { return false; } private: static const int kInlinedProbes = 4; @@ -139,7 +139,7 @@ class RecordWriteStub: public PlatformCodeStub { INCREMENTAL_COMPACTION }; - virtual bool SometimesSetsUpAFrame() { return false; } + bool SometimesSetsUpAFrame() OVERRIDE { return false; } static const byte kTwoByteNopInstruction = 0x3c; // Cmpb al, #imm8. static const byte kTwoByteJumpInstruction = 0xeb; // Jmp #imm8. @@ -328,9 +328,9 @@ class RecordWriteStub: public PlatformCodeStub { kUpdateRememberedSetOnNoNeedToInformIncrementalMarker }; - virtual inline Major MajorKey() const FINAL OVERRIDE { return RecordWrite; } + inline Major MajorKey() const FINAL { return RecordWrite; } - virtual void Generate(MacroAssembler* masm) OVERRIDE; + void Generate(MacroAssembler* masm) OVERRIDE; void GenerateIncremental(MacroAssembler* masm, Mode mode); void CheckNeedsToInformIncrementalMarker( MacroAssembler* masm, @@ -338,7 +338,7 @@ class RecordWriteStub: public PlatformCodeStub { Mode mode); void InformIncrementalMarker(MacroAssembler* masm); - void Activate(Code* code) { + void Activate(Code* code) OVERRIDE { code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code); } diff --git a/src/x87/codegen-x87.cc b/src/x87/codegen-x87.cc index e33959e6..1321461a 100644 --- a/src/x87/codegen-x87.cc +++ b/src/x87/codegen-x87.cc @@ -380,6 +380,19 @@ void ElementsTransitionGenerator::GenerateDoubleToObject( __ mov(FieldOperand(eax, FixedArray::kLengthOffset), ebx); __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); + // Allocating heap numbers in the loop below can fail and cause a jump to + // gc_required. We can't leave a partly initialized FixedArray behind, + // so pessimistically fill it with holes now. + Label initialization_loop, initialization_loop_entry; + __ jmp(&initialization_loop_entry, Label::kNear); + __ bind(&initialization_loop); + __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize), + masm->isolate()->factory()->the_hole_value()); + __ bind(&initialization_loop_entry); + __ sub(ebx, Immediate(Smi::FromInt(1))); + __ j(not_sign, &initialization_loop); + + __ mov(ebx, FieldOperand(edi, FixedDoubleArray::kLengthOffset)); __ jmp(&entry); // ebx: target map diff --git a/src/x87/debug-x87.cc b/src/x87/debug-x87.cc index 92c23abe..cdbcbad9 100644 --- a/src/x87/debug-x87.cc +++ b/src/x87/debug-x87.cc @@ -182,7 +182,11 @@ void DebugCodegen::GenerateLoadICDebugBreak(MacroAssembler* masm) { // Register state for IC load call (from ic-x87.cc). Register receiver = LoadDescriptor::ReceiverRegister(); Register name = LoadDescriptor::NameRegister(); - Generate_DebugBreakCallHelper(masm, receiver.bit() | name.bit(), 0, false); + RegList regs = receiver.bit() | name.bit(); + if (FLAG_vector_ics) { + regs |= VectorLoadICTrampolineDescriptor::SlotRegister().bit(); + } + Generate_DebugBreakCallHelper(masm, regs, 0, false); } diff --git a/src/x87/deoptimizer-x87.cc b/src/x87/deoptimizer-x87.cc index a76c7a70..0e53a0e8 100644 --- a/src/x87/deoptimizer-x87.cc +++ b/src/x87/deoptimizer-x87.cc @@ -27,7 +27,7 @@ void Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code) { HandleScope scope(isolate); // Compute the size of relocation information needed for the code - // patching in Deoptimizer::DeoptimizeFunction. + // patching in Deoptimizer::PatchCodeForDeoptimization below. int min_reloc_size = 0; int prev_pc_offset = 0; DeoptimizationInputData* deopt_data = diff --git a/src/x87/disasm-x87.cc b/src/x87/disasm-x87.cc index 908e8b04..8c77d771 100644 --- a/src/x87/disasm-x87.cc +++ b/src/x87/disasm-x87.cc @@ -1698,17 +1698,17 @@ int DisassemblerX87::InstructionDecode(v8::internal::Vector<char> out_buffer, //------------------------------------------------------------------------------ -static const char* cpu_regs[8] = { +static const char* const cpu_regs[8] = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" }; -static const char* byte_cpu_regs[8] = { +static const char* const byte_cpu_regs[8] = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" }; -static const char* xmm_regs[8] = { +static const char* const xmm_regs[8] = { "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" }; diff --git a/src/x87/full-codegen-x87.cc b/src/x87/full-codegen-x87.cc index c159edde..0f292cc4 100644 --- a/src/x87/full-codegen-x87.cc +++ b/src/x87/full-codegen-x87.cc @@ -188,10 +188,10 @@ void FullCodeGenerator::Generate() { Comment cmnt(masm_, "[ Allocate context"); bool need_write_barrier = true; // Argument to NewContext is the function, which is still in edi. - if (FLAG_harmony_scoping && info->scope()->is_global_scope()) { + if (FLAG_harmony_scoping && info->scope()->is_script_scope()) { __ push(edi); __ Push(info->scope()->GetScopeInfo()); - __ CallRuntime(Runtime::kNewGlobalContext, 2); + __ CallRuntime(Runtime::kNewScriptContext, 2); } else if (heap_slots <= FastNewContextStub::kMaximumSlots) { FastNewContextStub stub(isolate(), heap_slots); __ CallStub(&stub); @@ -865,7 +865,7 @@ void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) { EmitDebugCheckDeclarationContext(variable); // Load instance object. - __ LoadContext(eax, scope_->ContextChainLength(scope_->GlobalScope())); + __ LoadContext(eax, scope_->ContextChainLength(scope_->ScriptScope())); __ mov(eax, ContextOperand(eax, variable->interface()->Index())); __ mov(eax, ContextOperand(eax, Context::EXTENSION_INDEX)); @@ -1024,7 +1024,7 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { Comment cmnt(masm_, "[ ForInStatement"); - int slot = stmt->ForInFeedbackSlot(); + FeedbackVectorSlot slot = stmt->ForInFeedbackSlot(); SetStatementPosition(stmt); @@ -1034,6 +1034,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // Get the object to enumerate over. If the object is null or undefined, skip // over the loop. See ECMA-262 version 5, section 12.6.4. + SetExpressionPosition(stmt->enumerable()); VisitForAccumulatorValue(stmt->enumerable()); __ cmp(eax, isolate()->factory()->undefined_value()); __ j(equal, &exit); @@ -1051,6 +1052,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ push(eax); __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); __ bind(&done_convert); + PrepareForBailoutForId(stmt->ToObjectId(), TOS_REG); __ push(eax); // Check for proxies. @@ -1072,6 +1074,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ bind(&call_runtime); __ push(eax); __ CallRuntime(Runtime::kGetPropertyNamesFast, 1); + PrepareForBailoutForId(stmt->EnumId(), TOS_REG); __ cmp(FieldOperand(eax, HeapObject::kMapOffset), isolate()->factory()->meta_map()); __ j(not_equal, &fixed_array); @@ -1106,7 +1109,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // No need for a write barrier, we are storing a Smi in the feedback vector. __ LoadHeapObject(ebx, FeedbackVector()); - __ mov(FieldOperand(ebx, FixedArray::OffsetOfElementAt(slot)), + int vector_index = FeedbackVector()->GetIndex(slot); + __ mov(FieldOperand(ebx, FixedArray::OffsetOfElementAt(vector_index)), Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate()))); __ mov(ebx, Immediate(Smi::FromInt(1))); // Smi indicates slow check @@ -1125,6 +1129,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // Generate code for doing the condition check. PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS); __ bind(&loop); + SetExpressionPosition(stmt->each()); + __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index. __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length. __ j(above_equal, loop_statement.break_label()); @@ -1191,48 +1197,6 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { } -void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { - Comment cmnt(masm_, "[ ForOfStatement"); - SetStatementPosition(stmt); - - Iteration loop_statement(this, stmt); - increment_loop_depth(); - - // var iterator = iterable[Symbol.iterator](); - VisitForEffect(stmt->assign_iterator()); - - // Loop entry. - __ bind(loop_statement.continue_label()); - - // result = iterator.next() - VisitForEffect(stmt->next_result()); - - // if (result.done) break; - Label result_not_done; - VisitForControl(stmt->result_done(), - loop_statement.break_label(), - &result_not_done, - &result_not_done); - __ bind(&result_not_done); - - // each = result.value - VisitForEffect(stmt->assign_each()); - - // Generate code for the body of the loop. - Visit(stmt->body()); - - // Check stack before looping. - PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS); - EmitBackEdgeBookkeeping(stmt, loop_statement.continue_label()); - __ jmp(loop_statement.continue_label()); - - // Exit and decrement the loop depth. - PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); - __ bind(loop_statement.break_label()); - decrement_loop_depth(); -} - - void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info, bool pretenure) { // Use the fast case closure allocation code that allocates in new @@ -1276,7 +1240,13 @@ void FullCodeGenerator::EmitLoadHomeObject(SuperReference* expr) { Handle<Symbol> home_object_symbol(isolate()->heap()->home_object_symbol()); __ mov(LoadDescriptor::NameRegister(), home_object_symbol); - CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId()); + if (FLAG_vector_ics) { + __ mov(VectorLoadICDescriptor::SlotRegister(), + Immediate(SmiFromSlot(expr->HomeObjectFeedbackSlot()))); + CallLoadIC(NOT_CONTEXTUAL); + } else { + CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId()); + } __ cmp(eax, isolate()->factory()->undefined_value()); Label done; @@ -1286,6 +1256,19 @@ void FullCodeGenerator::EmitLoadHomeObject(SuperReference* expr) { } +void FullCodeGenerator::EmitSetHomeObjectIfNeeded(Expression* initializer, + int offset) { + if (NeedsHomeObject(initializer)) { + __ mov(StoreDescriptor::ReceiverRegister(), Operand(esp, 0)); + __ mov(StoreDescriptor::NameRegister(), + Immediate(isolate()->factory()->home_object_symbol())); + __ mov(StoreDescriptor::ValueRegister(), + Operand(esp, offset * kPointerSize)); + CallStoreIC(); + } +} + + void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy, TypeofState typeof_state, Label* slow) { @@ -1340,7 +1323,7 @@ void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy, __ mov(LoadDescriptor::NameRegister(), proxy->var()->name()); if (FLAG_vector_ics) { __ mov(VectorLoadICDescriptor::SlotRegister(), - Immediate(Smi::FromInt(proxy->VariableFeedbackSlot()))); + Immediate(SmiFromSlot(proxy->VariableFeedbackSlot()))); } ContextualMode mode = (typeof_state == INSIDE_TYPEOF) @@ -1427,7 +1410,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { __ mov(LoadDescriptor::NameRegister(), var->name()); if (FLAG_vector_ics) { __ mov(VectorLoadICDescriptor::SlotRegister(), - Immediate(Smi::FromInt(proxy->VariableFeedbackSlot()))); + Immediate(SmiFromSlot(proxy->VariableFeedbackSlot()))); } CallLoadIC(CONTEXTUAL); context()->Plug(eax); @@ -1611,6 +1594,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { FastCloneShallowObjectStub stub(isolate(), properties_count); __ CallStub(&stub); } + PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); // If result_saved is true the result is on top of the stack. If // result_saved is false the result is in eax. @@ -1639,6 +1623,8 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { DCHECK(!CompileTimeValue::IsCompileTimeValue(value)); // Fall through. case ObjectLiteral::Property::COMPUTED: + // It is safe to use [[Put]] here because the boilerplate already + // contains computed properties with an uninitialized value. if (key->value()->IsInternalizedString()) { if (property->emit_store()) { VisitForAccumulatorValue(value); @@ -1647,6 +1633,14 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { __ mov(StoreDescriptor::ReceiverRegister(), Operand(esp, 0)); CallStoreIC(key->LiteralFeedbackId()); PrepareForBailoutForId(key->id(), NO_REGISTERS); + + if (NeedsHomeObject(value)) { + __ mov(StoreDescriptor::ReceiverRegister(), eax); + __ mov(StoreDescriptor::NameRegister(), + Immediate(isolate()->factory()->home_object_symbol())); + __ mov(StoreDescriptor::ValueRegister(), Operand(esp, 0)); + CallStoreIC(); + } } else { VisitForEffect(value); } @@ -1656,6 +1650,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { VisitForStackValue(key); VisitForStackValue(value); if (property->emit_store()) { + EmitSetHomeObjectIfNeeded(value, 2); __ push(Immediate(Smi::FromInt(SLOPPY))); // Strict mode __ CallRuntime(Runtime::kSetProperty, 4); } else { @@ -1666,7 +1661,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { __ push(Operand(esp, 0)); // Duplicate receiver. VisitForStackValue(value); if (property->emit_store()) { - __ CallRuntime(Runtime::kSetPrototype, 2); + __ CallRuntime(Runtime::kInternalSetPrototype, 2); } else { __ Drop(2); } @@ -1688,7 +1683,9 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { __ push(Operand(esp, 0)); // Duplicate receiver. VisitForStackValue(it->first); EmitAccessor(it->second->getter); + EmitSetHomeObjectIfNeeded(it->second->getter, 2); EmitAccessor(it->second->setter); + EmitSetHomeObjectIfNeeded(it->second->setter, 3); __ push(Immediate(Smi::FromInt(NONE))); __ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5); } @@ -1801,22 +1798,23 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { Comment cmnt(masm_, "[ Assignment"); - // Left-hand side can only be a property, a global or a (parameter or local) - // slot. - enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; - LhsKind assign_type = VARIABLE; Property* property = expr->target()->AsProperty(); - if (property != NULL) { - assign_type = (property->key()->IsPropertyName()) - ? NAMED_PROPERTY - : KEYED_PROPERTY; - } + LhsKind assign_type = GetAssignType(property); // Evaluate LHS expression. switch (assign_type) { case VARIABLE: // Nothing to do here. break; + case NAMED_SUPER_PROPERTY: + VisitForStackValue(property->obj()->AsSuperReference()->this_var()); + EmitLoadHomeObject(property->obj()->AsSuperReference()); + __ push(result_register()); + if (expr->is_compound()) { + __ push(MemOperand(esp, kPointerSize)); + __ push(result_register()); + } + break; case NAMED_PROPERTY: if (expr->is_compound()) { // We need the receiver both on the stack and in the register. @@ -1826,6 +1824,18 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { VisitForStackValue(property->obj()); } break; + case KEYED_SUPER_PROPERTY: + VisitForStackValue(property->obj()->AsSuperReference()->this_var()); + EmitLoadHomeObject(property->obj()->AsSuperReference()); + __ Push(result_register()); + VisitForAccumulatorValue(property->key()); + __ Push(result_register()); + if (expr->is_compound()) { + __ push(MemOperand(esp, 2 * kPointerSize)); + __ push(MemOperand(esp, 2 * kPointerSize)); + __ push(result_register()); + } + break; case KEYED_PROPERTY: { if (expr->is_compound()) { VisitForStackValue(property->obj()); @@ -1850,10 +1860,18 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { EmitVariableLoad(expr->target()->AsVariableProxy()); PrepareForBailout(expr->target(), TOS_REG); break; + case NAMED_SUPER_PROPERTY: + EmitNamedSuperPropertyLoad(property); + PrepareForBailoutForId(property->LoadId(), TOS_REG); + break; case NAMED_PROPERTY: EmitNamedPropertyLoad(property); PrepareForBailoutForId(property->LoadId(), TOS_REG); break; + case KEYED_SUPER_PROPERTY: + EmitKeyedSuperPropertyLoad(property); + PrepareForBailoutForId(property->LoadId(), TOS_REG); + break; case KEYED_PROPERTY: EmitKeyedPropertyLoad(property); PrepareForBailoutForId(property->LoadId(), TOS_REG); @@ -1899,6 +1917,14 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { case NAMED_PROPERTY: EmitNamedPropertyAssignment(expr); break; + case NAMED_SUPER_PROPERTY: + EmitNamedSuperPropertyStore(property); + context()->Plug(result_register()); + break; + case KEYED_SUPER_PROPERTY: + EmitKeyedSuperPropertyStore(property); + context()->Plug(result_register()); + break; case KEYED_PROPERTY: EmitKeyedPropertyAssignment(expr); break; @@ -2031,7 +2057,7 @@ void FullCodeGenerator::VisitYield(Yield* expr) { __ mov(load_receiver, Operand(esp, kPointerSize)); if (FLAG_vector_ics) { __ mov(VectorLoadICDescriptor::SlotRegister(), - Immediate(Smi::FromInt(expr->KeyedLoadFeedbackSlot()))); + Immediate(SmiFromSlot(expr->KeyedLoadFeedbackSlot()))); } Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code(); CallIC(ic, TypeFeedbackId::None()); @@ -2051,7 +2077,7 @@ void FullCodeGenerator::VisitYield(Yield* expr) { isolate()->factory()->done_string()); // "done" if (FLAG_vector_ics) { __ mov(VectorLoadICDescriptor::SlotRegister(), - Immediate(Smi::FromInt(expr->DoneFeedbackSlot()))); + Immediate(SmiFromSlot(expr->DoneFeedbackSlot()))); } CallLoadIC(NOT_CONTEXTUAL); // result.done in eax Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate()); @@ -2065,7 +2091,7 @@ void FullCodeGenerator::VisitYield(Yield* expr) { isolate()->factory()->value_string()); // "value" if (FLAG_vector_ics) { __ mov(VectorLoadICDescriptor::SlotRegister(), - Immediate(Smi::FromInt(expr->ValueFeedbackSlot()))); + Immediate(SmiFromSlot(expr->ValueFeedbackSlot()))); } CallLoadIC(NOT_CONTEXTUAL); // result.value in eax context()->DropAndPlug(2, eax); // drop iter and g @@ -2086,15 +2112,6 @@ void FullCodeGenerator::EmitGeneratorResume(Expression *generator, VisitForAccumulatorValue(value); __ pop(ebx); - // Check generator state. - Label wrong_state, closed_state, done; - STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting < 0); - STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed == 0); - __ cmp(FieldOperand(ebx, JSGeneratorObject::kContinuationOffset), - Immediate(Smi::FromInt(0))); - __ j(equal, &closed_state); - __ j(less, &wrong_state); - // Load suspended function and context. __ mov(esi, FieldOperand(ebx, JSGeneratorObject::kContextOffset)); __ mov(edi, FieldOperand(ebx, JSGeneratorObject::kFunctionOffset)); @@ -2116,7 +2133,7 @@ void FullCodeGenerator::EmitGeneratorResume(Expression *generator, // Enter a new JavaScript frame, and initialize its slots as they were when // the generator was suspended. - Label resume_frame; + Label resume_frame, done; __ bind(&push_frame); __ call(&resume_frame); __ jmp(&done); @@ -2163,25 +2180,6 @@ void FullCodeGenerator::EmitGeneratorResume(Expression *generator, // Not reached: the runtime call returns elsewhere. __ Abort(kGeneratorFailedToResume); - // Reach here when generator is closed. - __ bind(&closed_state); - if (resume_mode == JSGeneratorObject::NEXT) { - // Return completed iterator result when generator is closed. - __ push(Immediate(isolate()->factory()->undefined_value())); - // Pop value from top-of-stack slot; box result into result register. - EmitCreateIteratorResult(true); - } else { - // Throw the provided value. - __ push(eax); - __ CallRuntime(Runtime::kThrow, 1); - } - __ jmp(&done); - - // Throw error if we attempt to operate on a running generator. - __ bind(&wrong_state); - __ push(ebx); - __ CallRuntime(Runtime::kThrowGeneratorStateError, 1); - __ bind(&done); context()->Plug(result_register()); } @@ -2229,10 +2227,12 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { SetSourcePosition(prop->position()); Literal* key = prop->key()->AsLiteral(); DCHECK(!key->value()->IsSmi()); + DCHECK(!prop->IsSuperAccess()); + __ mov(LoadDescriptor::NameRegister(), Immediate(key->value())); if (FLAG_vector_ics) { __ mov(VectorLoadICDescriptor::SlotRegister(), - Immediate(Smi::FromInt(prop->PropertyFeedbackSlot()))); + Immediate(SmiFromSlot(prop->PropertyFeedbackSlot()))); CallLoadIC(NOT_CONTEXTUAL); } else { CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId()); @@ -2241,15 +2241,12 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) { + // Stack: receiver, home_object. SetSourcePosition(prop->position()); Literal* key = prop->key()->AsLiteral(); DCHECK(!key->value()->IsSmi()); DCHECK(prop->IsSuperAccess()); - SuperReference* super_ref = prop->obj()->AsSuperReference(); - EmitLoadHomeObject(super_ref); - __ push(eax); - VisitForStackValue(super_ref->this_var()); __ push(Immediate(key->value())); __ CallRuntime(Runtime::kLoadFromSuper, 3); } @@ -2260,7 +2257,7 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code(); if (FLAG_vector_ics) { __ mov(VectorLoadICDescriptor::SlotRegister(), - Immediate(Smi::FromInt(prop->PropertyFeedbackSlot()))); + Immediate(SmiFromSlot(prop->PropertyFeedbackSlot()))); CallIC(ic); } else { CallIC(ic, prop->PropertyFeedbackId()); @@ -2268,6 +2265,14 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { } +void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) { + // Stack: receiver, home_object, key. + SetSourcePosition(prop->position()); + + __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3); +} + + void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, Token::Value op, OverwriteMode mode, @@ -2363,6 +2368,61 @@ void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, } +void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) { + // Constructor is in eax. + DCHECK(lit != NULL); + __ push(eax); + + // No access check is needed here since the constructor is created by the + // class literal. + Register scratch = ebx; + __ mov(scratch, FieldOperand(eax, JSFunction::kPrototypeOrInitialMapOffset)); + __ Push(scratch); + + for (int i = 0; i < lit->properties()->length(); i++) { + ObjectLiteral::Property* property = lit->properties()->at(i); + Literal* key = property->key()->AsLiteral(); + Expression* value = property->value(); + DCHECK(key != NULL); + + if (property->is_static()) { + __ push(Operand(esp, kPointerSize)); // constructor + } else { + __ push(Operand(esp, 0)); // prototype + } + VisitForStackValue(key); + VisitForStackValue(value); + EmitSetHomeObjectIfNeeded(value, 2); + + switch (property->kind()) { + case ObjectLiteral::Property::CONSTANT: + case ObjectLiteral::Property::MATERIALIZED_LITERAL: + case ObjectLiteral::Property::COMPUTED: + case ObjectLiteral::Property::PROTOTYPE: + __ CallRuntime(Runtime::kDefineClassMethod, 3); + break; + + case ObjectLiteral::Property::GETTER: + __ CallRuntime(Runtime::kDefineClassGetter, 3); + break; + + case ObjectLiteral::Property::SETTER: + __ CallRuntime(Runtime::kDefineClassSetter, 3); + break; + + default: + UNREACHABLE(); + } + } + + // prototype + __ CallRuntime(Runtime::kToFastProperties, 1); + + // constructor + __ CallRuntime(Runtime::kToFastProperties, 1); +} + + void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op, OverwriteMode mode) { @@ -2378,16 +2438,8 @@ void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, void FullCodeGenerator::EmitAssignment(Expression* expr) { DCHECK(expr->IsValidReferenceExpression()); - // Left-hand side can only be a property, a global or a (parameter or local) - // slot. - enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; - LhsKind assign_type = VARIABLE; Property* prop = expr->AsProperty(); - if (prop != NULL) { - assign_type = (prop->key()->IsPropertyName()) - ? NAMED_PROPERTY - : KEYED_PROPERTY; - } + LhsKind assign_type = GetAssignType(prop); switch (assign_type) { case VARIABLE: { @@ -2406,6 +2458,42 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) { CallStoreIC(); break; } + case NAMED_SUPER_PROPERTY: { + __ push(eax); + VisitForStackValue(prop->obj()->AsSuperReference()->this_var()); + EmitLoadHomeObject(prop->obj()->AsSuperReference()); + // stack: value, this; eax: home_object + Register scratch = ecx; + Register scratch2 = edx; + __ mov(scratch, result_register()); // home_object + __ mov(eax, MemOperand(esp, kPointerSize)); // value + __ mov(scratch2, MemOperand(esp, 0)); // this + __ mov(MemOperand(esp, kPointerSize), scratch2); // this + __ mov(MemOperand(esp, 0), scratch); // home_object + // stack: this, home_object. eax: value + EmitNamedSuperPropertyStore(prop); + break; + } + case KEYED_SUPER_PROPERTY: { + __ push(eax); + VisitForStackValue(prop->obj()->AsSuperReference()->this_var()); + EmitLoadHomeObject(prop->obj()->AsSuperReference()); + __ push(result_register()); + VisitForAccumulatorValue(prop->key()); + Register scratch = ecx; + Register scratch2 = edx; + __ mov(scratch2, MemOperand(esp, 2 * kPointerSize)); // value + // stack: value, this, home_object; eax: key, edx: value + __ mov(scratch, MemOperand(esp, kPointerSize)); // this + __ mov(MemOperand(esp, 2 * kPointerSize), scratch); + __ mov(scratch, MemOperand(esp, 0)); // home_object + __ mov(MemOperand(esp, kPointerSize), scratch); + __ mov(MemOperand(esp, 0), eax); + __ mov(eax, scratch2); + // stack: this, home_object, key; eax: value. + EmitKeyedSuperPropertyStore(prop); + break; + } case KEYED_PROPERTY: { __ push(eax); // Preserve value. VisitForStackValue(prop->obj()); @@ -2474,7 +2562,6 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, __ CallRuntime(Runtime::kThrowReferenceError, 1); __ bind(&assign); EmitStoreToStackLocalOrContextSlot(var, location); - } else if (!var->is_const_mode() || op == Token::INIT_CONST) { if (var->IsLookupSlot()) { // Assignment to var. @@ -2496,8 +2583,9 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, } EmitStoreToStackLocalOrContextSlot(var, location); } + } else if (IsSignallingAssignmentToConst(var, op, strict_mode())) { + __ CallRuntime(Runtime::kThrowConstAssignError, 0); } - // Non-initializing assignments to consts are ignored. } @@ -2520,6 +2608,34 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { } +void FullCodeGenerator::EmitNamedSuperPropertyStore(Property* prop) { + // Assignment to named property of super. + // eax : value + // stack : receiver ('this'), home_object + DCHECK(prop != NULL); + Literal* key = prop->key()->AsLiteral(); + DCHECK(key != NULL); + + __ push(Immediate(key->value())); + __ push(eax); + __ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreToSuper_Strict + : Runtime::kStoreToSuper_Sloppy), + 4); +} + + +void FullCodeGenerator::EmitKeyedSuperPropertyStore(Property* prop) { + // Assignment to named property of super. + // eax : value + // stack : receiver ('this'), home_object, key + + __ push(eax); + __ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreKeyedToSuper_Strict + : Runtime::kStoreKeyedToSuper_Sloppy), + 4); +} + + void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { // Assignment to a property, using a keyed store IC. // eax : value @@ -2549,16 +2665,27 @@ void FullCodeGenerator::VisitProperty(Property* expr) { __ Move(LoadDescriptor::ReceiverRegister(), result_register()); EmitNamedPropertyLoad(expr); } else { + VisitForStackValue(expr->obj()->AsSuperReference()->this_var()); + EmitLoadHomeObject(expr->obj()->AsSuperReference()); + __ push(result_register()); EmitNamedSuperPropertyLoad(expr); } PrepareForBailoutForId(expr->LoadId(), TOS_REG); context()->Plug(eax); } else { - VisitForStackValue(expr->obj()); - VisitForAccumulatorValue(expr->key()); - __ pop(LoadDescriptor::ReceiverRegister()); // Object. - __ Move(LoadDescriptor::NameRegister(), result_register()); // Key. - EmitKeyedPropertyLoad(expr); + if (!expr->IsSuperAccess()) { + VisitForStackValue(expr->obj()); + VisitForAccumulatorValue(expr->key()); + __ pop(LoadDescriptor::ReceiverRegister()); // Object. + __ Move(LoadDescriptor::NameRegister(), result_register()); // Key. + EmitKeyedPropertyLoad(expr); + } else { + VisitForStackValue(expr->obj()->AsSuperReference()->this_var()); + EmitLoadHomeObject(expr->obj()->AsSuperReference()); + __ push(result_register()); + VisitForStackValue(expr->key()); + EmitKeyedSuperPropertyLoad(expr); + } context()->Plug(eax); } } @@ -2617,14 +2744,14 @@ void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) { __ push(eax); VisitForAccumulatorValue(super_ref->this_var()); __ push(eax); - __ push(Operand(esp, kPointerSize)); __ push(eax); + __ push(Operand(esp, kPointerSize * 2)); __ push(Immediate(key->value())); // Stack here: // - home_object // - this (receiver) - // - home_object <-- LoadFromSuper will pop here and below. - // - this (receiver) + // - this (receiver) <-- LoadFromSuper will pop here and below. + // - home_object // - key __ CallRuntime(Runtime::kLoadFromSuper, 3); @@ -2661,6 +2788,40 @@ void FullCodeGenerator::EmitKeyedCallWithLoadIC(Call* expr, } +void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) { + Expression* callee = expr->expression(); + DCHECK(callee->IsProperty()); + Property* prop = callee->AsProperty(); + DCHECK(prop->IsSuperAccess()); + + SetSourcePosition(prop->position()); + // Load the function from the receiver. + SuperReference* super_ref = callee->AsProperty()->obj()->AsSuperReference(); + EmitLoadHomeObject(super_ref); + __ push(eax); + VisitForAccumulatorValue(super_ref->this_var()); + __ push(eax); + __ push(eax); + __ push(Operand(esp, kPointerSize * 2)); + VisitForStackValue(prop->key()); + // Stack here: + // - home_object + // - this (receiver) + // - this (receiver) <-- LoadKeyedFromSuper will pop here and below. + // - home_object + // - key + __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3); + + // Replace home_object with target function. + __ mov(Operand(esp, kPointerSize), eax); + + // Stack here: + // - target function + // - this (receiver) + EmitCall(expr, CallICState::METHOD); +} + + void FullCodeGenerator::EmitCall(Call* expr, CallICState::CallType call_type) { // Load the arguments. ZoneList<Expression*>* args = expr->arguments(); @@ -2675,7 +2836,7 @@ void FullCodeGenerator::EmitCall(Call* expr, CallICState::CallType call_type) { SetSourcePosition(expr->position()); Handle<Code> ic = CallIC::initialize_stub( isolate(), arg_count, call_type); - __ Move(edx, Immediate(Smi::FromInt(expr->CallFeedbackSlot()))); + __ Move(edx, Immediate(SmiFromSlot(expr->CallFeedbackSlot()))); __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize)); // Don't assign a type feedback id to the IC, since type feedback is provided // by the vector above. @@ -2713,6 +2874,13 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { } +void FullCodeGenerator::EmitLoadSuperConstructor(SuperReference* super_ref) { + DCHECK(super_ref != NULL); + __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); + __ CallRuntime(Runtime::kGetPrototype, 1); +} + + void FullCodeGenerator::VisitCall(Call* expr) { #ifdef DEBUG // We want to verify that RecordJSReturnSite gets called on all paths @@ -2748,6 +2916,8 @@ void FullCodeGenerator::VisitCall(Call* expr) { // edx (receiver). Touch up the stack with the right values. __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx); __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax); + + PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS); } // Record source position for debugger. SetSourcePosition(expr->position()); @@ -2779,6 +2949,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { __ CallRuntime(Runtime::kLoadLookupSlot, 2); __ push(eax); // Function. __ push(edx); // Receiver. + PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS); // If fast case code has been generated, emit code to push the function // and receiver and have the slow path jump around this code. @@ -2801,9 +2972,12 @@ void FullCodeGenerator::VisitCall(Call* expr) { } else if (call_type == Call::PROPERTY_CALL) { Property* property = callee->AsProperty(); bool is_named_call = property->key()->IsPropertyName(); - // super.x() is handled in EmitCallWithLoadIC. - if (property->IsSuperAccess() && is_named_call) { - EmitSuperCallWithLoadIC(expr); + if (property->IsSuperAccess()) { + if (is_named_call) { + EmitSuperCallWithLoadIC(expr); + } else { + EmitKeyedSuperCallWithLoadIC(expr); + } } else { { PreservePositionScope scope(masm()->positions_recorder()); @@ -2815,6 +2989,12 @@ void FullCodeGenerator::VisitCall(Call* expr) { EmitKeyedCallWithLoadIC(expr, property->key()); } } + } else if (call_type == Call::SUPER_CALL) { + SuperReference* super_ref = callee->AsSuperReference(); + EmitLoadSuperConstructor(super_ref); + __ push(result_register()); + VisitForStackValue(super_ref->this_var()); + EmitCall(expr, CallICState::METHOD); } else { DCHECK(call_type == Call::OTHER_CALL); // Call to an arbitrary expression not handled specially above. @@ -2842,7 +3022,12 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) { // Push constructor on the stack. If it's not a function it's used as // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is // ignored. - VisitForStackValue(expr->expression()); + if (expr->expression()->IsSuperReference()) { + EmitLoadSuperConstructor(expr->expression()->AsSuperReference()); + __ push(result_register()); + } else { + VisitForStackValue(expr->expression()); + } // Push the arguments ("left-to-right") on the stack. ZoneList<Expression*>* args = expr->arguments(); @@ -2862,12 +3047,12 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) { // Record call targets in unoptimized code. if (FLAG_pretenuring_call_new) { EnsureSlotContainsAllocationSite(expr->AllocationSiteFeedbackSlot()); - DCHECK(expr->AllocationSiteFeedbackSlot() == - expr->CallNewFeedbackSlot() + 1); + DCHECK(expr->AllocationSiteFeedbackSlot().ToInt() == + expr->CallNewFeedbackSlot().ToInt() + 1); } __ LoadHeapObject(ebx, FeedbackVector()); - __ mov(edx, Immediate(Smi::FromInt(expr->CallNewFeedbackSlot()))); + __ mov(edx, Immediate(SmiFromSlot(expr->CallNewFeedbackSlot()))); CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET); __ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL); @@ -3181,6 +3366,31 @@ void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) { } +void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) { + ZoneList<Expression*>* args = expr->arguments(); + DCHECK(args->length() == 1); + + VisitForAccumulatorValue(args->at(0)); + + Label materialize_true, materialize_false; + Label* if_true = NULL; + Label* if_false = NULL; + Label* fall_through = NULL; + context()->PrepareTest(&materialize_true, &materialize_false, &if_true, + &if_false, &fall_through); + + __ JumpIfSmi(eax, if_false); + Register map = ebx; + __ mov(map, FieldOperand(eax, HeapObject::kMapOffset)); + __ CmpInstanceType(map, FIRST_JS_PROXY_TYPE); + __ j(less, if_false); + __ CmpInstanceType(map, LAST_JS_PROXY_TYPE); + PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); + Split(less_equal, if_true, if_false, fall_through); + + context()->Plug(if_true, if_false); +} + void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) { DCHECK(expr->arguments()->length() == 0); @@ -4118,7 +4328,7 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { __ mov(LoadDescriptor::NameRegister(), Immediate(expr->name())); if (FLAG_vector_ics) { __ mov(VectorLoadICDescriptor::SlotRegister(), - Immediate(Smi::FromInt(expr->CallRuntimeFeedbackSlot()))); + Immediate(SmiFromSlot(expr->CallRuntimeFeedbackSlot()))); CallLoadIC(NOT_CONTEXTUAL); } else { CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId()); @@ -4279,17 +4489,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { Comment cmnt(masm_, "[ CountOperation"); SetSourcePosition(expr->position()); - // Expression can only be a property, a global or a (parameter or local) - // slot. - enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; - LhsKind assign_type = VARIABLE; Property* prop = expr->expression()->AsProperty(); - // In case of a property we use the uninitialized expression context - // of the key to detect a named property. - if (prop != NULL) { - assign_type = - (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; - } + LhsKind assign_type = GetAssignType(prop); // Evaluate expression and get value. if (assign_type == VARIABLE) { @@ -4301,18 +4502,50 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { if (expr->is_postfix() && !context()->IsEffect()) { __ push(Immediate(Smi::FromInt(0))); } - if (assign_type == NAMED_PROPERTY) { - // Put the object both on the stack and in the register. - VisitForStackValue(prop->obj()); - __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0)); - EmitNamedPropertyLoad(prop); - } else { - VisitForStackValue(prop->obj()); - VisitForStackValue(prop->key()); - __ mov(LoadDescriptor::ReceiverRegister(), - Operand(esp, kPointerSize)); // Object. - __ mov(LoadDescriptor::NameRegister(), Operand(esp, 0)); // Key. - EmitKeyedPropertyLoad(prop); + switch (assign_type) { + case NAMED_PROPERTY: { + // Put the object both on the stack and in the register. + VisitForStackValue(prop->obj()); + __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0)); + EmitNamedPropertyLoad(prop); + break; + } + + case NAMED_SUPER_PROPERTY: { + VisitForStackValue(prop->obj()->AsSuperReference()->this_var()); + EmitLoadHomeObject(prop->obj()->AsSuperReference()); + __ push(result_register()); + __ push(MemOperand(esp, kPointerSize)); + __ push(result_register()); + EmitNamedSuperPropertyLoad(prop); + break; + } + + case KEYED_SUPER_PROPERTY: { + VisitForStackValue(prop->obj()->AsSuperReference()->this_var()); + EmitLoadHomeObject(prop->obj()->AsSuperReference()); + __ push(result_register()); + VisitForAccumulatorValue(prop->key()); + __ push(result_register()); + __ push(MemOperand(esp, 2 * kPointerSize)); + __ push(MemOperand(esp, 2 * kPointerSize)); + __ push(result_register()); + EmitKeyedSuperPropertyLoad(prop); + break; + } + + case KEYED_PROPERTY: { + VisitForStackValue(prop->obj()); + VisitForStackValue(prop->key()); + __ mov(LoadDescriptor::ReceiverRegister(), + Operand(esp, kPointerSize)); // Object. + __ mov(LoadDescriptor::NameRegister(), Operand(esp, 0)); // Key. + EmitKeyedPropertyLoad(prop); + break; + } + + case VARIABLE: + UNREACHABLE(); } } @@ -4344,9 +4577,15 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { case NAMED_PROPERTY: __ mov(Operand(esp, kPointerSize), eax); break; + case NAMED_SUPER_PROPERTY: + __ mov(Operand(esp, 2 * kPointerSize), eax); + break; case KEYED_PROPERTY: __ mov(Operand(esp, 2 * kPointerSize), eax); break; + case KEYED_SUPER_PROPERTY: + __ mov(Operand(esp, 3 * kPointerSize), eax); + break; } } } @@ -4382,9 +4621,15 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { case NAMED_PROPERTY: __ mov(Operand(esp, kPointerSize), eax); break; + case NAMED_SUPER_PROPERTY: + __ mov(Operand(esp, 2 * kPointerSize), eax); + break; case KEYED_PROPERTY: __ mov(Operand(esp, 2 * kPointerSize), eax); break; + case KEYED_SUPER_PROPERTY: + __ mov(Operand(esp, 3 * kPointerSize), eax); + break; } } } @@ -4441,6 +4686,28 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { } break; } + case NAMED_SUPER_PROPERTY: { + EmitNamedSuperPropertyStore(prop); + if (expr->is_postfix()) { + if (!context()->IsEffect()) { + context()->PlugTOS(); + } + } else { + context()->Plug(eax); + } + break; + } + case KEYED_SUPER_PROPERTY: { + EmitKeyedSuperPropertyStore(prop); + if (expr->is_postfix()) { + if (!context()->IsEffect()) { + context()->PlugTOS(); + } + } else { + context()->Plug(eax); + } + break; + } case KEYED_PROPERTY: { __ pop(StoreDescriptor::NameRegister()); __ pop(StoreDescriptor::ReceiverRegister()); @@ -4473,7 +4740,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { __ mov(LoadDescriptor::NameRegister(), Immediate(proxy->name())); if (FLAG_vector_ics) { __ mov(VectorLoadICDescriptor::SlotRegister(), - Immediate(Smi::FromInt(proxy->VariableFeedbackSlot()))); + Immediate(SmiFromSlot(proxy->VariableFeedbackSlot()))); } // Use a regular load, not a contextual load, to avoid a reference // error. @@ -4708,7 +4975,7 @@ void FullCodeGenerator::LoadContextField(Register dst, int context_index) { void FullCodeGenerator::PushFunctionArgumentForContextAllocation() { Scope* declaration_scope = scope()->DeclarationScope(); - if (declaration_scope->is_global_scope() || + if (declaration_scope->is_script_scope() || declaration_scope->is_module_scope()) { // Contexts nested in the native context have a canonical empty function // as their closure, not the anonymous closure containing the global diff --git a/src/x87/interface-descriptors-x87.cc b/src/x87/interface-descriptors-x87.cc index 8dfad363..26ce4dcb 100644 --- a/src/x87/interface-descriptors-x87.cc +++ b/src/x87/interface-descriptors-x87.cc @@ -29,6 +29,9 @@ const Register StoreDescriptor::NameRegister() { return ecx; } const Register StoreDescriptor::ValueRegister() { return eax; } +const Register StoreTransitionDescriptor::MapRegister() { return ebx; } + + const Register ElementTransitionAndStoreDescriptor::MapRegister() { return ebx; } @@ -152,6 +155,15 @@ void TransitionElementsKindDescriptor::Initialize( } +void AllocateHeapNumberDescriptor::Initialize( + CallInterfaceDescriptorData* data) { + // register state + // esi -- context + Register registers[] = {esi}; + data->Initialize(arraysize(registers), registers, nullptr); +} + + void ArrayConstructorConstantArgCountDescriptor::Initialize( CallInterfaceDescriptorData* data) { // register state diff --git a/src/x87/lithium-codegen-x87.cc b/src/x87/lithium-codegen-x87.cc index a5bc5eae..c292bb94 100644 --- a/src/x87/lithium-codegen-x87.cc +++ b/src/x87/lithium-codegen-x87.cc @@ -32,9 +32,9 @@ class SafepointGenerator FINAL : public CallWrapper { deopt_mode_(mode) {} virtual ~SafepointGenerator() {} - virtual void BeforeCall(int call_size) const OVERRIDE {} + void BeforeCall(int call_size) const OVERRIDE {} - virtual void AfterCall() const OVERRIDE { + void AfterCall() const OVERRIDE { codegen_->RecordSafepoint(pointers_, deopt_mode_); } @@ -2924,10 +2924,10 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { LInstanceOfKnownGlobal* instr, const X87Stack& x87_stack) : LDeferredCode(codegen, x87_stack), instr_(instr) { } - virtual void Generate() OVERRIDE { + void Generate() OVERRIDE { codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_); } - virtual LInstruction* instr() OVERRIDE { return instr_; } + LInstruction* instr() OVERRIDE { return instr_; } Label* map_check() { return &map_check_; } private: LInstanceOfKnownGlobal* instr_; @@ -3050,6 +3050,7 @@ void LCodeGen::EmitReturn(LReturn* instr, bool dynamic_frame_alignment) { } __ Ret((parameter_count + extra_value_count) * kPointerSize, ecx); } else { + DCHECK(info()->IsStub()); // Functions would need to drop one more value. Register reg = ToRegister(instr->parameter_count()); // The argument count parameter is a smi __ SmiUntag(reg); @@ -3124,13 +3125,18 @@ void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) { template <class T> void LCodeGen::EmitVectorLoadICRegisters(T* instr) { DCHECK(FLAG_vector_ics); - Register vector = ToRegister(instr->temp_vector()); - DCHECK(vector.is(VectorLoadICDescriptor::VectorRegister())); - __ mov(vector, instr->hydrogen()->feedback_vector()); + Register vector_register = ToRegister(instr->temp_vector()); + Register slot_register = VectorLoadICDescriptor::SlotRegister(); + DCHECK(vector_register.is(VectorLoadICDescriptor::VectorRegister())); + DCHECK(slot_register.is(eax)); + + AllowDeferredHandleDereference vector_structure_check; + Handle<TypeFeedbackVector> vector = instr->hydrogen()->feedback_vector(); + __ mov(vector_register, vector); // No need to allocate this register. - DCHECK(VectorLoadICDescriptor::SlotRegister().is(eax)); - __ mov(VectorLoadICDescriptor::SlotRegister(), - Immediate(Smi::FromInt(instr->hydrogen()->slot()))); + FeedbackVectorICSlot slot = instr->hydrogen()->slot(); + int index = vector->GetIndex(slot); + __ mov(slot_register, Immediate(Smi::FromInt(index))); } @@ -3145,7 +3151,7 @@ void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { EmitVectorLoadICRegisters<LLoadGlobalGeneric>(instr); } ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL; - Handle<Code> ic = CodeFactory::LoadIC(isolate(), mode).code(); + Handle<Code> ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode).code(); CallCode(ic, RelocInfo::CODE_TARGET, instr); } @@ -3275,7 +3281,8 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { if (FLAG_vector_ics) { EmitVectorLoadICRegisters<LLoadNamedGeneric>(instr); } - Handle<Code> ic = CodeFactory::LoadIC(isolate(), NOT_CONTEXTUAL).code(); + Handle<Code> ic = + CodeFactory::LoadICInOptimizedCode(isolate(), NOT_CONTEXTUAL).code(); CallCode(ic, RelocInfo::CODE_TARGET, instr); } @@ -3498,7 +3505,7 @@ void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { EmitVectorLoadICRegisters<LLoadKeyedGeneric>(instr); } - Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code(); + Handle<Code> ic = CodeFactory::KeyedLoadICInOptimizedCode(isolate()).code(); CallCode(ic, RelocInfo::CODE_TARGET, instr); } @@ -3734,45 +3741,81 @@ void LCodeGen::DoTailCallThroughMegamorphicCache( Register name = ToRegister(instr->name()); DCHECK(receiver.is(LoadDescriptor::ReceiverRegister())); DCHECK(name.is(LoadDescriptor::NameRegister())); + Register slot = FLAG_vector_ics ? ToRegister(instr->slot()) : no_reg; + Register vector = FLAG_vector_ics ? ToRegister(instr->vector()) : no_reg; Register scratch = ebx; - Register extra = eax; + Register extra = edi; + DCHECK(!extra.is(slot) && !extra.is(vector)); DCHECK(!scratch.is(receiver) && !scratch.is(name)); DCHECK(!extra.is(receiver) && !extra.is(name)); // Important for the tail-call. bool must_teardown_frame = NeedsEagerFrame(); - // The probe will tail call to a handler if found. - isolate()->stub_cache()->GenerateProbe(masm(), instr->hydrogen()->flags(), - must_teardown_frame, receiver, name, - scratch, extra); + if (!instr->hydrogen()->is_just_miss()) { + if (FLAG_vector_ics) { + __ push(slot); + __ push(vector); + } + + // The probe will tail call to a handler if found. + // If --vector-ics is on, then it knows to pop the two args first. + DCHECK(!instr->hydrogen()->is_keyed_load()); + isolate()->stub_cache()->GenerateProbe( + masm(), Code::LOAD_IC, instr->hydrogen()->flags(), must_teardown_frame, + receiver, name, scratch, extra); + + if (FLAG_vector_ics) { + __ pop(vector); + __ pop(slot); + } + } // Tail call to miss if we ended up here. if (must_teardown_frame) __ leave(); - LoadIC::GenerateMiss(masm()); + if (instr->hydrogen()->is_keyed_load()) { + KeyedLoadIC::GenerateMiss(masm()); + } else { + LoadIC::GenerateMiss(masm()); + } } void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) { DCHECK(ToRegister(instr->result()).is(eax)); - LPointerMap* pointers = instr->pointer_map(); - SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); + if (instr->hydrogen()->IsTailCall()) { + if (NeedsEagerFrame()) __ leave(); - if (instr->target()->IsConstantOperand()) { - LConstantOperand* target = LConstantOperand::cast(instr->target()); - Handle<Code> code = Handle<Code>::cast(ToHandle(target)); - generator.BeforeCall(__ CallSize(code, RelocInfo::CODE_TARGET)); - __ call(code, RelocInfo::CODE_TARGET); + if (instr->target()->IsConstantOperand()) { + LConstantOperand* target = LConstantOperand::cast(instr->target()); + Handle<Code> code = Handle<Code>::cast(ToHandle(target)); + __ jmp(code, RelocInfo::CODE_TARGET); + } else { + DCHECK(instr->target()->IsRegister()); + Register target = ToRegister(instr->target()); + __ add(target, Immediate(Code::kHeaderSize - kHeapObjectTag)); + __ jmp(target); + } } else { - DCHECK(instr->target()->IsRegister()); - Register target = ToRegister(instr->target()); - generator.BeforeCall(__ CallSize(Operand(target))); - __ add(target, Immediate(Code::kHeaderSize - kHeapObjectTag)); - __ call(target); + LPointerMap* pointers = instr->pointer_map(); + SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); + + if (instr->target()->IsConstantOperand()) { + LConstantOperand* target = LConstantOperand::cast(instr->target()); + Handle<Code> code = Handle<Code>::cast(ToHandle(target)); + generator.BeforeCall(__ CallSize(code, RelocInfo::CODE_TARGET)); + __ call(code, RelocInfo::CODE_TARGET); + } else { + DCHECK(instr->target()->IsRegister()); + Register target = ToRegister(instr->target()); + generator.BeforeCall(__ CallSize(Operand(target))); + __ add(target, Immediate(Code::kHeaderSize - kHeapObjectTag)); + __ call(target); + } + generator.AfterCall(); } - generator.AfterCall(); } @@ -3869,10 +3912,11 @@ void LCodeGen::DoMathAbs(LMathAbs* instr) { LMathAbs* instr, const X87Stack& x87_stack) : LDeferredCode(codegen, x87_stack), instr_(instr) { } - virtual void Generate() OVERRIDE { + void Generate() OVERRIDE { codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_); } - virtual LInstruction* instr() OVERRIDE { return instr_; } + LInstruction* instr() OVERRIDE { return instr_; } + private: LMathAbs* instr_; }; @@ -4777,10 +4821,9 @@ void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { LStringCharCodeAt* instr, const X87Stack& x87_stack) : LDeferredCode(codegen, x87_stack), instr_(instr) { } - virtual void Generate() OVERRIDE { - codegen()->DoDeferredStringCharCodeAt(instr_); - } - virtual LInstruction* instr() OVERRIDE { return instr_; } + void Generate() OVERRIDE { codegen()->DoDeferredStringCharCodeAt(instr_); } + LInstruction* instr() OVERRIDE { return instr_; } + private: LStringCharCodeAt* instr_; }; @@ -4836,10 +4879,11 @@ void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) { LStringCharFromCode* instr, const X87Stack& x87_stack) : LDeferredCode(codegen, x87_stack), instr_(instr) { } - virtual void Generate() OVERRIDE { + void Generate() OVERRIDE { codegen()->DoDeferredStringCharFromCode(instr_); } - virtual LInstruction* instr() OVERRIDE { return instr_; } + LInstruction* instr() OVERRIDE { return instr_; } + private: LStringCharFromCode* instr_; }; @@ -4925,11 +4969,12 @@ void LCodeGen::DoNumberTagI(LNumberTagI* instr) { LNumberTagI* instr, const X87Stack& x87_stack) : LDeferredCode(codegen, x87_stack), instr_(instr) { } - virtual void Generate() OVERRIDE { + void Generate() OVERRIDE { codegen()->DoDeferredNumberTagIU(instr_, instr_->value(), instr_->temp(), SIGNED_INT32); } - virtual LInstruction* instr() OVERRIDE { return instr_; } + LInstruction* instr() OVERRIDE { return instr_; } + private: LNumberTagI* instr_; }; @@ -4953,11 +4998,12 @@ void LCodeGen::DoNumberTagU(LNumberTagU* instr) { LNumberTagU* instr, const X87Stack& x87_stack) : LDeferredCode(codegen, x87_stack), instr_(instr) { } - virtual void Generate() OVERRIDE { + void Generate() OVERRIDE { codegen()->DoDeferredNumberTagIU(instr_, instr_->value(), instr_->temp(), UNSIGNED_INT32); } - virtual LInstruction* instr() OVERRIDE { return instr_; } + LInstruction* instr() OVERRIDE { return instr_; } + private: LNumberTagU* instr_; }; @@ -5042,10 +5088,9 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) { LNumberTagD* instr, const X87Stack& x87_stack) : LDeferredCode(codegen, x87_stack), instr_(instr) { } - virtual void Generate() OVERRIDE { - codegen()->DoDeferredNumberTagD(instr_); - } - virtual LInstruction* instr() OVERRIDE { return instr_; } + void Generate() OVERRIDE { codegen()->DoDeferredNumberTagD(instr_); } + LInstruction* instr() OVERRIDE { return instr_; } + private: LNumberTagD* instr_; }; @@ -5288,10 +5333,9 @@ void LCodeGen::DoTaggedToI(LTaggedToI* instr) { LTaggedToI* instr, const X87Stack& x87_stack) : LDeferredCode(codegen, x87_stack), instr_(instr) { } - virtual void Generate() OVERRIDE { - codegen()->DoDeferredTaggedToI(instr_, done()); - } - virtual LInstruction* instr() OVERRIDE { return instr_; } + void Generate() OVERRIDE { codegen()->DoDeferredTaggedToI(instr_, done()); } + LInstruction* instr() OVERRIDE { return instr_; } + private: LTaggedToI* instr_; }; @@ -5353,9 +5397,8 @@ void LCodeGen::DoDoubleToI(LDoubleToI* instr) { Label lost_precision, is_nan, minus_zero, done; X87Register input_reg = ToX87Register(input); X87Fxch(input_reg); - Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear; __ X87TOSToI(result_reg, instr->hydrogen()->GetMinusZeroMode(), - &lost_precision, &is_nan, &minus_zero, dist); + &lost_precision, &is_nan, &minus_zero); __ jmp(&done); __ bind(&lost_precision); DeoptimizeIf(no_condition, instr, "lost precision"); @@ -5378,9 +5421,8 @@ void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) { Label lost_precision, is_nan, minus_zero, done; X87Register input_reg = ToX87Register(input); X87Fxch(input_reg); - Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear; __ X87TOSToI(result_reg, instr->hydrogen()->GetMinusZeroMode(), - &lost_precision, &is_nan, &minus_zero, dist); + &lost_precision, &is_nan, &minus_zero); __ jmp(&done); __ bind(&lost_precision); DeoptimizeIf(no_condition, instr, "lost precision"); @@ -5494,11 +5536,12 @@ void LCodeGen::DoCheckMaps(LCheckMaps* instr) { : LDeferredCode(codegen, x87_stack), instr_(instr), object_(object) { SetExit(check_maps()); } - virtual void Generate() OVERRIDE { + void Generate() OVERRIDE { codegen()->DoDeferredInstanceMigration(instr_, object_); } Label* check_maps() { return &check_maps_; } - virtual LInstruction* instr() OVERRIDE { return instr_; } + LInstruction* instr() OVERRIDE { return instr_; } + private: LCheckMaps* instr_; Label check_maps_; @@ -5717,10 +5760,9 @@ void LCodeGen::DoAllocate(LAllocate* instr) { LAllocate* instr, const X87Stack& x87_stack) : LDeferredCode(codegen, x87_stack), instr_(instr) { } - virtual void Generate() OVERRIDE { - codegen()->DoDeferredAllocate(instr_); - } - virtual LInstruction* instr() OVERRIDE { return instr_; } + void Generate() OVERRIDE { codegen()->DoDeferredAllocate(instr_); } + LInstruction* instr() OVERRIDE { return instr_; } + private: LAllocate* instr_; }; @@ -6086,10 +6128,9 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) { LStackCheck* instr, const X87Stack& x87_stack) : LDeferredCode(codegen, x87_stack), instr_(instr) { } - virtual void Generate() OVERRIDE { - codegen()->DoDeferredStackCheck(instr_); - } - virtual LInstruction* instr() OVERRIDE { return instr_; } + void Generate() OVERRIDE { codegen()->DoDeferredStackCheck(instr_); } + LInstruction* instr() OVERRIDE { return instr_; } + private: LStackCheck* instr_; }; @@ -6237,10 +6278,11 @@ void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) { object_(object), index_(index) { } - virtual void Generate() OVERRIDE { + void Generate() OVERRIDE { codegen()->DoDeferredLoadMutableDouble(instr_, object_, index_); } - virtual LInstruction* instr() OVERRIDE { return instr_; } + LInstruction* instr() OVERRIDE { return instr_; } + private: LLoadFieldByIndex* instr_; Register object_; diff --git a/src/x87/lithium-x87.cc b/src/x87/lithium-x87.cc index 9304b897..3a52dc4b 100644 --- a/src/x87/lithium-x87.cc +++ b/src/x87/lithium-x87.cc @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <sstream> + #include "src/v8.h" #if V8_TARGET_ARCH_X87 @@ -376,9 +378,9 @@ LOperand* LPlatformChunk::GetNextSpillSlot(RegisterKind kind) { void LStoreNamedField::PrintDataTo(StringStream* stream) { object()->PrintTo(stream); - OStringStream os; + std::ostringstream os; os << hydrogen()->access() << " <- "; - stream->Add(os.c_str()); + stream->Add(os.str().c_str()); value()->PrintTo(stream); } @@ -736,11 +738,7 @@ LInstruction* LChunkBuilder::DoShift(Token::Value op, // Shift operations can only deoptimize if we do a logical shift by 0 and // the result cannot be truncated to int32. if (op == Token::SHR && constant_value == 0) { - if (FLAG_opt_safe_uint32_operations) { - does_deopt = !instr->CheckFlag(HInstruction::kUint32); - } else { - does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToInt32); - } + does_deopt = !instr->CheckFlag(HInstruction::kUint32); } LInstruction* result = @@ -1159,9 +1157,17 @@ LInstruction* LChunkBuilder::DoTailCallThroughMegamorphicCache( UseFixed(instr->receiver(), LoadDescriptor::ReceiverRegister()); LOperand* name_register = UseFixed(instr->name(), LoadDescriptor::NameRegister()); + LOperand* slot = NULL; + LOperand* vector = NULL; + if (FLAG_vector_ics) { + slot = UseFixed(instr->slot(), VectorLoadICDescriptor::SlotRegister()); + vector = + UseFixed(instr->vector(), VectorLoadICDescriptor::VectorRegister()); + } + // Not marked as call. It can't deoptimize, and it never returns. return new (zone()) LTailCallThroughMegamorphicCache( - context, receiver_register, name_register); + context, receiver_register, name_register, slot, vector); } @@ -2115,7 +2121,7 @@ LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) { LOperand* global_object = UseFixed(instr->global_object(), LoadDescriptor::ReceiverRegister()); LOperand* vector = NULL; - if (FLAG_vector_ics) { + if (instr->HasVectorAndSlot()) { vector = FixedTemp(VectorLoadICDescriptor::VectorRegister()); } @@ -2176,7 +2182,7 @@ LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) { LOperand* object = UseFixed(instr->object(), LoadDescriptor::ReceiverRegister()); LOperand* vector = NULL; - if (FLAG_vector_ics) { + if (instr->HasVectorAndSlot()) { vector = FixedTemp(VectorLoadICDescriptor::VectorRegister()); } LLoadNamedGeneric* result = new(zone()) LLoadNamedGeneric( @@ -2241,7 +2247,7 @@ LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) { UseFixed(instr->object(), LoadDescriptor::ReceiverRegister()); LOperand* key = UseFixed(instr->key(), LoadDescriptor::NameRegister()); LOperand* vector = NULL; - if (FLAG_vector_ics) { + if (instr->HasVectorAndSlot()) { vector = FixedTemp(VectorLoadICDescriptor::VectorRegister()); } LLoadKeyedGeneric* result = diff --git a/src/x87/lithium-x87.h b/src/x87/lithium-x87.h index dbb18eca..5d27fcb7 100644 --- a/src/x87/lithium-x87.h +++ b/src/x87/lithium-x87.h @@ -168,17 +168,13 @@ class LCodeGen; V(WrapReceiver) -#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \ - virtual Opcode opcode() const FINAL OVERRIDE { \ - return LInstruction::k##type; \ - } \ - virtual void CompileToNative(LCodeGen* generator) FINAL OVERRIDE; \ - virtual const char* Mnemonic() const FINAL OVERRIDE { \ - return mnemonic; \ - } \ - static L##type* cast(LInstruction* instr) { \ - DCHECK(instr->Is##type()); \ - return reinterpret_cast<L##type*>(instr); \ +#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \ + Opcode opcode() const FINAL { return LInstruction::k##type; } \ + void CompileToNative(LCodeGen* generator) FINAL; \ + const char* Mnemonic() const FINAL { return mnemonic; } \ + static L##type* cast(LInstruction* instr) { \ + DCHECK(instr->Is##type()); \ + return reinterpret_cast<L##type*>(instr); \ } @@ -297,11 +293,9 @@ class LTemplateResultInstruction : public LInstruction { public: // Allow 0 or 1 output operands. STATIC_ASSERT(R == 0 || R == 1); - virtual bool HasResult() const FINAL OVERRIDE { - return R != 0 && result() != NULL; - } + bool HasResult() const FINAL { return R != 0 && result() != NULL; } void set_result(LOperand* operand) { results_[0] = operand; } - LOperand* result() const { return results_[0]; } + LOperand* result() const OVERRIDE { return results_[0]; } protected: EmbeddedContainer<LOperand*, R> results_; @@ -319,11 +313,11 @@ class LTemplateInstruction : public LTemplateResultInstruction<R> { private: // Iterator support. - virtual int InputCount() FINAL OVERRIDE { return I; } - virtual LOperand* InputAt(int i) FINAL OVERRIDE { return inputs_[i]; } + int InputCount() FINAL { return I; } + LOperand* InputAt(int i) FINAL { return inputs_[i]; } - virtual int TempCount() FINAL OVERRIDE { return T; } - virtual LOperand* TempAt(int i) FINAL OVERRIDE { return temps_[i]; } + int TempCount() FINAL { return T; } + LOperand* TempAt(int i) FINAL { return temps_[i]; } }; @@ -337,8 +331,8 @@ class LGap : public LTemplateInstruction<0, 0, 0> { } // Can't use the DECLARE-macro here because of sub-classes. - virtual bool IsGap() const FINAL OVERRIDE { return true; } - virtual void PrintDataTo(StringStream* stream) OVERRIDE; + bool IsGap() const FINAL { return true; } + void PrintDataTo(StringStream* stream) OVERRIDE; static LGap* cast(LInstruction* instr) { DCHECK(instr->IsGap()); return reinterpret_cast<LGap*>(instr); @@ -378,7 +372,7 @@ class LInstructionGap FINAL : public LGap { public: explicit LInstructionGap(HBasicBlock* block) : LGap(block) { } - virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { + bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return !IsRedundant(); } @@ -390,9 +384,7 @@ class LClobberDoubles FINAL : public LTemplateInstruction<0, 0, 0> { public: explicit LClobberDoubles(Isolate* isolate) { } - virtual bool ClobbersDoubleRegisters(Isolate* isolate) const OVERRIDE { - return true; - } + bool ClobbersDoubleRegisters(Isolate* isolate) const OVERRIDE { return true; } DECLARE_CONCRETE_INSTRUCTION(ClobberDoubles, "clobber-d") }; @@ -402,13 +394,13 @@ class LGoto FINAL : public LTemplateInstruction<0, 0, 0> { public: explicit LGoto(HBasicBlock* block) : block_(block) { } - virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE; + bool HasInterestingComment(LCodeGen* gen) const OVERRIDE; DECLARE_CONCRETE_INSTRUCTION(Goto, "goto") - virtual void PrintDataTo(StringStream* stream) OVERRIDE; - virtual bool IsControl() const OVERRIDE { return true; } + void PrintDataTo(StringStream* stream) OVERRIDE; + bool IsControl() const OVERRIDE { return true; } int block_id() const { return block_->block_id(); } - virtual bool ClobbersDoubleRegisters(Isolate* isolate) const OVERRIDE { + bool ClobbersDoubleRegisters(Isolate* isolate) const OVERRIDE { return false; } @@ -444,7 +436,7 @@ class LDummyUse FINAL : public LTemplateInstruction<1, 1, 0> { class LDeoptimize FINAL : public LTemplateInstruction<0, 0, 0> { public: - virtual bool IsControl() const OVERRIDE { return true; } + bool IsControl() const OVERRIDE { return true; } DECLARE_CONCRETE_INSTRUCTION(Deoptimize, "deoptimize") DECLARE_HYDROGEN_ACCESSOR(Deoptimize) }; @@ -455,12 +447,10 @@ class LLabel FINAL : public LGap { explicit LLabel(HBasicBlock* block) : LGap(block), replacement_(NULL) { } - virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { - return false; - } + bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; } DECLARE_CONCRETE_INSTRUCTION(Label, "label") - virtual void PrintDataTo(StringStream* stream) OVERRIDE; + void PrintDataTo(StringStream* stream) OVERRIDE; int block_id() const { return block()->block_id(); } bool is_loop_header() const { return block()->IsLoopHeader(); } @@ -478,9 +468,7 @@ class LLabel FINAL : public LGap { class LParameter FINAL : public LTemplateInstruction<1, 0, 0> { public: - virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { - return false; - } + bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; } DECLARE_CONCRETE_INSTRUCTION(Parameter, "parameter") }; @@ -499,19 +487,23 @@ class LCallStub FINAL : public LTemplateInstruction<1, 1, 0> { class LTailCallThroughMegamorphicCache FINAL - : public LTemplateInstruction<0, 3, 0> { + : public LTemplateInstruction<0, 5, 0> { public: - explicit LTailCallThroughMegamorphicCache(LOperand* context, - LOperand* receiver, - LOperand* name) { + LTailCallThroughMegamorphicCache(LOperand* context, LOperand* receiver, + LOperand* name, LOperand* slot, + LOperand* vector) { inputs_[0] = context; inputs_[1] = receiver; inputs_[2] = name; + inputs_[3] = slot; + inputs_[4] = vector; } LOperand* context() { return inputs_[0]; } LOperand* receiver() { return inputs_[1]; } LOperand* name() { return inputs_[2]; } + LOperand* slot() { return inputs_[3]; } + LOperand* vector() { return inputs_[4]; } DECLARE_CONCRETE_INSTRUCTION(TailCallThroughMegamorphicCache, "tail-call-through-megamorphic-cache") @@ -521,9 +513,7 @@ class LTailCallThroughMegamorphicCache FINAL class LUnknownOSRValue FINAL : public LTemplateInstruction<1, 0, 0> { public: - virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { - return false; - } + bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; } DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue, "unknown-osr-value") }; @@ -533,7 +523,7 @@ class LControlInstruction: public LTemplateInstruction<0, I, T> { public: LControlInstruction() : false_label_(NULL), true_label_(NULL) { } - virtual bool IsControl() const FINAL OVERRIDE { return true; } + bool IsControl() const FINAL { return true; } int SuccessorCount() { return hydrogen()->SuccessorCount(); } HBasicBlock* SuccessorAt(int i) { return hydrogen()->SuccessorAt(i); } @@ -626,7 +616,7 @@ class LAccessArgumentsAt FINAL : public LTemplateInstruction<1, 3, 0> { DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt, "access-arguments-at") - virtual void PrintDataTo(StringStream* stream) OVERRIDE; + void PrintDataTo(StringStream* stream) OVERRIDE; }; @@ -875,7 +865,7 @@ class LCompareNumericAndBranch FINAL : public LControlInstruction<2, 0> { return hydrogen()->representation().IsDouble(); } - virtual void PrintDataTo(StringStream* stream); + void PrintDataTo(StringStream* stream) OVERRIDE; }; @@ -1052,7 +1042,7 @@ class LIsObjectAndBranch FINAL : public LControlInstruction<1, 1> { DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch") - virtual void PrintDataTo(StringStream* stream) OVERRIDE; + void PrintDataTo(StringStream* stream) OVERRIDE; }; @@ -1069,7 +1059,7 @@ class LIsStringAndBranch FINAL : public LControlInstruction<1, 1> { DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch, "is-string-and-branch") DECLARE_HYDROGEN_ACCESSOR(IsStringAndBranch) - virtual void PrintDataTo(StringStream* stream) OVERRIDE; + void PrintDataTo(StringStream* stream) OVERRIDE; }; @@ -1084,7 +1074,7 @@ class LIsSmiAndBranch FINAL : public LControlInstruction<1, 0> { DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch, "is-smi-and-branch") DECLARE_HYDROGEN_ACCESSOR(IsSmiAndBranch) - virtual void PrintDataTo(StringStream* stream) OVERRIDE; + void PrintDataTo(StringStream* stream) OVERRIDE; }; @@ -1102,7 +1092,7 @@ class LIsUndetectableAndBranch FINAL : public LControlInstruction<1, 1> { "is-undetectable-and-branch") DECLARE_HYDROGEN_ACCESSOR(IsUndetectableAndBranch) - virtual void PrintDataTo(StringStream* stream) OVERRIDE; + void PrintDataTo(StringStream* stream) OVERRIDE; }; @@ -1122,7 +1112,7 @@ class LStringCompareAndBranch FINAL : public LControlInstruction<3, 0> { "string-compare-and-branch") DECLARE_HYDROGEN_ACCESSOR(StringCompareAndBranch) - virtual void PrintDataTo(StringStream* stream) OVERRIDE; + void PrintDataTo(StringStream* stream) OVERRIDE; Token::Value op() const { return hydrogen()->token(); } }; @@ -1142,7 +1132,7 @@ class LHasInstanceTypeAndBranch FINAL : public LControlInstruction<1, 1> { "has-instance-type-and-branch") DECLARE_HYDROGEN_ACCESSOR(HasInstanceTypeAndBranch) - virtual void PrintDataTo(StringStream* stream) OVERRIDE; + void PrintDataTo(StringStream* stream) OVERRIDE; }; @@ -1171,7 +1161,7 @@ class LHasCachedArrayIndexAndBranch FINAL DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch, "has-cached-array-index-and-branch") - virtual void PrintDataTo(StringStream* stream) OVERRIDE; + void PrintDataTo(StringStream* stream) OVERRIDE; }; @@ -1204,7 +1194,7 @@ class LClassOfTestAndBranch FINAL : public LControlInstruction<1, 2> { "class-of-test-and-branch") DECLARE_HYDROGEN_ACCESSOR(ClassOfTestAndBranch) - virtual void PrintDataTo(StringStream* stream) OVERRIDE; + void PrintDataTo(StringStream* stream) OVERRIDE; }; @@ -1399,7 +1389,7 @@ class LBranch FINAL : public LControlInstruction<1, 1> { DECLARE_CONCRETE_INSTRUCTION(Branch, "branch") DECLARE_HYDROGEN_ACCESSOR(Branch) - virtual void PrintDataTo(StringStream* stream) OVERRIDE; + void PrintDataTo(StringStream* stream) OVERRIDE; }; @@ -1552,11 +1542,9 @@ class LArithmeticD FINAL : public LTemplateInstruction<1, 2, 0> { Token::Value op() const { return op_; } - virtual Opcode opcode() const OVERRIDE { - return LInstruction::kArithmeticD; - } - virtual void CompileToNative(LCodeGen* generator) OVERRIDE; - virtual const char* Mnemonic() const OVERRIDE; + Opcode opcode() const OVERRIDE { return LInstruction::kArithmeticD; } + void CompileToNative(LCodeGen* generator) OVERRIDE; + const char* Mnemonic() const OVERRIDE; private: Token::Value op_; @@ -1579,11 +1567,9 @@ class LArithmeticT FINAL : public LTemplateInstruction<1, 3, 0> { LOperand* left() { return inputs_[1]; } LOperand* right() { return inputs_[2]; } - virtual Opcode opcode() const OVERRIDE { - return LInstruction::kArithmeticT; - } - virtual void CompileToNative(LCodeGen* generator) OVERRIDE; - virtual const char* Mnemonic() const OVERRIDE; + Opcode opcode() const OVERRIDE { return LInstruction::kArithmeticT; } + void CompileToNative(LCodeGen* generator) OVERRIDE; + const char* Mnemonic() const OVERRIDE; Token::Value op() const { return op_; } @@ -1696,7 +1682,7 @@ class LLoadKeyed FINAL : public LTemplateInstruction<1, 2, 0> { DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed") DECLARE_HYDROGEN_ACCESSOR(LoadKeyed) - virtual void PrintDataTo(StringStream* stream) OVERRIDE; + void PrintDataTo(StringStream* stream) OVERRIDE; uint32_t base_offset() const { return hydrogen()->base_offset(); } bool key_is_smi() { return hydrogen()->key()->representation().IsTagged(); @@ -1794,7 +1780,7 @@ class LLoadContextSlot FINAL : public LTemplateInstruction<1, 1, 0> { int slot_index() { return hydrogen()->slot_index(); } - virtual void PrintDataTo(StringStream* stream) OVERRIDE; + void PrintDataTo(StringStream* stream) OVERRIDE; }; @@ -1815,7 +1801,7 @@ class LStoreContextSlot FINAL : public LTemplateInstruction<0, 2, 1> { int slot_index() { return hydrogen()->slot_index(); } - virtual void PrintDataTo(StringStream* stream) OVERRIDE; + void PrintDataTo(StringStream* stream) OVERRIDE; }; @@ -1854,7 +1840,7 @@ class LStoreCodeEntry FINAL: public LTemplateInstruction<0, 2, 0> { LOperand* function() { return inputs_[0]; } LOperand* code_object() { return inputs_[1]; } - virtual void PrintDataTo(StringStream* stream); + void PrintDataTo(StringStream* stream) OVERRIDE; DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry, "store-code-entry") DECLARE_HYDROGEN_ACCESSOR(StoreCodeEntry) @@ -1871,7 +1857,7 @@ class LInnerAllocatedObject FINAL: public LTemplateInstruction<1, 2, 0> { LOperand* base_object() const { return inputs_[0]; } LOperand* offset() const { return inputs_[1]; } - virtual void PrintDataTo(StringStream* stream); + void PrintDataTo(StringStream* stream) OVERRIDE; DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject, "inner-allocated-object") }; @@ -1915,7 +1901,7 @@ class LCallJSFunction FINAL : public LTemplateInstruction<1, 1, 0> { DECLARE_CONCRETE_INSTRUCTION(CallJSFunction, "call-js-function") DECLARE_HYDROGEN_ACCESSOR(CallJSFunction) - virtual void PrintDataTo(StringStream* stream) OVERRIDE; + void PrintDataTo(StringStream* stream) OVERRIDE; int arity() const { return hydrogen()->argument_count() - 1; } }; @@ -1937,18 +1923,18 @@ class LCallWithDescriptor FINAL : public LTemplateResultInstruction<1> { private: DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor, "call-with-descriptor") - virtual void PrintDataTo(StringStream* stream) OVERRIDE; + void PrintDataTo(StringStream* stream) OVERRIDE; int arity() const { return hydrogen()->argument_count() - 1; } ZoneList<LOperand*> inputs_; // Iterator support. - virtual int InputCount() FINAL OVERRIDE { return inputs_.length(); } - virtual LOperand* InputAt(int i) FINAL OVERRIDE { return inputs_[i]; } + int InputCount() FINAL { return inputs_.length(); } + LOperand* InputAt(int i) FINAL { return inputs_[i]; } - virtual int TempCount() FINAL OVERRIDE { return 0; } - virtual LOperand* TempAt(int i) FINAL OVERRIDE { return NULL; } + int TempCount() FINAL { return 0; } + LOperand* TempAt(int i) FINAL { return NULL; } }; @@ -1965,7 +1951,7 @@ class LInvokeFunction FINAL : public LTemplateInstruction<1, 2, 0> { DECLARE_CONCRETE_INSTRUCTION(InvokeFunction, "invoke-function") DECLARE_HYDROGEN_ACCESSOR(InvokeFunction) - virtual void PrintDataTo(StringStream* stream) OVERRIDE; + void PrintDataTo(StringStream* stream) OVERRIDE; int arity() const { return hydrogen()->argument_count() - 1; } }; @@ -2001,7 +1987,7 @@ class LCallNew FINAL : public LTemplateInstruction<1, 2, 0> { DECLARE_CONCRETE_INSTRUCTION(CallNew, "call-new") DECLARE_HYDROGEN_ACCESSOR(CallNew) - virtual void PrintDataTo(StringStream* stream) OVERRIDE; + void PrintDataTo(StringStream* stream) OVERRIDE; int arity() const { return hydrogen()->argument_count() - 1; } }; @@ -2020,7 +2006,7 @@ class LCallNewArray FINAL : public LTemplateInstruction<1, 2, 0> { DECLARE_CONCRETE_INSTRUCTION(CallNewArray, "call-new-array") DECLARE_HYDROGEN_ACCESSOR(CallNewArray) - virtual void PrintDataTo(StringStream* stream) OVERRIDE; + void PrintDataTo(StringStream* stream) OVERRIDE; int arity() const { return hydrogen()->argument_count() - 1; } }; @@ -2037,7 +2023,7 @@ class LCallRuntime FINAL : public LTemplateInstruction<1, 1, 0> { DECLARE_CONCRETE_INSTRUCTION(CallRuntime, "call-runtime") DECLARE_HYDROGEN_ACCESSOR(CallRuntime) - virtual bool ClobbersDoubleRegisters(Isolate* isolate) const OVERRIDE { + bool ClobbersDoubleRegisters(Isolate* isolate) const OVERRIDE { return save_doubles() == kDontSaveFPRegs; } @@ -2225,7 +2211,7 @@ class LStoreNamedField FINAL : public LTemplateInstruction<0, 2, 2> { DECLARE_CONCRETE_INSTRUCTION(StoreNamedField, "store-named-field") DECLARE_HYDROGEN_ACCESSOR(StoreNamedField) - virtual void PrintDataTo(StringStream* stream) OVERRIDE; + void PrintDataTo(StringStream* stream) OVERRIDE; }; @@ -2244,7 +2230,7 @@ class LStoreNamedGeneric FINAL : public LTemplateInstruction<0, 3, 0> { DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric, "store-named-generic") DECLARE_HYDROGEN_ACCESSOR(StoreNamedGeneric) - virtual void PrintDataTo(StringStream* stream) OVERRIDE; + void PrintDataTo(StringStream* stream) OVERRIDE; Handle<Object> name() const { return hydrogen()->name(); } StrictMode strict_mode() { return hydrogen()->strict_mode(); } }; @@ -2275,7 +2261,7 @@ class LStoreKeyed FINAL : public LTemplateInstruction<0, 3, 0> { DECLARE_CONCRETE_INSTRUCTION(StoreKeyed, "store-keyed") DECLARE_HYDROGEN_ACCESSOR(StoreKeyed) - virtual void PrintDataTo(StringStream* stream) OVERRIDE; + void PrintDataTo(StringStream* stream) OVERRIDE; uint32_t base_offset() const { return hydrogen()->base_offset(); } bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); } }; @@ -2301,7 +2287,7 @@ class LStoreKeyedGeneric FINAL : public LTemplateInstruction<0, 4, 0> { DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric, "store-keyed-generic") DECLARE_HYDROGEN_ACCESSOR(StoreKeyedGeneric) - virtual void PrintDataTo(StringStream* stream) OVERRIDE; + void PrintDataTo(StringStream* stream) OVERRIDE; StrictMode strict_mode() { return hydrogen()->strict_mode(); } }; @@ -2328,7 +2314,7 @@ class LTransitionElementsKind FINAL : public LTemplateInstruction<0, 2, 2> { "transition-elements-kind") DECLARE_HYDROGEN_ACCESSOR(TransitionElementsKind) - virtual void PrintDataTo(StringStream* stream) OVERRIDE; + void PrintDataTo(StringStream* stream) OVERRIDE; Handle<Map> original_map() { return hydrogen()->original_map().handle(); } Handle<Map> transitioned_map() { @@ -2628,15 +2614,13 @@ class LTypeofIsAndBranch FINAL : public LControlInstruction<1, 0> { Handle<String> type_literal() { return hydrogen()->type_literal(); } - virtual void PrintDataTo(StringStream* stream) OVERRIDE; + void PrintDataTo(StringStream* stream) OVERRIDE; }; class LOsrEntry FINAL : public LTemplateInstruction<0, 0, 0> { public: - virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { - return false; - } + bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; } DECLARE_CONCRETE_INSTRUCTION(OsrEntry, "osr-entry") }; @@ -2843,7 +2827,7 @@ class LChunkBuilder FINAL : public LChunkBuilderBase { // An input operand in register, stack slot or a constant operand. // Will not be moved to a register even if one is freely available. - virtual MUST_USE_RESULT LOperand* UseAny(HValue* value) OVERRIDE; + MUST_USE_RESULT LOperand* UseAny(HValue* value) OVERRIDE; // Temporary operand that must be in a register. MUST_USE_RESULT LUnallocated* TempRegister(); diff --git a/src/x87/macro-assembler-x87.cc b/src/x87/macro-assembler-x87.cc index a1fa3317..008b2af6 100644 --- a/src/x87/macro-assembler-x87.cc +++ b/src/x87/macro-assembler-x87.cc @@ -13,7 +13,7 @@ #include "src/cpu-profiler.h" #include "src/debug.h" #include "src/isolate-inl.h" -#include "src/runtime.h" +#include "src/runtime/runtime.h" #include "src/serialize.h" namespace v8 { @@ -278,7 +278,7 @@ void MacroAssembler::TruncateHeapNumberToI(Register result_reg, } -void MacroAssembler::LoadUint32NoSSE2(Register src) { +void MacroAssembler::LoadUint32NoSSE2(const Operand& src) { Label done; push(src); fild_s(Operand(esp, 0)); @@ -654,16 +654,16 @@ void MacroAssembler::CheckMap(Register obj, } -void MacroAssembler::DispatchMap(Register obj, - Register unused, - Handle<Map> map, - Handle<Code> success, - SmiCheckType smi_check_type) { +void MacroAssembler::DispatchWeakMap(Register obj, Register scratch1, + Register scratch2, Handle<WeakCell> cell, + Handle<Code> success, + SmiCheckType smi_check_type) { Label fail; if (smi_check_type == DO_SMI_CHECK) { JumpIfSmi(obj, &fail); } - cmp(FieldOperand(obj, HeapObject::kMapOffset), Immediate(map)); + mov(scratch1, FieldOperand(obj, HeapObject::kMapOffset)); + CmpWeakValue(scratch1, cell, scratch2); j(equal, success); bind(&fail); @@ -867,6 +867,13 @@ void MacroAssembler::Prologue(bool code_pre_aging) { } +void MacroAssembler::EnterFrame(StackFrame::Type type, + bool load_constant_pool_pointer_reg) { + // Out-of-line constant pool not implemented on x87. + UNREACHABLE(); +} + + void MacroAssembler::EnterFrame(StackFrame::Type type) { push(ebp); mov(ebp, esp); @@ -906,8 +913,10 @@ void MacroAssembler::EnterExitFramePrologue() { // Save the frame pointer and the context in top. ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress, isolate()); ExternalReference context_address(Isolate::kContextAddress, isolate()); + ExternalReference c_function_address(Isolate::kCFunctionAddress, isolate()); mov(Operand::StaticVariable(c_entry_fp_address), ebp); mov(Operand::StaticVariable(context_address), esi); + mov(Operand::StaticVariable(c_function_address), ebx); } @@ -1312,10 +1321,10 @@ void MacroAssembler::LoadFromNumberDictionary(Label* miss, } bind(&done); - // Check that the value is a normal propety. + // Check that the value is a field property. const int kDetailsOffset = SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize; - DCHECK_EQ(NORMAL, 0); + DCHECK_EQ(FIELD, 0); test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset), Immediate(PropertyDetails::TypeField::kMask << kSmiTagSize)); j(not_zero, miss); @@ -2535,6 +2544,21 @@ void MacroAssembler::PushHeapObject(Handle<HeapObject> object) { } +void MacroAssembler::CmpWeakValue(Register value, Handle<WeakCell> cell, + Register scratch) { + mov(scratch, cell); + cmp(value, FieldOperand(scratch, WeakCell::kValueOffset)); +} + + +void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell, + Label* miss) { + mov(value, cell); + mov(value, FieldOperand(value, WeakCell::kValueOffset)); + JumpIfSmi(value, miss); +} + + void MacroAssembler::Ret() { ret(0); } @@ -3063,18 +3087,6 @@ void MacroAssembler::CheckPageFlagForMap( } -void MacroAssembler::CheckMapDeprecated(Handle<Map> map, - Register scratch, - Label* if_deprecated) { - if (map->CanBeDeprecated()) { - mov(scratch, map); - mov(scratch, FieldOperand(scratch, Map::kBitField3Offset)); - and_(scratch, Immediate(Map::Deprecated::kMask)); - j(not_zero, if_deprecated); - } -} - - void MacroAssembler::JumpIfBlack(Register object, Register scratch0, Register scratch1, diff --git a/src/x87/macro-assembler-x87.h b/src/x87/macro-assembler-x87.h index c9e9087f..b7972651 100644 --- a/src/x87/macro-assembler-x87.h +++ b/src/x87/macro-assembler-x87.h @@ -93,10 +93,6 @@ class MacroAssembler: public Assembler { Label* condition_met, Label::Distance condition_met_distance = Label::kFar); - void CheckMapDeprecated(Handle<Map> map, - Register scratch, - Label* if_deprecated); - // Check if object is in new space. Jumps if the object is not in new space. // The register scratch can be object itself, but scratch will be clobbered. void JumpIfNotInNewSpace(Register object, @@ -277,6 +273,9 @@ class MacroAssembler: public Assembler { } } + void CmpWeakValue(Register value, Handle<WeakCell> cell, Register scratch); + void LoadWeakValue(Register value, Handle<WeakCell> cell, Label* miss); + // --------------------------------------------------------------------------- // JavaScript invokes @@ -379,14 +378,12 @@ class MacroAssembler: public Assembler { Label* fail, SmiCheckType smi_check_type); - // Check if the map of an object is equal to a specified map and branch to a - // specified target if equal. Skip the smi check if not required (object is - // known to be a heap object) - void DispatchMap(Register obj, - Register unused, - Handle<Map> map, - Handle<Code> success, - SmiCheckType smi_check_type); + // Check if the map of an object is equal to a specified weak map and branch + // to a specified target if equal. Skip the smi check if not required + // (object is known to be a heap object) + void DispatchWeakMap(Register obj, Register scratch1, Register scratch2, + Handle<WeakCell> cell, Handle<Code> success, + SmiCheckType smi_check_type); // Check if the object in register heap_object is a string. Afterwards the // register map contains the object map and the register instance_type @@ -458,7 +455,10 @@ class MacroAssembler: public Assembler { j(not_carry, is_smi); } - void LoadUint32NoSSE2(Register src); + void LoadUint32NoSSE2(Register src) { + LoadUint32NoSSE2(Operand(src)); + } + void LoadUint32NoSSE2(const Operand& src); // Jump the register contains a smi. inline void JumpIfSmi(Register value, @@ -904,6 +904,7 @@ class MacroAssembler: public Assembler { // Activation support. void EnterFrame(StackFrame::Type type); + void EnterFrame(StackFrame::Type type, bool load_constant_pool_pointer_reg); void LeaveFrame(StackFrame::Type type); // Expects object in eax and returns map with validated enum cache |