blob: e71c30583e58952315ef812807b7dd13daf5d92e [file] [log] [blame]
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001// Copyright 2011 the V8 project authors. All rights reserved.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#ifndef V8_MIPS_CODE_STUBS_ARM_H_
29#define V8_MIPS_CODE_STUBS_ARM_H_
30
31#include "ic-inl.h"
32
33
34namespace v8 {
35namespace internal {
36
37
danno@chromium.orgca29dd82013-04-26 11:59:48 +000038void ArrayNativeCode(MacroAssembler* masm, Label* call_generic_code);
39
40
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000041class StoreBufferOverflowStub: public PlatformCodeStub {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000042 public:
43 explicit StoreBufferOverflowStub(SaveFPRegsMode save_fp)
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000044 : save_doubles_(save_fp) {}
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000045
46 void Generate(MacroAssembler* masm);
47
hpayer@chromium.org8432c912013-02-28 15:55:26 +000048 static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000049 virtual bool SometimesSetsUpAFrame() { return false; }
50
51 private:
52 SaveFPRegsMode save_doubles_;
53
54 Major MajorKey() { return StoreBufferOverflow; }
55 int MinorKey() { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; }
56};
57
58
danno@chromium.org2c456792011-11-11 12:00:53 +000059class StringHelper : public AllStatic {
60 public:
danno@chromium.org2c456792011-11-11 12:00:53 +000061 // Generate code for copying a large number of characters. This function
62 // is allowed to spend extra time setting up conditions to make copying
63 // faster. Copying of overlapping regions is not supported.
64 // Dest register ends at the position after the last character written.
65 static void GenerateCopyCharactersLong(MacroAssembler* masm,
66 Register dest,
67 Register src,
68 Register count,
69 Register scratch1,
70 Register scratch2,
71 Register scratch3,
72 Register scratch4,
73 Register scratch5,
74 int flags);
75
76
danno@chromium.org2c456792011-11-11 12:00:53 +000077 // Generate string hash.
78 static void GenerateHashInit(MacroAssembler* masm,
79 Register hash,
80 Register character);
81
82 static void GenerateHashAddCharacter(MacroAssembler* masm,
83 Register hash,
84 Register character);
85
86 static void GenerateHashGetHash(MacroAssembler* masm,
87 Register hash);
88
89 private:
90 DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
91};
92
93
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000094class SubStringStub: public PlatformCodeStub {
lrn@chromium.org7516f052011-03-30 08:52:27 +000095 public:
96 SubStringStub() {}
97
98 private:
99 Major MajorKey() { return SubString; }
100 int MinorKey() { return 0; }
101
102 void Generate(MacroAssembler* masm);
103};
104
yangguo@chromium.org49546742013-12-23 16:17:49 +0000105class StoreRegistersStateStub: public PlatformCodeStub {
106 public:
107 explicit StoreRegistersStateStub(SaveFPRegsMode with_fp)
108 : save_doubles_(with_fp) {}
109
110 static void GenerateAheadOfTime(Isolate* isolate);
111 private:
112 Major MajorKey() { return StoreRegistersState; }
113 int MinorKey() { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; }
114 SaveFPRegsMode save_doubles_;
115
116 void Generate(MacroAssembler* masm);
117};
118
119class RestoreRegistersStateStub: public PlatformCodeStub {
120 public:
121 explicit RestoreRegistersStateStub(SaveFPRegsMode with_fp)
122 : save_doubles_(with_fp) {}
123
124 static void GenerateAheadOfTime(Isolate* isolate);
125 private:
126 Major MajorKey() { return RestoreRegistersState; }
127 int MinorKey() { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; }
128 SaveFPRegsMode save_doubles_;
129
130 void Generate(MacroAssembler* masm);
131};
lrn@chromium.org7516f052011-03-30 08:52:27 +0000132
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000133class StringCompareStub: public PlatformCodeStub {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000134 public:
135 StringCompareStub() { }
136
137 // Compare two flat ASCII strings and returns result in v0.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000138 static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
139 Register left,
140 Register right,
141 Register scratch1,
142 Register scratch2,
143 Register scratch3,
144 Register scratch4);
145
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000146 // Compares two flat ASCII strings for equality and returns result
147 // in v0.
148 static void GenerateFlatAsciiStringEquals(MacroAssembler* masm,
149 Register left,
150 Register right,
151 Register scratch1,
152 Register scratch2,
153 Register scratch3);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000154
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000155 private:
156 virtual Major MajorKey() { return StringCompare; }
157 virtual int MinorKey() { return 0; }
158 virtual void Generate(MacroAssembler* masm);
159
160 static void GenerateAsciiCharsCompareLoop(MacroAssembler* masm,
161 Register left,
162 Register right,
163 Register length,
164 Register scratch1,
165 Register scratch2,
166 Register scratch3,
167 Label* chars_not_equal);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000168};
169
170
171// This stub can convert a signed int32 to a heap number (double). It does
172// not work for int32s that are in Smi range! No GC occurs during this stub
173// so you don't have to set up the frame.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000174class WriteInt32ToHeapNumberStub : public PlatformCodeStub {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000175 public:
176 WriteInt32ToHeapNumberStub(Register the_int,
177 Register the_heap_number,
178 Register scratch,
179 Register scratch2)
180 : the_int_(the_int),
181 the_heap_number_(the_heap_number),
182 scratch_(scratch),
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000183 sign_(scratch2) {
184 ASSERT(IntRegisterBits::is_valid(the_int_.code()));
185 ASSERT(HeapNumberRegisterBits::is_valid(the_heap_number_.code()));
186 ASSERT(ScratchRegisterBits::is_valid(scratch_.code()));
187 ASSERT(SignRegisterBits::is_valid(sign_.code()));
188 }
189
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000190 static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000191
192 private:
193 Register the_int_;
194 Register the_heap_number_;
195 Register scratch_;
196 Register sign_;
197
198 // Minor key encoding in 16 bits.
199 class IntRegisterBits: public BitField<int, 0, 4> {};
200 class HeapNumberRegisterBits: public BitField<int, 4, 4> {};
201 class ScratchRegisterBits: public BitField<int, 8, 4> {};
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000202 class SignRegisterBits: public BitField<int, 12, 4> {};
lrn@chromium.org7516f052011-03-30 08:52:27 +0000203
204 Major MajorKey() { return WriteInt32ToHeapNumber; }
205 int MinorKey() {
206 // Encode the parameters in a unique 16 bit value.
207 return IntRegisterBits::encode(the_int_.code())
208 | HeapNumberRegisterBits::encode(the_heap_number_.code())
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000209 | ScratchRegisterBits::encode(scratch_.code())
210 | SignRegisterBits::encode(sign_.code());
lrn@chromium.org7516f052011-03-30 08:52:27 +0000211 }
212
213 void Generate(MacroAssembler* masm);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000214};
215
216
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000217class RecordWriteStub: public PlatformCodeStub {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000218 public:
219 RecordWriteStub(Register object,
220 Register value,
221 Register address,
222 RememberedSetAction remembered_set_action,
223 SaveFPRegsMode fp_mode)
224 : object_(object),
225 value_(value),
226 address_(address),
227 remembered_set_action_(remembered_set_action),
228 save_fp_regs_mode_(fp_mode),
229 regs_(object, // An input reg.
230 address, // An input reg.
231 value) { // One scratch reg.
232 }
233
234 enum Mode {
235 STORE_BUFFER_ONLY,
236 INCREMENTAL,
237 INCREMENTAL_COMPACTION
238 };
239
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000240 virtual bool SometimesSetsUpAFrame() { return false; }
241
242 static void PatchBranchIntoNop(MacroAssembler* masm, int pos) {
243 const unsigned offset = masm->instr_at(pos) & kImm16Mask;
244 masm->instr_at_put(pos, BNE | (zero_reg.code() << kRsShift) |
245 (zero_reg.code() << kRtShift) | (offset & kImm16Mask));
246 ASSERT(Assembler::IsBne(masm->instr_at(pos)));
247 }
248
249 static void PatchNopIntoBranch(MacroAssembler* masm, int pos) {
250 const unsigned offset = masm->instr_at(pos) & kImm16Mask;
251 masm->instr_at_put(pos, BEQ | (zero_reg.code() << kRsShift) |
252 (zero_reg.code() << kRtShift) | (offset & kImm16Mask));
253 ASSERT(Assembler::IsBeq(masm->instr_at(pos)));
254 }
255
256 static Mode GetMode(Code* stub) {
257 Instr first_instruction = Assembler::instr_at(stub->instruction_start());
258 Instr second_instruction = Assembler::instr_at(stub->instruction_start() +
259 2 * Assembler::kInstrSize);
260
261 if (Assembler::IsBeq(first_instruction)) {
262 return INCREMENTAL;
263 }
264
265 ASSERT(Assembler::IsBne(first_instruction));
266
267 if (Assembler::IsBeq(second_instruction)) {
268 return INCREMENTAL_COMPACTION;
269 }
270
271 ASSERT(Assembler::IsBne(second_instruction));
272
273 return STORE_BUFFER_ONLY;
274 }
275
276 static void Patch(Code* stub, Mode mode) {
277 MacroAssembler masm(NULL,
278 stub->instruction_start(),
279 stub->instruction_size());
280 switch (mode) {
281 case STORE_BUFFER_ONLY:
282 ASSERT(GetMode(stub) == INCREMENTAL ||
283 GetMode(stub) == INCREMENTAL_COMPACTION);
284 PatchBranchIntoNop(&masm, 0);
285 PatchBranchIntoNop(&masm, 2 * Assembler::kInstrSize);
286 break;
287 case INCREMENTAL:
288 ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
289 PatchNopIntoBranch(&masm, 0);
290 break;
291 case INCREMENTAL_COMPACTION:
292 ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
293 PatchNopIntoBranch(&masm, 2 * Assembler::kInstrSize);
294 break;
295 }
296 ASSERT(GetMode(stub) == mode);
297 CPU::FlushICache(stub->instruction_start(), 4 * Assembler::kInstrSize);
298 }
299
300 private:
301 // This is a helper class for freeing up 3 scratch registers. The input is
302 // two registers that must be preserved and one scratch register provided by
303 // the caller.
304 class RegisterAllocation {
305 public:
306 RegisterAllocation(Register object,
307 Register address,
308 Register scratch0)
309 : object_(object),
310 address_(address),
311 scratch0_(scratch0) {
312 ASSERT(!AreAliased(scratch0, object, address, no_reg));
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000313 scratch1_ = GetRegisterThatIsNotOneOf(object_, address_, scratch0_);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000314 }
315
316 void Save(MacroAssembler* masm) {
317 ASSERT(!AreAliased(object_, address_, scratch1_, scratch0_));
318 // We don't have to save scratch0_ because it was given to us as
319 // a scratch register.
320 masm->push(scratch1_);
321 }
322
323 void Restore(MacroAssembler* masm) {
324 masm->pop(scratch1_);
325 }
326
327 // If we have to call into C then we need to save and restore all caller-
328 // saved registers that were not already preserved. The scratch registers
329 // will be restored by other means so we don't bother pushing them here.
330 void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
331 masm->MultiPush((kJSCallerSaved | ra.bit()) & ~scratch1_.bit());
332 if (mode == kSaveFPRegs) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000333 masm->MultiPushFPU(kCallerSavedFPU);
334 }
335 }
336
337 inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
338 SaveFPRegsMode mode) {
339 if (mode == kSaveFPRegs) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000340 masm->MultiPopFPU(kCallerSavedFPU);
341 }
342 masm->MultiPop((kJSCallerSaved | ra.bit()) & ~scratch1_.bit());
343 }
344
345 inline Register object() { return object_; }
346 inline Register address() { return address_; }
347 inline Register scratch0() { return scratch0_; }
348 inline Register scratch1() { return scratch1_; }
349
350 private:
351 Register object_;
352 Register address_;
353 Register scratch0_;
354 Register scratch1_;
355
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000356 friend class RecordWriteStub;
357 };
358
359 enum OnNoNeedToInformIncrementalMarker {
360 kReturnOnNoNeedToInformIncrementalMarker,
361 kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
362 };
363
364 void Generate(MacroAssembler* masm);
365 void GenerateIncremental(MacroAssembler* masm, Mode mode);
366 void CheckNeedsToInformIncrementalMarker(
367 MacroAssembler* masm,
368 OnNoNeedToInformIncrementalMarker on_no_need,
369 Mode mode);
titzer@chromium.orgf5a24542014-03-04 09:06:17 +0000370 void InformIncrementalMarker(MacroAssembler* masm);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000371
372 Major MajorKey() { return RecordWrite; }
373
374 int MinorKey() {
375 return ObjectBits::encode(object_.code()) |
376 ValueBits::encode(value_.code()) |
377 AddressBits::encode(address_.code()) |
378 RememberedSetActionBits::encode(remembered_set_action_) |
379 SaveFPRegsModeBits::encode(save_fp_regs_mode_);
380 }
381
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000382 void Activate(Code* code) {
383 code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
384 }
385
386 class ObjectBits: public BitField<int, 0, 5> {};
387 class ValueBits: public BitField<int, 5, 5> {};
388 class AddressBits: public BitField<int, 10, 5> {};
389 class RememberedSetActionBits: public BitField<RememberedSetAction, 15, 1> {};
390 class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 16, 1> {};
391
392 Register object_;
393 Register value_;
394 Register address_;
395 RememberedSetAction remembered_set_action_;
396 SaveFPRegsMode save_fp_regs_mode_;
397 Label slow_;
398 RegisterAllocation regs_;
399};
400
401
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000402// Trampoline stub to call into native code. To call safely into native code
403// in the presence of compacting GC (which can move code objects) we need to
404// keep the code which called into native pinned in the memory. Currently the
405// simplest approach is to generate such stub early enough so it can never be
406// moved by GC
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000407class DirectCEntryStub: public PlatformCodeStub {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000408 public:
409 DirectCEntryStub() {}
410 void Generate(MacroAssembler* masm);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000411 void GenerateCall(MacroAssembler* masm, Register target);
412
413 private:
414 Major MajorKey() { return DirectCEntry; }
415 int MinorKey() { return 0; }
416
417 bool NeedsImmovableCode() { return true; }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000418};
lrn@chromium.org7516f052011-03-30 08:52:27 +0000419
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000420
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000421class NameDictionaryLookupStub: public PlatformCodeStub {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000422 public:
423 enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
424
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000425 explicit NameDictionaryLookupStub(LookupMode mode) : mode_(mode) { }
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000426
427 void Generate(MacroAssembler* masm);
428
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000429 static void GenerateNegativeLookup(MacroAssembler* masm,
430 Label* miss,
431 Label* done,
432 Register receiver,
433 Register properties,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000434 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000435 Register scratch0);
436
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000437 static void GeneratePositiveLookup(MacroAssembler* masm,
438 Label* miss,
439 Label* done,
440 Register elements,
441 Register name,
442 Register r0,
443 Register r1);
444
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000445 virtual bool SometimesSetsUpAFrame() { return false; }
446
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000447 private:
448 static const int kInlinedProbes = 4;
449 static const int kTotalProbes = 20;
450
451 static const int kCapacityOffset =
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000452 NameDictionary::kHeaderSize +
453 NameDictionary::kCapacityIndex * kPointerSize;
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000454
455 static const int kElementsStartOffset =
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000456 NameDictionary::kHeaderSize +
457 NameDictionary::kElementsStartIndex * kPointerSize;
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000458
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000459 Major MajorKey() { return NameDictionaryLookup; }
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000460
461 int MinorKey() {
462 return LookupModeBits::encode(mode_);
463 }
464
465 class LookupModeBits: public BitField<LookupMode, 0, 1> {};
466
467 LookupMode mode_;
468};
lrn@chromium.org7516f052011-03-30 08:52:27 +0000469
470
471} } // namespace v8::internal
472
473#endif // V8_MIPS_CODE_STUBS_ARM_H_