blob: 751095d8d82920d90ea1ac963bcd0a5245871513 [file] [log] [blame]
Ben Murdoch257744e2011-11-30 15:57:28 +00001// Copyright 2011 the V8 project authors. All rights reserved.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Steve Block44f0eee2011-05-26 01:26:41 +01004
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005#ifndef V8_MIPS_CODE_STUBS_MIPS_H_
6#define V8_MIPS_CODE_STUBS_MIPS_H_
7
8#include "src/mips/frames-mips.h"
Steve Block44f0eee2011-05-26 01:26:41 +01009
Steve Block44f0eee2011-05-26 01:26:41 +010010namespace v8 {
11namespace internal {
12
13
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014void ArrayNativeCode(MacroAssembler* masm, Label* call_generic_code);
Steve Block44f0eee2011-05-26 01:26:41 +010015
16
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017class 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 Murdoch3ef787d2012-04-12 10:51:47 +010022 // 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 Murdoch3ef787d2012-04-12 10:51:47 +010029
Ben Murdochb8a8cc12014-11-26 15:28:44 +000030 // Compares two flat one-byte strings and returns result in v0.
31 static void GenerateCompareFlatOneByteStrings(
32 MacroAssembler* masm, Register left, Register right, Register scratch1,
33 Register scratch2, Register scratch3, Register scratch4);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010034
Ben Murdochb8a8cc12014-11-26 15:28:44 +000035 // Compares two flat one-byte strings for equality and returns result in v0.
36 static void GenerateFlatOneByteStringEquals(MacroAssembler* masm,
37 Register left, Register right,
38 Register scratch1,
39 Register scratch2,
40 Register scratch3);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010041
42 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, Register scratch3,
46 Label* chars_not_equal);
47
Ben Murdoch3ef787d2012-04-12 10:51:47 +010048 DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
49};
50
51
Ben Murdochb8a8cc12014-11-26 15:28:44 +000052class StoreRegistersStateStub: public PlatformCodeStub {
53 public:
54 explicit StoreRegistersStateStub(Isolate* isolate)
55 : PlatformCodeStub(isolate) {}
56
57 static void GenerateAheadOfTime(Isolate* isolate);
58
59 private:
60 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
61 DEFINE_PLATFORM_CODE_STUB(StoreRegistersState, PlatformCodeStub);
Steve Block44f0eee2011-05-26 01:26:41 +010062};
63
64
Ben Murdochb8a8cc12014-11-26 15:28:44 +000065class RestoreRegistersStateStub: public PlatformCodeStub {
Steve Block44f0eee2011-05-26 01:26:41 +010066 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000067 explicit RestoreRegistersStateStub(Isolate* isolate)
68 : PlatformCodeStub(isolate) {}
69
70 static void GenerateAheadOfTime(Isolate* isolate);
Steve Block44f0eee2011-05-26 01:26:41 +010071
72 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000073 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
74 DEFINE_PLATFORM_CODE_STUB(RestoreRegistersState, PlatformCodeStub);
Steve Block44f0eee2011-05-26 01:26:41 +010075};
76
77
Ben Murdochb8a8cc12014-11-26 15:28:44 +000078class RecordWriteStub: public PlatformCodeStub {
Steve Block44f0eee2011-05-26 01:26:41 +010079 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000080 RecordWriteStub(Isolate* isolate,
81 Register object,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010082 Register value,
83 Register address,
84 RememberedSetAction remembered_set_action,
85 SaveFPRegsMode fp_mode)
Ben Murdochb8a8cc12014-11-26 15:28:44 +000086 : PlatformCodeStub(isolate),
Ben Murdoch3ef787d2012-04-12 10:51:47 +010087 regs_(object, // An input reg.
88 address, // An input reg.
89 value) { // One scratch reg.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000090 minor_key_ = ObjectBits::encode(object.code()) |
91 ValueBits::encode(value.code()) |
92 AddressBits::encode(address.code()) |
93 RememberedSetActionBits::encode(remembered_set_action) |
94 SaveFPRegsModeBits::encode(fp_mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010095 }
96
Ben Murdochb8a8cc12014-11-26 15:28:44 +000097 RecordWriteStub(uint32_t key, Isolate* isolate)
98 : PlatformCodeStub(key, isolate), regs_(object(), address(), value()) {}
99
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100100 enum Mode {
101 STORE_BUFFER_ONLY,
102 INCREMENTAL,
103 INCREMENTAL_COMPACTION
104 };
105
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000106 bool SometimesSetsUpAFrame() override { return false; }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100107
108 static void PatchBranchIntoNop(MacroAssembler* masm, int pos) {
109 const unsigned offset = masm->instr_at(pos) & kImm16Mask;
110 masm->instr_at_put(pos, BNE | (zero_reg.code() << kRsShift) |
111 (zero_reg.code() << kRtShift) | (offset & kImm16Mask));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000112 DCHECK(Assembler::IsBne(masm->instr_at(pos)));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100113 }
114
115 static void PatchNopIntoBranch(MacroAssembler* masm, int pos) {
116 const unsigned offset = masm->instr_at(pos) & kImm16Mask;
117 masm->instr_at_put(pos, BEQ | (zero_reg.code() << kRsShift) |
118 (zero_reg.code() << kRtShift) | (offset & kImm16Mask));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000119 DCHECK(Assembler::IsBeq(masm->instr_at(pos)));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100120 }
121
122 static Mode GetMode(Code* stub) {
123 Instr first_instruction = Assembler::instr_at(stub->instruction_start());
124 Instr second_instruction = Assembler::instr_at(stub->instruction_start() +
125 2 * Assembler::kInstrSize);
126
127 if (Assembler::IsBeq(first_instruction)) {
128 return INCREMENTAL;
129 }
130
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000131 DCHECK(Assembler::IsBne(first_instruction));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100132
133 if (Assembler::IsBeq(second_instruction)) {
134 return INCREMENTAL_COMPACTION;
135 }
136
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000137 DCHECK(Assembler::IsBne(second_instruction));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100138
139 return STORE_BUFFER_ONLY;
140 }
141
142 static void Patch(Code* stub, Mode mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000143 MacroAssembler masm(stub->GetIsolate(), stub->instruction_start(),
144 stub->instruction_size(), CodeObjectRequired::kNo);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100145 switch (mode) {
146 case STORE_BUFFER_ONLY:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000147 DCHECK(GetMode(stub) == INCREMENTAL ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100148 GetMode(stub) == INCREMENTAL_COMPACTION);
149 PatchBranchIntoNop(&masm, 0);
150 PatchBranchIntoNop(&masm, 2 * Assembler::kInstrSize);
151 break;
152 case INCREMENTAL:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000153 DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100154 PatchNopIntoBranch(&masm, 0);
155 break;
156 case INCREMENTAL_COMPACTION:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000157 DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100158 PatchNopIntoBranch(&masm, 2 * Assembler::kInstrSize);
159 break;
160 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000161 DCHECK(GetMode(stub) == mode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000162 Assembler::FlushICache(stub->GetIsolate(), stub->instruction_start(),
163 4 * Assembler::kInstrSize);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100164 }
165
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000166 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
167
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100168 private:
169 // This is a helper class for freeing up 3 scratch registers. The input is
170 // two registers that must be preserved and one scratch register provided by
171 // the caller.
172 class RegisterAllocation {
173 public:
174 RegisterAllocation(Register object,
175 Register address,
176 Register scratch0)
177 : object_(object),
178 address_(address),
179 scratch0_(scratch0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000180 DCHECK(!AreAliased(scratch0, object, address, no_reg));
181 scratch1_ = GetRegisterThatIsNotOneOf(object_, address_, scratch0_);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100182 }
183
184 void Save(MacroAssembler* masm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000185 DCHECK(!AreAliased(object_, address_, scratch1_, scratch0_));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100186 // We don't have to save scratch0_ because it was given to us as
187 // a scratch register.
188 masm->push(scratch1_);
189 }
190
191 void Restore(MacroAssembler* masm) {
192 masm->pop(scratch1_);
193 }
194
195 // If we have to call into C then we need to save and restore all caller-
196 // saved registers that were not already preserved. The scratch registers
197 // will be restored by other means so we don't bother pushing them here.
198 void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
199 masm->MultiPush((kJSCallerSaved | ra.bit()) & ~scratch1_.bit());
200 if (mode == kSaveFPRegs) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100201 masm->MultiPushFPU(kCallerSavedFPU);
202 }
203 }
204
205 inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
206 SaveFPRegsMode mode) {
207 if (mode == kSaveFPRegs) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100208 masm->MultiPopFPU(kCallerSavedFPU);
209 }
210 masm->MultiPop((kJSCallerSaved | ra.bit()) & ~scratch1_.bit());
211 }
212
213 inline Register object() { return object_; }
214 inline Register address() { return address_; }
215 inline Register scratch0() { return scratch0_; }
216 inline Register scratch1() { return scratch1_; }
217
218 private:
219 Register object_;
220 Register address_;
221 Register scratch0_;
222 Register scratch1_;
223
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100224 friend class RecordWriteStub;
225 };
226
227 enum OnNoNeedToInformIncrementalMarker {
228 kReturnOnNoNeedToInformIncrementalMarker,
229 kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
230 };
231
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000232 inline Major MajorKey() const final { return RecordWrite; }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000233
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000234 void Generate(MacroAssembler* masm) override;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100235 void GenerateIncremental(MacroAssembler* masm, Mode mode);
236 void CheckNeedsToInformIncrementalMarker(
237 MacroAssembler* masm,
238 OnNoNeedToInformIncrementalMarker on_no_need,
239 Mode mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000240 void InformIncrementalMarker(MacroAssembler* masm);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100241
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000242 void Activate(Code* code) override {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100243 code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
244 }
245
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000246 Register object() const {
247 return Register::from_code(ObjectBits::decode(minor_key_));
248 }
249
250 Register value() const {
251 return Register::from_code(ValueBits::decode(minor_key_));
252 }
253
254 Register address() const {
255 return Register::from_code(AddressBits::decode(minor_key_));
256 }
257
258 RememberedSetAction remembered_set_action() const {
259 return RememberedSetActionBits::decode(minor_key_);
260 }
261
262 SaveFPRegsMode save_fp_regs_mode() const {
263 return SaveFPRegsModeBits::decode(minor_key_);
264 }
265
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100266 class ObjectBits: public BitField<int, 0, 5> {};
267 class ValueBits: public BitField<int, 5, 5> {};
268 class AddressBits: public BitField<int, 10, 5> {};
269 class RememberedSetActionBits: public BitField<RememberedSetAction, 15, 1> {};
270 class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 16, 1> {};
271
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100272 Label slow_;
273 RegisterAllocation regs_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000274
275 DISALLOW_COPY_AND_ASSIGN(RecordWriteStub);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100276};
277
278
Ben Murdoch257744e2011-11-30 15:57:28 +0000279// Trampoline stub to call into native code. To call safely into native code
280// in the presence of compacting GC (which can move code objects) we need to
281// keep the code which called into native pinned in the memory. Currently the
282// simplest approach is to generate such stub early enough so it can never be
283// moved by GC
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000284class DirectCEntryStub: public PlatformCodeStub {
Ben Murdoch257744e2011-11-30 15:57:28 +0000285 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000286 explicit DirectCEntryStub(Isolate* isolate) : PlatformCodeStub(isolate) {}
Ben Murdoch257744e2011-11-30 15:57:28 +0000287 void GenerateCall(MacroAssembler* masm, Register target);
Steve Block44f0eee2011-05-26 01:26:41 +0100288
Ben Murdoch257744e2011-11-30 15:57:28 +0000289 private:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000290 bool NeedsImmovableCode() override { return true; }
Ben Murdoch257744e2011-11-30 15:57:28 +0000291
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000292 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
293 DEFINE_PLATFORM_CODE_STUB(DirectCEntry, PlatformCodeStub);
Ben Murdoch257744e2011-11-30 15:57:28 +0000294};
295
296
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000297class NameDictionaryLookupStub: public PlatformCodeStub {
Ben Murdoch257744e2011-11-30 15:57:28 +0000298 public:
299 enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
300
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000301 NameDictionaryLookupStub(Isolate* isolate, LookupMode mode)
302 : PlatformCodeStub(isolate) {
303 minor_key_ = LookupModeBits::encode(mode);
304 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000305
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100306 static void GenerateNegativeLookup(MacroAssembler* masm,
307 Label* miss,
308 Label* done,
309 Register receiver,
310 Register properties,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000311 Handle<Name> name,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100312 Register scratch0);
Ben Murdoch257744e2011-11-30 15:57:28 +0000313
314 static void GeneratePositiveLookup(MacroAssembler* masm,
315 Label* miss,
316 Label* done,
317 Register elements,
318 Register name,
319 Register r0,
320 Register r1);
321
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000322 bool SometimesSetsUpAFrame() override { return false; }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100323
Ben Murdoch257744e2011-11-30 15:57:28 +0000324 private:
325 static const int kInlinedProbes = 4;
326 static const int kTotalProbes = 20;
327
328 static const int kCapacityOffset =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000329 NameDictionary::kHeaderSize +
330 NameDictionary::kCapacityIndex * kPointerSize;
Ben Murdoch257744e2011-11-30 15:57:28 +0000331
332 static const int kElementsStartOffset =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000333 NameDictionary::kHeaderSize +
334 NameDictionary::kElementsStartIndex * kPointerSize;
Ben Murdoch257744e2011-11-30 15:57:28 +0000335
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000336 LookupMode mode() const { return LookupModeBits::decode(minor_key_); }
Ben Murdoch257744e2011-11-30 15:57:28 +0000337
338 class LookupModeBits: public BitField<LookupMode, 0, 1> {};
339
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000340 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
341 DEFINE_PLATFORM_CODE_STUB(NameDictionaryLookup, PlatformCodeStub);
Ben Murdoch257744e2011-11-30 15:57:28 +0000342};
Steve Block44f0eee2011-05-26 01:26:41 +0100343
344
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000345} // namespace internal
346} // namespace v8
Steve Block44f0eee2011-05-26 01:26:41 +0100347
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000348#endif // V8_MIPS_CODE_STUBS_MIPS_H_