blob: e1fab290301c921b4727ab81ac1c6dc7dcfe5d67 [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
Ben Murdochb8a8cc12014-11-26 15:28:44 +000049class RecordWriteStub: public PlatformCodeStub {
Kristian Monsen80d68ea2010-09-08 11:05:35 +010050 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000051 RecordWriteStub(Isolate* isolate,
52 Register object,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010053 Register value,
54 Register address,
55 RememberedSetAction remembered_set_action,
56 SaveFPRegsMode fp_mode)
Ben Murdochb8a8cc12014-11-26 15:28:44 +000057 : PlatformCodeStub(isolate),
Ben Murdoch3ef787d2012-04-12 10:51:47 +010058 regs_(object, // An input reg.
59 address, // An input reg.
60 value) { // One scratch reg.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000061 minor_key_ = ObjectBits::encode(object.code()) |
62 ValueBits::encode(value.code()) |
63 AddressBits::encode(address.code()) |
64 RememberedSetActionBits::encode(remembered_set_action) |
65 SaveFPRegsModeBits::encode(fp_mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010066 }
67
Ben Murdochb8a8cc12014-11-26 15:28:44 +000068 RecordWriteStub(uint32_t key, Isolate* isolate)
69 : PlatformCodeStub(key, isolate), regs_(object(), address(), value()) {}
70
Ben Murdoch3ef787d2012-04-12 10:51:47 +010071 enum Mode {
72 STORE_BUFFER_ONLY,
73 INCREMENTAL,
74 INCREMENTAL_COMPACTION
75 };
76
Emily Bernierd0a1eb72015-03-24 16:35:39 -040077 bool SometimesSetsUpAFrame() OVERRIDE { return false; }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010078
79 static void PatchBranchIntoNop(MacroAssembler* masm, int pos) {
80 masm->instr_at_put(pos, (masm->instr_at(pos) & ~B27) | (B24 | B20));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000081 DCHECK(Assembler::IsTstImmediate(masm->instr_at(pos)));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010082 }
83
84 static void PatchNopIntoBranch(MacroAssembler* masm, int pos) {
85 masm->instr_at_put(pos, (masm->instr_at(pos) & ~(B24 | B20)) | B27);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000086 DCHECK(Assembler::IsBranch(masm->instr_at(pos)));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010087 }
88
89 static Mode GetMode(Code* stub) {
90 Instr first_instruction = Assembler::instr_at(stub->instruction_start());
91 Instr second_instruction = Assembler::instr_at(stub->instruction_start() +
92 Assembler::kInstrSize);
93
94 if (Assembler::IsBranch(first_instruction)) {
95 return INCREMENTAL;
96 }
97
Ben Murdochb8a8cc12014-11-26 15:28:44 +000098 DCHECK(Assembler::IsTstImmediate(first_instruction));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010099
100 if (Assembler::IsBranch(second_instruction)) {
101 return INCREMENTAL_COMPACTION;
102 }
103
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000104 DCHECK(Assembler::IsTstImmediate(second_instruction));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100105
106 return STORE_BUFFER_ONLY;
107 }
108
109 static void Patch(Code* stub, Mode mode) {
110 MacroAssembler masm(NULL,
111 stub->instruction_start(),
112 stub->instruction_size());
113 switch (mode) {
114 case STORE_BUFFER_ONLY:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000115 DCHECK(GetMode(stub) == INCREMENTAL ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100116 GetMode(stub) == INCREMENTAL_COMPACTION);
117 PatchBranchIntoNop(&masm, 0);
118 PatchBranchIntoNop(&masm, Assembler::kInstrSize);
119 break;
120 case INCREMENTAL:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000121 DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100122 PatchNopIntoBranch(&masm, 0);
123 break;
124 case INCREMENTAL_COMPACTION:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000125 DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100126 PatchNopIntoBranch(&masm, Assembler::kInstrSize);
127 break;
128 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000129 DCHECK(GetMode(stub) == mode);
130 CpuFeatures::FlushICache(stub->instruction_start(),
131 2 * Assembler::kInstrSize);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100132 }
133
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000134 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
135
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100136 private:
137 // This is a helper class for freeing up 3 scratch registers. The input is
138 // two registers that must be preserved and one scratch register provided by
139 // the caller.
140 class RegisterAllocation {
141 public:
142 RegisterAllocation(Register object,
143 Register address,
144 Register scratch0)
145 : object_(object),
146 address_(address),
147 scratch0_(scratch0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000148 DCHECK(!AreAliased(scratch0, object, address, no_reg));
149 scratch1_ = GetRegisterThatIsNotOneOf(object_, address_, scratch0_);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100150 }
151
152 void Save(MacroAssembler* masm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000153 DCHECK(!AreAliased(object_, address_, scratch1_, scratch0_));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100154 // We don't have to save scratch0_ because it was given to us as
155 // a scratch register.
156 masm->push(scratch1_);
157 }
158
159 void Restore(MacroAssembler* masm) {
160 masm->pop(scratch1_);
161 }
162
163 // If we have to call into C then we need to save and restore all caller-
164 // saved registers that were not already preserved. The scratch registers
165 // will be restored by other means so we don't bother pushing them here.
166 void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
167 masm->stm(db_w, sp, (kCallerSaved | lr.bit()) & ~scratch1_.bit());
168 if (mode == kSaveFPRegs) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000169 masm->SaveFPRegs(sp, scratch0_);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100170 }
171 }
172
173 inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
174 SaveFPRegsMode mode) {
175 if (mode == kSaveFPRegs) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000176 masm->RestoreFPRegs(sp, scratch0_);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100177 }
178 masm->ldm(ia_w, sp, (kCallerSaved | lr.bit()) & ~scratch1_.bit());
179 }
180
181 inline Register object() { return object_; }
182 inline Register address() { return address_; }
183 inline Register scratch0() { return scratch0_; }
184 inline Register scratch1() { return scratch1_; }
185
186 private:
187 Register object_;
188 Register address_;
189 Register scratch0_;
190 Register scratch1_;
191
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100192 friend class RecordWriteStub;
193 };
194
195 enum OnNoNeedToInformIncrementalMarker {
196 kReturnOnNoNeedToInformIncrementalMarker,
197 kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
198 };
199
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400200 inline Major MajorKey() const FINAL { return RecordWrite; }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000201
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400202 void Generate(MacroAssembler* masm) OVERRIDE;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100203 void GenerateIncremental(MacroAssembler* masm, Mode mode);
204 void CheckNeedsToInformIncrementalMarker(
205 MacroAssembler* masm,
206 OnNoNeedToInformIncrementalMarker on_no_need,
207 Mode mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000208 void InformIncrementalMarker(MacroAssembler* masm);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100209
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400210 void Activate(Code* code) OVERRIDE {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100211 code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
212 }
213
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000214 Register object() const {
215 return Register::from_code(ObjectBits::decode(minor_key_));
216 }
217
218 Register value() const {
219 return Register::from_code(ValueBits::decode(minor_key_));
220 }
221
222 Register address() const {
223 return Register::from_code(AddressBits::decode(minor_key_));
224 }
225
226 RememberedSetAction remembered_set_action() const {
227 return RememberedSetActionBits::decode(minor_key_);
228 }
229
230 SaveFPRegsMode save_fp_regs_mode() const {
231 return SaveFPRegsModeBits::decode(minor_key_);
232 }
233
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100234 class ObjectBits: public BitField<int, 0, 4> {};
235 class ValueBits: public BitField<int, 4, 4> {};
236 class AddressBits: public BitField<int, 8, 4> {};
237 class RememberedSetActionBits: public BitField<RememberedSetAction, 12, 1> {};
238 class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 13, 1> {};
239
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100240 Label slow_;
241 RegisterAllocation regs_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100242
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000243 DISALLOW_COPY_AND_ASSIGN(RecordWriteStub);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100244};
245
246
Steve Block1e0659c2011-05-24 12:43:12 +0100247// Trampoline stub to call into native code. To call safely into native code
248// in the presence of compacting GC (which can move code objects) we need to
249// keep the code which called into native pinned in the memory. Currently the
250// simplest approach is to generate such stub early enough so it can never be
251// moved by GC
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000252class DirectCEntryStub: public PlatformCodeStub {
Steve Block1e0659c2011-05-24 12:43:12 +0100253 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000254 explicit DirectCEntryStub(Isolate* isolate) : PlatformCodeStub(isolate) {}
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100255 void GenerateCall(MacroAssembler* masm, Register target);
Steve Block1e0659c2011-05-24 12:43:12 +0100256
257 private:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400258 bool NeedsImmovableCode() OVERRIDE { return true; }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000259
260 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
261 DEFINE_PLATFORM_CODE_STUB(DirectCEntry, PlatformCodeStub);
Steve Block1e0659c2011-05-24 12:43:12 +0100262};
263
264
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000265class NameDictionaryLookupStub: public PlatformCodeStub {
Ben Murdoch257744e2011-11-30 15:57:28 +0000266 public:
267 enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
268
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000269 NameDictionaryLookupStub(Isolate* isolate, LookupMode mode)
270 : PlatformCodeStub(isolate) {
271 minor_key_ = LookupModeBits::encode(mode);
272 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000273
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100274 static void GenerateNegativeLookup(MacroAssembler* masm,
275 Label* miss,
276 Label* done,
277 Register receiver,
278 Register properties,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000279 Handle<Name> name,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100280 Register scratch0);
Ben Murdoch257744e2011-11-30 15:57:28 +0000281
282 static void GeneratePositiveLookup(MacroAssembler* masm,
283 Label* miss,
284 Label* done,
285 Register elements,
286 Register name,
287 Register r0,
288 Register r1);
289
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400290 bool SometimesSetsUpAFrame() OVERRIDE { return false; }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100291
Ben Murdoch257744e2011-11-30 15:57:28 +0000292 private:
293 static const int kInlinedProbes = 4;
294 static const int kTotalProbes = 20;
295
296 static const int kCapacityOffset =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000297 NameDictionary::kHeaderSize +
298 NameDictionary::kCapacityIndex * kPointerSize;
Ben Murdoch257744e2011-11-30 15:57:28 +0000299
300 static const int kElementsStartOffset =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000301 NameDictionary::kHeaderSize +
302 NameDictionary::kElementsStartIndex * kPointerSize;
Ben Murdoch257744e2011-11-30 15:57:28 +0000303
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000304 LookupMode mode() const { return LookupModeBits::decode(minor_key_); }
Ben Murdoch257744e2011-11-30 15:57:28 +0000305
306 class LookupModeBits: public BitField<LookupMode, 0, 1> {};
307
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000308 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
309 DEFINE_PLATFORM_CODE_STUB(NameDictionaryLookup, PlatformCodeStub);
Ben Murdoch257744e2011-11-30 15:57:28 +0000310};
311
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100312} } // namespace v8::internal
313
314#endif // V8_ARM_CODE_STUBS_ARM_H_