blob: 30ae358eb05eae446c55040faf241e13b85d5346 [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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008#include "src/arm/frames-arm.h"
9
Kristian Monsen80d68ea2010-09-08 11:05:35 +010010namespace v8 {
11namespace internal {
12
13
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014void ArrayNativeCode(MacroAssembler* masm, Label* call_generic_code);
Steve Block1e0659c2011-05-24 12:43:12 +010015
16
Ben Murdoch692be652012-01-10 18:47:50 +000017class StringHelper : public AllStatic {
18 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019 // Generate code for copying a large number of characters. This function
20 // is allowed to spend extra time setting up conditions to make copying
21 // faster. Copying of overlapping regions is not supported.
Ben Murdoch692be652012-01-10 18:47:50 +000022 // Dest register ends at the position after the last character written.
23 static void GenerateCopyCharacters(MacroAssembler* masm,
24 Register dest,
25 Register src,
26 Register count,
27 Register scratch,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000028 String::Encoding encoding);
Ben Murdoch692be652012-01-10 18:47:50 +000029
Ben Murdochb8a8cc12014-11-26 15:28:44 +000030 // Compares two flat one-byte strings and returns result in r0.
31 static void GenerateCompareFlatOneByteStrings(
32 MacroAssembler* masm, Register left, Register right, Register scratch1,
33 Register scratch2, Register scratch3, Register scratch4);
Ben Murdoch692be652012-01-10 18:47:50 +000034
Ben Murdochb8a8cc12014-11-26 15:28:44 +000035 // Compares two flat one-byte strings for equality and returns result in r0.
36 static void GenerateFlatOneByteStringEquals(MacroAssembler* masm,
37 Register left, Register right,
Kristian Monsen80d68ea2010-09-08 11:05:35 +010038 Register scratch1,
39 Register scratch2,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000040 Register scratch3);
Kristian Monsen80d68ea2010-09-08 11:05:35 +010041
Ben Murdoch257744e2011-11-30 15:57:28 +000042 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000043 static void GenerateOneByteCharsCompareLoop(
44 MacroAssembler* masm, Register left, Register right, Register length,
45 Register scratch1, Register scratch2, Label* chars_not_equal);
Ben Murdoch257744e2011-11-30 15:57:28 +000046
Ben Murdochb8a8cc12014-11-26 15:28:44 +000047 DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
Kristian Monsen80d68ea2010-09-08 11:05:35 +010048};
49
50
Ben Murdochb8a8cc12014-11-26 15:28:44 +000051class RecordWriteStub: public PlatformCodeStub {
Kristian Monsen80d68ea2010-09-08 11:05:35 +010052 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000053 RecordWriteStub(Isolate* isolate,
54 Register object,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010055 Register value,
56 Register address,
57 RememberedSetAction remembered_set_action,
58 SaveFPRegsMode fp_mode)
Ben Murdochb8a8cc12014-11-26 15:28:44 +000059 : PlatformCodeStub(isolate),
Ben Murdoch3ef787d2012-04-12 10:51:47 +010060 regs_(object, // An input reg.
61 address, // An input reg.
62 value) { // One scratch reg.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000063 minor_key_ = ObjectBits::encode(object.code()) |
64 ValueBits::encode(value.code()) |
65 AddressBits::encode(address.code()) |
66 RememberedSetActionBits::encode(remembered_set_action) |
67 SaveFPRegsModeBits::encode(fp_mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010068 }
69
Ben Murdochb8a8cc12014-11-26 15:28:44 +000070 RecordWriteStub(uint32_t key, Isolate* isolate)
71 : PlatformCodeStub(key, isolate), regs_(object(), address(), value()) {}
72
Ben Murdoch3ef787d2012-04-12 10:51:47 +010073 enum Mode {
74 STORE_BUFFER_ONLY,
75 INCREMENTAL,
76 INCREMENTAL_COMPACTION
77 };
78
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000079 bool SometimesSetsUpAFrame() override { return false; }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010080
81 static void PatchBranchIntoNop(MacroAssembler* masm, int pos) {
82 masm->instr_at_put(pos, (masm->instr_at(pos) & ~B27) | (B24 | B20));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000083 DCHECK(Assembler::IsTstImmediate(masm->instr_at(pos)));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010084 }
85
86 static void PatchNopIntoBranch(MacroAssembler* masm, int pos) {
87 masm->instr_at_put(pos, (masm->instr_at(pos) & ~(B24 | B20)) | B27);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000088 DCHECK(Assembler::IsBranch(masm->instr_at(pos)));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010089 }
90
91 static Mode GetMode(Code* stub) {
92 Instr first_instruction = Assembler::instr_at(stub->instruction_start());
93 Instr second_instruction = Assembler::instr_at(stub->instruction_start() +
94 Assembler::kInstrSize);
95
96 if (Assembler::IsBranch(first_instruction)) {
97 return INCREMENTAL;
98 }
99
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000100 DCHECK(Assembler::IsTstImmediate(first_instruction));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100101
102 if (Assembler::IsBranch(second_instruction)) {
103 return INCREMENTAL_COMPACTION;
104 }
105
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000106 DCHECK(Assembler::IsTstImmediate(second_instruction));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100107
108 return STORE_BUFFER_ONLY;
109 }
110
111 static void Patch(Code* stub, Mode mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000112 MacroAssembler masm(stub->GetIsolate(), stub->instruction_start(),
113 stub->instruction_size(), CodeObjectRequired::kNo);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100114 switch (mode) {
115 case STORE_BUFFER_ONLY:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000116 DCHECK(GetMode(stub) == INCREMENTAL ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100117 GetMode(stub) == INCREMENTAL_COMPACTION);
118 PatchBranchIntoNop(&masm, 0);
119 PatchBranchIntoNop(&masm, Assembler::kInstrSize);
120 break;
121 case INCREMENTAL:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000122 DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100123 PatchNopIntoBranch(&masm, 0);
124 break;
125 case INCREMENTAL_COMPACTION:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000126 DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100127 PatchNopIntoBranch(&masm, Assembler::kInstrSize);
128 break;
129 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000130 DCHECK(GetMode(stub) == mode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000131 Assembler::FlushICache(stub->GetIsolate(), stub->instruction_start(),
132 2 * Assembler::kInstrSize);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100133 }
134
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000135 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
136
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100137 private:
138 // This is a helper class for freeing up 3 scratch registers. The input is
139 // two registers that must be preserved and one scratch register provided by
140 // the caller.
141 class RegisterAllocation {
142 public:
143 RegisterAllocation(Register object,
144 Register address,
145 Register scratch0)
146 : object_(object),
147 address_(address),
148 scratch0_(scratch0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000149 DCHECK(!AreAliased(scratch0, object, address, no_reg));
150 scratch1_ = GetRegisterThatIsNotOneOf(object_, address_, scratch0_);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100151 }
152
153 void Save(MacroAssembler* masm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000154 DCHECK(!AreAliased(object_, address_, scratch1_, scratch0_));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100155 // We don't have to save scratch0_ because it was given to us as
156 // a scratch register.
157 masm->push(scratch1_);
158 }
159
160 void Restore(MacroAssembler* masm) {
161 masm->pop(scratch1_);
162 }
163
164 // If we have to call into C then we need to save and restore all caller-
165 // saved registers that were not already preserved. The scratch registers
166 // will be restored by other means so we don't bother pushing them here.
167 void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
168 masm->stm(db_w, sp, (kCallerSaved | lr.bit()) & ~scratch1_.bit());
169 if (mode == kSaveFPRegs) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000170 masm->SaveFPRegs(sp, scratch0_);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100171 }
172 }
173
174 inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
175 SaveFPRegsMode mode) {
176 if (mode == kSaveFPRegs) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000177 masm->RestoreFPRegs(sp, scratch0_);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100178 }
179 masm->ldm(ia_w, sp, (kCallerSaved | lr.bit()) & ~scratch1_.bit());
180 }
181
182 inline Register object() { return object_; }
183 inline Register address() { return address_; }
184 inline Register scratch0() { return scratch0_; }
185 inline Register scratch1() { return scratch1_; }
186
187 private:
188 Register object_;
189 Register address_;
190 Register scratch0_;
191 Register scratch1_;
192
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100193 friend class RecordWriteStub;
194 };
195
196 enum OnNoNeedToInformIncrementalMarker {
197 kReturnOnNoNeedToInformIncrementalMarker,
198 kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
199 };
200
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000201 inline Major MajorKey() const final { return RecordWrite; }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000202
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000203 void Generate(MacroAssembler* masm) override;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100204 void GenerateIncremental(MacroAssembler* masm, Mode mode);
205 void CheckNeedsToInformIncrementalMarker(
206 MacroAssembler* masm,
207 OnNoNeedToInformIncrementalMarker on_no_need,
208 Mode mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000209 void InformIncrementalMarker(MacroAssembler* masm);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100210
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000211 void Activate(Code* code) override {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100212 code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
213 }
214
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000215 Register object() const {
216 return Register::from_code(ObjectBits::decode(minor_key_));
217 }
218
219 Register value() const {
220 return Register::from_code(ValueBits::decode(minor_key_));
221 }
222
223 Register address() const {
224 return Register::from_code(AddressBits::decode(minor_key_));
225 }
226
227 RememberedSetAction remembered_set_action() const {
228 return RememberedSetActionBits::decode(minor_key_);
229 }
230
231 SaveFPRegsMode save_fp_regs_mode() const {
232 return SaveFPRegsModeBits::decode(minor_key_);
233 }
234
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100235 class ObjectBits: public BitField<int, 0, 4> {};
236 class ValueBits: public BitField<int, 4, 4> {};
237 class AddressBits: public BitField<int, 8, 4> {};
238 class RememberedSetActionBits: public BitField<RememberedSetAction, 12, 1> {};
239 class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 13, 1> {};
240
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100241 Label slow_;
242 RegisterAllocation regs_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100243
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000244 DISALLOW_COPY_AND_ASSIGN(RecordWriteStub);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100245};
246
247
Steve Block1e0659c2011-05-24 12:43:12 +0100248// Trampoline stub to call into native code. To call safely into native code
249// in the presence of compacting GC (which can move code objects) we need to
250// keep the code which called into native pinned in the memory. Currently the
251// simplest approach is to generate such stub early enough so it can never be
252// moved by GC
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000253class DirectCEntryStub: public PlatformCodeStub {
Steve Block1e0659c2011-05-24 12:43:12 +0100254 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000255 explicit DirectCEntryStub(Isolate* isolate) : PlatformCodeStub(isolate) {}
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100256 void GenerateCall(MacroAssembler* masm, Register target);
Steve Block1e0659c2011-05-24 12:43:12 +0100257
258 private:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000259 bool NeedsImmovableCode() override { return true; }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000260
261 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
262 DEFINE_PLATFORM_CODE_STUB(DirectCEntry, PlatformCodeStub);
Steve Block1e0659c2011-05-24 12:43:12 +0100263};
264
265
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000266class NameDictionaryLookupStub: public PlatformCodeStub {
Ben Murdoch257744e2011-11-30 15:57:28 +0000267 public:
268 enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
269
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000270 NameDictionaryLookupStub(Isolate* isolate, LookupMode mode)
271 : PlatformCodeStub(isolate) {
272 minor_key_ = LookupModeBits::encode(mode);
273 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000274
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100275 static void GenerateNegativeLookup(MacroAssembler* masm,
276 Label* miss,
277 Label* done,
278 Register receiver,
279 Register properties,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000280 Handle<Name> name,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100281 Register scratch0);
Ben Murdoch257744e2011-11-30 15:57:28 +0000282
283 static void GeneratePositiveLookup(MacroAssembler* masm,
284 Label* miss,
285 Label* done,
286 Register elements,
287 Register name,
288 Register r0,
289 Register r1);
290
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000291 bool SometimesSetsUpAFrame() override { return false; }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100292
Ben Murdoch257744e2011-11-30 15:57:28 +0000293 private:
294 static const int kInlinedProbes = 4;
295 static const int kTotalProbes = 20;
296
297 static const int kCapacityOffset =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000298 NameDictionary::kHeaderSize +
299 NameDictionary::kCapacityIndex * kPointerSize;
Ben Murdoch257744e2011-11-30 15:57:28 +0000300
301 static const int kElementsStartOffset =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000302 NameDictionary::kHeaderSize +
303 NameDictionary::kElementsStartIndex * kPointerSize;
Ben Murdoch257744e2011-11-30 15:57:28 +0000304
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000305 LookupMode mode() const { return LookupModeBits::decode(minor_key_); }
Ben Murdoch257744e2011-11-30 15:57:28 +0000306
307 class LookupModeBits: public BitField<LookupMode, 0, 1> {};
308
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000309 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
310 DEFINE_PLATFORM_CODE_STUB(NameDictionaryLookup, PlatformCodeStub);
Ben Murdoch257744e2011-11-30 15:57:28 +0000311};
312
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000313} // namespace internal
314} // namespace v8
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100315
316#endif // V8_ARM_CODE_STUBS_ARM_H_