Revision f230a1cf deps/v8/src/arm/full-codegen-arm.cc
deps/v8/src/arm/full-codegen-arm.cc | ||
---|---|---|
148 | 148 |
// receiver object). r5 is zero for method calls and non-zero for |
149 | 149 |
// function calls. |
150 | 150 |
if (!info->is_classic_mode() || info->is_native()) { |
151 |
Label ok; |
|
152 | 151 |
__ cmp(r5, Operand::Zero()); |
153 |
__ b(eq, &ok); |
|
154 | 152 |
int receiver_offset = info->scope()->num_parameters() * kPointerSize; |
155 | 153 |
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex); |
156 |
__ str(r2, MemOperand(sp, receiver_offset)); |
|
157 |
__ bind(&ok); |
|
154 |
__ str(r2, MemOperand(sp, receiver_offset), ne); |
|
158 | 155 |
} |
159 | 156 |
|
160 | 157 |
// Open a frame scope to indicate that there is a frame on the stack. The |
... | ... | |
163 | 160 |
FrameScope frame_scope(masm_, StackFrame::MANUAL); |
164 | 161 |
|
165 | 162 |
info->set_prologue_offset(masm_->pc_offset()); |
166 |
{ |
|
167 |
PredictableCodeSizeScope predictible_code_size_scope( |
|
168 |
masm_, kNoCodeAgeSequenceLength * Assembler::kInstrSize); |
|
169 |
// The following three instructions must remain together and unmodified |
|
170 |
// for code aging to work properly. |
|
171 |
__ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit()); |
|
172 |
__ nop(ip.code()); |
|
173 |
// Adjust FP to point to saved FP. |
|
174 |
__ add(fp, sp, Operand(2 * kPointerSize)); |
|
175 |
} |
|
163 |
__ Prologue(BUILD_FUNCTION_FRAME); |
|
176 | 164 |
info->AddNoFrameRange(0, masm_->pc_offset()); |
177 | 165 |
|
178 | 166 |
{ Comment cmnt(masm_, "[ Allocate locals"); |
... | ... | |
1167 | 1155 |
Handle<Object>(Smi::FromInt(TypeFeedbackCells::kForInFastCaseMarker), |
1168 | 1156 |
isolate())); |
1169 | 1157 |
RecordTypeFeedbackCell(stmt->ForInFeedbackId(), cell); |
1170 |
__ LoadHeapObject(r1, cell);
|
|
1158 |
__ Move(r1, cell);
|
|
1171 | 1159 |
__ mov(r2, Operand(Smi::FromInt(TypeFeedbackCells::kForInSlowCaseMarker))); |
1172 | 1160 |
__ str(r2, FieldMemOperand(r1, Cell::kValueOffset)); |
1173 | 1161 |
|
... | ... | |
1651 | 1639 |
__ mov(r0, Operand(Smi::FromInt(flags))); |
1652 | 1640 |
int properties_count = constant_properties->length() / 2; |
1653 | 1641 |
if ((FLAG_track_double_fields && expr->may_store_doubles()) || |
1654 |
expr->depth() > 1) { |
|
1655 |
__ Push(r3, r2, r1, r0); |
|
1656 |
__ CallRuntime(Runtime::kCreateObjectLiteral, 4); |
|
1657 |
} else if (Serializer::enabled() || flags != ObjectLiteral::kFastElements || |
|
1642 |
expr->depth() > 1 || Serializer::enabled() || |
|
1643 |
flags != ObjectLiteral::kFastElements || |
|
1658 | 1644 |
properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) { |
1659 | 1645 |
__ Push(r3, r2, r1, r0); |
1660 |
__ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
|
|
1646 |
__ CallRuntime(Runtime::kCreateObjectLiteral, 4); |
|
1661 | 1647 |
} else { |
1662 | 1648 |
FastCloneShallowObjectStub stub(properties_count); |
1663 | 1649 |
__ CallStub(&stub); |
... | ... | |
3592 | 3578 |
void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) { |
3593 | 3579 |
ZoneList<Expression*>* args = expr->arguments(); |
3594 | 3580 |
ASSERT_EQ(args->length(), 1); |
3595 |
// Load the argument on the stack and call the stub.
|
|
3596 |
VisitForStackValue(args->at(0));
|
|
3581 |
// Load the argument into r0 and call the stub.
|
|
3582 |
VisitForAccumulatorValue(args->at(0));
|
|
3597 | 3583 |
|
3598 | 3584 |
NumberToStringStub stub; |
3599 | 3585 |
__ CallStub(&stub); |
... | ... | |
3964 | 3950 |
|
3965 | 3951 |
|
3966 | 3952 |
void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { |
3967 |
Label bailout, done, one_char_separator, long_separator, |
|
3968 |
non_trivial_array, not_size_one_array, loop, |
|
3969 |
empty_separator_loop, one_char_separator_loop, |
|
3953 |
Label bailout, done, one_char_separator, long_separator, non_trivial_array, |
|
3954 |
not_size_one_array, loop, empty_separator_loop, one_char_separator_loop, |
|
3970 | 3955 |
one_char_separator_loop_entry, long_separator_loop; |
3971 | 3956 |
ZoneList<Expression*>* args = expr->arguments(); |
3972 | 3957 |
ASSERT(args->length() == 2); |
... | ... | |
3984 | 3969 |
Register string = r4; |
3985 | 3970 |
Register element = r5; |
3986 | 3971 |
Register elements_end = r6; |
3987 |
Register scratch1 = r7; |
|
3988 |
Register scratch2 = r9; |
|
3972 |
Register scratch = r9; |
|
3989 | 3973 |
|
3990 | 3974 |
// Separator operand is on the stack. |
3991 | 3975 |
__ pop(separator); |
3992 | 3976 |
|
3993 | 3977 |
// Check that the array is a JSArray. |
3994 | 3978 |
__ JumpIfSmi(array, &bailout); |
3995 |
__ CompareObjectType(array, scratch1, scratch2, JS_ARRAY_TYPE);
|
|
3979 |
__ CompareObjectType(array, scratch, array_length, JS_ARRAY_TYPE);
|
|
3996 | 3980 |
__ b(ne, &bailout); |
3997 | 3981 |
|
3998 | 3982 |
// Check that the array has fast elements. |
3999 |
__ CheckFastElements(scratch1, scratch2, &bailout);
|
|
3983 |
__ CheckFastElements(scratch, array_length, &bailout);
|
|
4000 | 3984 |
|
4001 | 3985 |
// If the array has length zero, return the empty string. |
4002 | 3986 |
__ ldr(array_length, FieldMemOperand(array, JSArray::kLengthOffset)); |
... | ... | |
4033 | 4017 |
__ bind(&loop); |
4034 | 4018 |
__ ldr(string, MemOperand(element, kPointerSize, PostIndex)); |
4035 | 4019 |
__ JumpIfSmi(string, &bailout); |
4036 |
__ ldr(scratch1, FieldMemOperand(string, HeapObject::kMapOffset));
|
|
4037 |
__ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
|
|
4038 |
__ JumpIfInstanceTypeIsNotSequentialAscii(scratch1, scratch2, &bailout);
|
|
4039 |
__ ldr(scratch1, FieldMemOperand(string, SeqOneByteString::kLengthOffset));
|
|
4040 |
__ add(string_length, string_length, Operand(scratch1), SetCC);
|
|
4020 |
__ ldr(scratch, FieldMemOperand(string, HeapObject::kMapOffset)); |
|
4021 |
__ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
|
|
4022 |
__ JumpIfInstanceTypeIsNotSequentialAscii(scratch, scratch, &bailout);
|
|
4023 |
__ ldr(scratch, FieldMemOperand(string, SeqOneByteString::kLengthOffset)); |
|
4024 |
__ add(string_length, string_length, Operand(scratch), SetCC); |
|
4041 | 4025 |
__ b(vs, &bailout); |
4042 | 4026 |
__ cmp(element, elements_end); |
4043 | 4027 |
__ b(lt, &loop); |
... | ... | |
4058 | 4042 |
|
4059 | 4043 |
// Check that the separator is a flat ASCII string. |
4060 | 4044 |
__ JumpIfSmi(separator, &bailout); |
4061 |
__ ldr(scratch1, FieldMemOperand(separator, HeapObject::kMapOffset));
|
|
4062 |
__ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
|
|
4063 |
__ JumpIfInstanceTypeIsNotSequentialAscii(scratch1, scratch2, &bailout);
|
|
4045 |
__ ldr(scratch, FieldMemOperand(separator, HeapObject::kMapOffset)); |
|
4046 |
__ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
|
|
4047 |
__ JumpIfInstanceTypeIsNotSequentialAscii(scratch, scratch, &bailout);
|
|
4064 | 4048 |
|
4065 | 4049 |
// Add (separator length times array_length) - separator length to the |
4066 | 4050 |
// string_length to get the length of the result string. array_length is not |
4067 | 4051 |
// smi but the other values are, so the result is a smi |
4068 |
__ ldr(scratch1, FieldMemOperand(separator, SeqOneByteString::kLengthOffset));
|
|
4069 |
__ sub(string_length, string_length, Operand(scratch1));
|
|
4070 |
__ smull(scratch2, ip, array_length, scratch1);
|
|
4052 |
__ ldr(scratch, FieldMemOperand(separator, SeqOneByteString::kLengthOffset)); |
|
4053 |
__ sub(string_length, string_length, Operand(scratch)); |
|
4054 |
__ smull(scratch, ip, array_length, scratch);
|
|
4071 | 4055 |
// Check for smi overflow. No overflow if higher 33 bits of 64-bit result are |
4072 | 4056 |
// zero. |
4073 | 4057 |
__ cmp(ip, Operand::Zero()); |
4074 | 4058 |
__ b(ne, &bailout); |
4075 |
__ tst(scratch2, Operand(0x80000000));
|
|
4059 |
__ tst(scratch, Operand(0x80000000)); |
|
4076 | 4060 |
__ b(ne, &bailout); |
4077 |
__ add(string_length, string_length, Operand(scratch2), SetCC);
|
|
4061 |
__ add(string_length, string_length, Operand(scratch), SetCC); |
|
4078 | 4062 |
__ b(vs, &bailout); |
4079 | 4063 |
__ SmiUntag(string_length); |
4080 | 4064 |
|
... | ... | |
4091 | 4075 |
// array_length: Length of the array. |
4092 | 4076 |
__ AllocateAsciiString(result, |
4093 | 4077 |
string_length, |
4094 |
scratch1,
|
|
4095 |
scratch2,
|
|
4096 |
elements_end, |
|
4078 |
scratch, |
|
4079 |
string, // used as scratch
|
|
4080 |
elements_end, // used as scratch
|
|
4097 | 4081 |
&bailout); |
4098 | 4082 |
// Prepare for looping. Set up elements_end to end of the array. Set |
4099 | 4083 |
// result_pos to the position of the result where to write the first |
... | ... | |
4106 | 4090 |
Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
4107 | 4091 |
|
4108 | 4092 |
// Check the length of the separator. |
4109 |
__ ldr(scratch1, FieldMemOperand(separator, SeqOneByteString::kLengthOffset));
|
|
4110 |
__ cmp(scratch1, Operand(Smi::FromInt(1)));
|
|
4093 |
__ ldr(scratch, FieldMemOperand(separator, SeqOneByteString::kLengthOffset)); |
|
4094 |
__ cmp(scratch, Operand(Smi::FromInt(1))); |
|
4111 | 4095 |
__ b(eq, &one_char_separator); |
4112 | 4096 |
__ b(gt, &long_separator); |
4113 | 4097 |
|
... | ... | |
4125 | 4109 |
__ add(string, |
4126 | 4110 |
string, |
4127 | 4111 |
Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
4128 |
__ CopyBytes(string, result_pos, string_length, scratch1);
|
|
4112 |
__ CopyBytes(string, result_pos, string_length, scratch); |
|
4129 | 4113 |
__ cmp(element, elements_end); |
4130 | 4114 |
__ b(lt, &empty_separator_loop); // End while (element < elements_end). |
4131 | 4115 |
ASSERT(result.is(r0)); |
... | ... | |
4157 | 4141 |
__ add(string, |
4158 | 4142 |
string, |
4159 | 4143 |
Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
4160 |
__ CopyBytes(string, result_pos, string_length, scratch1);
|
|
4144 |
__ CopyBytes(string, result_pos, string_length, scratch); |
|
4161 | 4145 |
__ cmp(element, elements_end); |
4162 | 4146 |
__ b(lt, &one_char_separator_loop); // End while (element < elements_end). |
4163 | 4147 |
ASSERT(result.is(r0)); |
... | ... | |
4178 | 4162 |
__ add(string, |
4179 | 4163 |
separator, |
4180 | 4164 |
Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
4181 |
__ CopyBytes(string, result_pos, string_length, scratch1);
|
|
4165 |
__ CopyBytes(string, result_pos, string_length, scratch); |
|
4182 | 4166 |
|
4183 | 4167 |
__ bind(&long_separator); |
4184 | 4168 |
__ ldr(string, MemOperand(element, kPointerSize, PostIndex)); |
... | ... | |
4187 | 4171 |
__ add(string, |
4188 | 4172 |
string, |
4189 | 4173 |
Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
4190 |
__ CopyBytes(string, result_pos, string_length, scratch1);
|
|
4174 |
__ CopyBytes(string, result_pos, string_length, scratch); |
|
4191 | 4175 |
__ cmp(element, elements_end); |
4192 | 4176 |
__ b(lt, &long_separator_loop); // End while (element < elements_end). |
4193 | 4177 |
ASSERT(result.is(r0)); |
... | ... | |
4894 | 4878 |
|
4895 | 4879 |
#undef __ |
4896 | 4880 |
|
4881 |
|
|
4882 |
static const int32_t kBranchBeforeInterrupt = 0x5a000004; |
|
4883 |
|
|
4884 |
|
|
4885 |
void BackEdgeTable::PatchAt(Code* unoptimized_code, |
|
4886 |
Address pc, |
|
4887 |
BackEdgeState target_state, |
|
4888 |
Code* replacement_code) { |
|
4889 |
static const int kInstrSize = Assembler::kInstrSize; |
|
4890 |
Address branch_address = pc - 3 * kInstrSize; |
|
4891 |
CodePatcher patcher(branch_address, 1); |
|
4892 |
|
|
4893 |
switch (target_state) { |
|
4894 |
case INTERRUPT: |
|
4895 |
// <decrement profiling counter> |
|
4896 |
// 2a 00 00 01 bpl ok |
|
4897 |
// e5 9f c? ?? ldr ip, [pc, <interrupt stub address>] |
|
4898 |
// e1 2f ff 3c blx ip |
|
4899 |
// ok-label |
|
4900 |
patcher.masm()->b(4 * kInstrSize, pl); // Jump offset is 4 instructions. |
|
4901 |
ASSERT_EQ(kBranchBeforeInterrupt, Memory::int32_at(branch_address)); |
|
4902 |
break; |
|
4903 |
case ON_STACK_REPLACEMENT: |
|
4904 |
case OSR_AFTER_STACK_CHECK: |
|
4905 |
// <decrement profiling counter> |
|
4906 |
// e1 a0 00 00 mov r0, r0 (NOP) |
|
4907 |
// e5 9f c? ?? ldr ip, [pc, <on-stack replacement address>] |
|
4908 |
// e1 2f ff 3c blx ip |
|
4909 |
// ok-label |
|
4910 |
patcher.masm()->nop(); |
|
4911 |
break; |
|
4912 |
} |
|
4913 |
|
|
4914 |
Address pc_immediate_load_address = pc - 2 * kInstrSize; |
|
4915 |
// Replace the call address. |
|
4916 |
uint32_t interrupt_address_offset = |
|
4917 |
Memory::uint16_at(pc_immediate_load_address) & 0xfff; |
|
4918 |
Address interrupt_address_pointer = pc + interrupt_address_offset; |
|
4919 |
Memory::uint32_at(interrupt_address_pointer) = |
|
4920 |
reinterpret_cast<uint32_t>(replacement_code->entry()); |
|
4921 |
|
|
4922 |
unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch( |
|
4923 |
unoptimized_code, pc_immediate_load_address, replacement_code); |
|
4924 |
} |
|
4925 |
|
|
4926 |
|
|
4927 |
BackEdgeTable::BackEdgeState BackEdgeTable::GetBackEdgeState( |
|
4928 |
Isolate* isolate, |
|
4929 |
Code* unoptimized_code, |
|
4930 |
Address pc) { |
|
4931 |
static const int kInstrSize = Assembler::kInstrSize; |
|
4932 |
ASSERT(Memory::int32_at(pc - kInstrSize) == kBlxIp); |
|
4933 |
|
|
4934 |
Address branch_address = pc - 3 * kInstrSize; |
|
4935 |
Address pc_immediate_load_address = pc - 2 * kInstrSize; |
|
4936 |
uint32_t interrupt_address_offset = |
|
4937 |
Memory::uint16_at(pc_immediate_load_address) & 0xfff; |
|
4938 |
Address interrupt_address_pointer = pc + interrupt_address_offset; |
|
4939 |
|
|
4940 |
if (Memory::int32_at(branch_address) == kBranchBeforeInterrupt) { |
|
4941 |
ASSERT(Memory::uint32_at(interrupt_address_pointer) == |
|
4942 |
reinterpret_cast<uint32_t>( |
|
4943 |
isolate->builtins()->InterruptCheck()->entry())); |
|
4944 |
ASSERT(Assembler::IsLdrPcImmediateOffset( |
|
4945 |
Assembler::instr_at(pc_immediate_load_address))); |
|
4946 |
return INTERRUPT; |
|
4947 |
} |
|
4948 |
|
|
4949 |
ASSERT(Assembler::IsNop(Assembler::instr_at(branch_address))); |
|
4950 |
ASSERT(Assembler::IsLdrPcImmediateOffset( |
|
4951 |
Assembler::instr_at(pc_immediate_load_address))); |
|
4952 |
|
|
4953 |
if (Memory::uint32_at(interrupt_address_pointer) == |
|
4954 |
reinterpret_cast<uint32_t>( |
|
4955 |
isolate->builtins()->OnStackReplacement()->entry())) { |
|
4956 |
return ON_STACK_REPLACEMENT; |
|
4957 |
} |
|
4958 |
|
|
4959 |
ASSERT(Memory::uint32_at(interrupt_address_pointer) == |
|
4960 |
reinterpret_cast<uint32_t>( |
|
4961 |
isolate->builtins()->OsrAfterStackCheck()->entry())); |
|
4962 |
return OSR_AFTER_STACK_CHECK; |
|
4963 |
} |
|
4964 |
|
|
4965 |
|
|
4897 | 4966 |
} } // namespace v8::internal |
4898 | 4967 |
|
4899 | 4968 |
#endif // V8_TARGET_ARCH_ARM |
Also available in: Unified diff