blob: 727bb1b22703cfee80acdbbdddb3747dedc2d128 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2012 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004
5#ifndef V8_ARM_CODE_STUBS_ARM_H_
6#define V8_ARM_CODE_STUBS_ARM_H_
7
Kristian Monsen80d68ea2010-09-08 11:05:35 +01008namespace v8 {
9namespace internal {
10
11
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012void ArrayNativeCode(MacroAssembler* masm, Label* call_generic_code);
Steve Block1e0659c2011-05-24 12:43:12 +010013
14
Ben Murdoch692be652012-01-10 18:47:50 +000015class StringHelper : public AllStatic {
16 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017 // Generate code for copying a large number of characters. This function
18 // is allowed to spend extra time setting up conditions to make copying
19 // faster. Copying of overlapping regions is not supported.
Ben Murdoch692be652012-01-10 18:47:50 +000020 // Dest register ends at the position after the last character written.
21 static void GenerateCopyCharacters(MacroAssembler* masm,
22 Register dest,
23 Register src,
24 Register count,
25 Register scratch,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000026 String::Encoding encoding);
Ben Murdoch692be652012-01-10 18:47:50 +000027
Ben Murdochb8a8cc12014-11-26 15:28:44 +000028 // Compares two flat one-byte strings and returns result in r0.
29 static void GenerateCompareFlatOneByteStrings(
30 MacroAssembler* masm, Register left, Register right, Register scratch1,
31 Register scratch2, Register scratch3, Register scratch4);
Ben Murdoch692be652012-01-10 18:47:50 +000032
Ben Murdochb8a8cc12014-11-26 15:28:44 +000033 // Compares two flat one-byte strings for equality and returns result in r0.
34 static void GenerateFlatOneByteStringEquals(MacroAssembler* masm,
35 Register left, Register right,
Kristian Monsen80d68ea2010-09-08 11:05:35 +010036 Register scratch1,
37 Register scratch2,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000038 Register scratch3);
Kristian Monsen80d68ea2010-09-08 11:05:35 +010039
Ben Murdoch257744e2011-11-30 15:57:28 +000040 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000041 static void GenerateOneByteCharsCompareLoop(
42 MacroAssembler* masm, Register left, Register right, Register length,
43 Register scratch1, Register scratch2, Label* chars_not_equal);
Ben Murdoch257744e2011-11-30 15:57:28 +000044
Ben Murdochb8a8cc12014-11-26 15:28:44 +000045 DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
Kristian Monsen80d68ea2010-09-08 11:05:35 +010046};
47
48
Kristian Monsen80d68ea2010-09-08 11:05:35 +010049// This stub can convert a signed int32 to a heap number (double). It does
50// not work for int32s that are in Smi range! No GC occurs during this stub
51// so you don't have to set up the frame.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000052class WriteInt32ToHeapNumberStub : public PlatformCodeStub {
Kristian Monsen80d68ea2010-09-08 11:05:35 +010053 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000054 WriteInt32ToHeapNumberStub(Isolate* isolate, Register the_int,
55 Register the_heap_number, Register scratch)
56 : PlatformCodeStub(isolate) {
57 minor_key_ = IntRegisterBits::encode(the_int.code()) |
58 HeapNumberRegisterBits::encode(the_heap_number.code()) |
59 ScratchRegisterBits::encode(scratch.code());
60 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +010061
Ben Murdochb8a8cc12014-11-26 15:28:44 +000062 static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010063
Kristian Monsen80d68ea2010-09-08 11:05:35 +010064 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000065 Register the_int() const {
66 return Register::from_code(IntRegisterBits::decode(minor_key_));
67 }
68
69 Register the_heap_number() const {
70 return Register::from_code(HeapNumberRegisterBits::decode(minor_key_));
71 }
72
73 Register scratch() const {
74 return Register::from_code(ScratchRegisterBits::decode(minor_key_));
75 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +010076
77 // Minor key encoding in 16 bits.
78 class IntRegisterBits: public BitField<int, 0, 4> {};
79 class HeapNumberRegisterBits: public BitField<int, 4, 4> {};
80 class ScratchRegisterBits: public BitField<int, 8, 4> {};
81
Ben Murdochb8a8cc12014-11-26 15:28:44 +000082 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
83 DEFINE_PLATFORM_CODE_STUB(WriteInt32ToHeapNumber, PlatformCodeStub);
Kristian Monsen80d68ea2010-09-08 11:05:35 +010084};
85
86
Ben Murdochb8a8cc12014-11-26 15:28:44 +000087class RecordWriteStub: public PlatformCodeStub {
Kristian Monsen80d68ea2010-09-08 11:05:35 +010088 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000089 RecordWriteStub(Isolate* isolate,
90 Register object,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010091 Register value,
92 Register address,
93 RememberedSetAction remembered_set_action,
94 SaveFPRegsMode fp_mode)
Ben Murdochb8a8cc12014-11-26 15:28:44 +000095 : PlatformCodeStub(isolate),
Ben Murdoch3ef787d2012-04-12 10:51:47 +010096 regs_(object, // An input reg.
97 address, // An input reg.
98 value) { // One scratch reg.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000099 minor_key_ = ObjectBits::encode(object.code()) |
100 ValueBits::encode(value.code()) |
101 AddressBits::encode(address.code()) |
102 RememberedSetActionBits::encode(remembered_set_action) |
103 SaveFPRegsModeBits::encode(fp_mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100104 }
105
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000106 RecordWriteStub(uint32_t key, Isolate* isolate)
107 : PlatformCodeStub(key, isolate), regs_(object(), address(), value()) {}
108
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100109 enum Mode {
110 STORE_BUFFER_ONLY,
111 INCREMENTAL,
112 INCREMENTAL_COMPACTION
113 };
114
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100115 virtual bool SometimesSetsUpAFrame() { return false; }
116
117 static void PatchBranchIntoNop(MacroAssembler* masm, int pos) {
118 masm->instr_at_put(pos, (masm->instr_at(pos) & ~B27) | (B24 | B20));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000119 DCHECK(Assembler::IsTstImmediate(masm->instr_at(pos)));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100120 }
121
122 static void PatchNopIntoBranch(MacroAssembler* masm, int pos) {
123 masm->instr_at_put(pos, (masm->instr_at(pos) & ~(B24 | B20)) | B27);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000124 DCHECK(Assembler::IsBranch(masm->instr_at(pos)));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100125 }
126
127 static Mode GetMode(Code* stub) {
128 Instr first_instruction = Assembler::instr_at(stub->instruction_start());
129 Instr second_instruction = Assembler::instr_at(stub->instruction_start() +
130 Assembler::kInstrSize);
131
132 if (Assembler::IsBranch(first_instruction)) {
133 return INCREMENTAL;
134 }
135
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000136 DCHECK(Assembler::IsTstImmediate(first_instruction));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100137
138 if (Assembler::IsBranch(second_instruction)) {
139 return INCREMENTAL_COMPACTION;
140 }
141
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000142 DCHECK(Assembler::IsTstImmediate(second_instruction));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100143
144 return STORE_BUFFER_ONLY;
145 }
146
147 static void Patch(Code* stub, Mode mode) {
148 MacroAssembler masm(NULL,
149 stub->instruction_start(),
150 stub->instruction_size());
151 switch (mode) {
152 case STORE_BUFFER_ONLY:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000153 DCHECK(GetMode(stub) == INCREMENTAL ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100154 GetMode(stub) == INCREMENTAL_COMPACTION);
155 PatchBranchIntoNop(&masm, 0);
156 PatchBranchIntoNop(&masm, Assembler::kInstrSize);
157 break;
158 case INCREMENTAL:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000159 DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100160 PatchNopIntoBranch(&masm, 0);
161 break;
162 case INCREMENTAL_COMPACTION:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000163 DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100164 PatchNopIntoBranch(&masm, Assembler::kInstrSize);
165 break;
166 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000167 DCHECK(GetMode(stub) == mode);
168 CpuFeatures::FlushICache(stub->instruction_start(),
169 2 * Assembler::kInstrSize);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100170 }
171
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000172 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
173
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100174 private:
175 // This is a helper class for freeing up 3 scratch registers. The input is
176 // two registers that must be preserved and one scratch register provided by
177 // the caller.
178 class RegisterAllocation {
179 public:
180 RegisterAllocation(Register object,
181 Register address,
182 Register scratch0)
183 : object_(object),
184 address_(address),
185 scratch0_(scratch0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000186 DCHECK(!AreAliased(scratch0, object, address, no_reg));
187 scratch1_ = GetRegisterThatIsNotOneOf(object_, address_, scratch0_);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100188 }
189
190 void Save(MacroAssembler* masm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000191 DCHECK(!AreAliased(object_, address_, scratch1_, scratch0_));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100192 // We don't have to save scratch0_ because it was given to us as
193 // a scratch register.
194 masm->push(scratch1_);
195 }
196
197 void Restore(MacroAssembler* masm) {
198 masm->pop(scratch1_);
199 }
200
201 // If we have to call into C then we need to save and restore all caller-
202 // saved registers that were not already preserved. The scratch registers
203 // will be restored by other means so we don't bother pushing them here.
204 void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
205 masm->stm(db_w, sp, (kCallerSaved | lr.bit()) & ~scratch1_.bit());
206 if (mode == kSaveFPRegs) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000207 masm->SaveFPRegs(sp, scratch0_);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100208 }
209 }
210
211 inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
212 SaveFPRegsMode mode) {
213 if (mode == kSaveFPRegs) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000214 masm->RestoreFPRegs(sp, scratch0_);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100215 }
216 masm->ldm(ia_w, sp, (kCallerSaved | lr.bit()) & ~scratch1_.bit());
217 }
218
219 inline Register object() { return object_; }
220 inline Register address() { return address_; }
221 inline Register scratch0() { return scratch0_; }
222 inline Register scratch1() { return scratch1_; }
223
224 private:
225 Register object_;
226 Register address_;
227 Register scratch0_;
228 Register scratch1_;
229
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100230 friend class RecordWriteStub;
231 };
232
233 enum OnNoNeedToInformIncrementalMarker {
234 kReturnOnNoNeedToInformIncrementalMarker,
235 kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
236 };
237
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000238 virtual inline Major MajorKey() const FINAL OVERRIDE { return RecordWrite; }
239
240 virtual void Generate(MacroAssembler* masm) OVERRIDE;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100241 void GenerateIncremental(MacroAssembler* masm, Mode mode);
242 void CheckNeedsToInformIncrementalMarker(
243 MacroAssembler* masm,
244 OnNoNeedToInformIncrementalMarker on_no_need,
245 Mode mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000246 void InformIncrementalMarker(MacroAssembler* masm);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100247
248 void Activate(Code* code) {
249 code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
250 }
251
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000252 Register object() const {
253 return Register::from_code(ObjectBits::decode(minor_key_));
254 }
255
256 Register value() const {
257 return Register::from_code(ValueBits::decode(minor_key_));
258 }
259
260 Register address() const {
261 return Register::from_code(AddressBits::decode(minor_key_));
262 }
263
264 RememberedSetAction remembered_set_action() const {
265 return RememberedSetActionBits::decode(minor_key_);
266 }
267
268 SaveFPRegsMode save_fp_regs_mode() const {
269 return SaveFPRegsModeBits::decode(minor_key_);
270 }
271
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100272 class ObjectBits: public BitField<int, 0, 4> {};
273 class ValueBits: public BitField<int, 4, 4> {};
274 class AddressBits: public BitField<int, 8, 4> {};
275 class RememberedSetActionBits: public BitField<RememberedSetAction, 12, 1> {};
276 class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 13, 1> {};
277
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100278 Label slow_;
279 RegisterAllocation regs_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100280
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000281 DISALLOW_COPY_AND_ASSIGN(RecordWriteStub);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100282};
283
284
Steve Block1e0659c2011-05-24 12:43:12 +0100285// Trampoline stub to call into native code. To call safely into native code
286// in the presence of compacting GC (which can move code objects) we need to
287// keep the code which called into native pinned in the memory. Currently the
288// simplest approach is to generate such stub early enough so it can never be
289// moved by GC
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000290class DirectCEntryStub: public PlatformCodeStub {
Steve Block1e0659c2011-05-24 12:43:12 +0100291 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000292 explicit DirectCEntryStub(Isolate* isolate) : PlatformCodeStub(isolate) {}
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100293 void GenerateCall(MacroAssembler* masm, Register target);
Steve Block1e0659c2011-05-24 12:43:12 +0100294
295 private:
Steve Block44f0eee2011-05-26 01:26:41 +0100296 bool NeedsImmovableCode() { return true; }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000297
298 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
299 DEFINE_PLATFORM_CODE_STUB(DirectCEntry, PlatformCodeStub);
Steve Block1e0659c2011-05-24 12:43:12 +0100300};
301
302
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000303class NameDictionaryLookupStub: public PlatformCodeStub {
Ben Murdoch257744e2011-11-30 15:57:28 +0000304 public:
305 enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
306
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000307 NameDictionaryLookupStub(Isolate* isolate, LookupMode mode)
308 : PlatformCodeStub(isolate) {
309 minor_key_ = LookupModeBits::encode(mode);
310 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000311
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100312 static void GenerateNegativeLookup(MacroAssembler* masm,
313 Label* miss,
314 Label* done,
315 Register receiver,
316 Register properties,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000317 Handle<Name> name,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100318 Register scratch0);
Ben Murdoch257744e2011-11-30 15:57:28 +0000319
320 static void GeneratePositiveLookup(MacroAssembler* masm,
321 Label* miss,
322 Label* done,
323 Register elements,
324 Register name,
325 Register r0,
326 Register r1);
327
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100328 virtual bool SometimesSetsUpAFrame() { return false; }
329
Ben Murdoch257744e2011-11-30 15:57:28 +0000330 private:
331 static const int kInlinedProbes = 4;
332 static const int kTotalProbes = 20;
333
334 static const int kCapacityOffset =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000335 NameDictionary::kHeaderSize +
336 NameDictionary::kCapacityIndex * kPointerSize;
Ben Murdoch257744e2011-11-30 15:57:28 +0000337
338 static const int kElementsStartOffset =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000339 NameDictionary::kHeaderSize +
340 NameDictionary::kElementsStartIndex * kPointerSize;
Ben Murdoch257744e2011-11-30 15:57:28 +0000341
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000342 LookupMode mode() const { return LookupModeBits::decode(minor_key_); }
Ben Murdoch257744e2011-11-30 15:57:28 +0000343
344 class LookupModeBits: public BitField<LookupMode, 0, 1> {};
345
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000346 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
347 DEFINE_PLATFORM_CODE_STUB(NameDictionaryLookup, PlatformCodeStub);
Ben Murdoch257744e2011-11-30 15:57:28 +0000348};
349
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100350} } // namespace v8::internal
351
352#endif // V8_ARM_CODE_STUBS_ARM_H_