1 // Copyright 2011 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.
5 #ifndef V8_MIPS_CODE_STUBS_MIPS64_H_
6 #define V8_MIPS_CODE_STUBS_MIPS64_H_
8 #include "src/mips64/frames-mips64.h"
14 void ArrayNativeCode(MacroAssembler* masm, Label* call_generic_code);
17 class StringHelper : public AllStatic {
19 // 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.
22 // Dest register ends at the position after the last character written.
23 static void GenerateCopyCharacters(MacroAssembler* masm,
28 String::Encoding encoding);
30 // 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);
35 // Compares two flat one-byte strings for equality and returns result in v0.
36 static void GenerateFlatOneByteStringEquals(MacroAssembler* masm,
37 Register left, Register right,
43 static void GenerateOneByteCharsCompareLoop(
44 MacroAssembler* masm, Register left, Register right, Register length,
45 Register scratch1, Register scratch2, Register scratch3,
46 Label* chars_not_equal);
49 DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
53 class StoreRegistersStateStub: public PlatformCodeStub {
55 explicit StoreRegistersStateStub(Isolate* isolate)
56 : PlatformCodeStub(isolate) {}
58 static void GenerateAheadOfTime(Isolate* isolate);
61 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
62 DEFINE_PLATFORM_CODE_STUB(StoreRegistersState, PlatformCodeStub);
66 class RestoreRegistersStateStub: public PlatformCodeStub {
68 explicit RestoreRegistersStateStub(Isolate* isolate)
69 : PlatformCodeStub(isolate) {}
71 static void GenerateAheadOfTime(Isolate* isolate);
74 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
75 DEFINE_PLATFORM_CODE_STUB(RestoreRegistersState, PlatformCodeStub);
79 class RecordWriteStub: public PlatformCodeStub {
81 RecordWriteStub(Isolate* isolate,
85 RememberedSetAction remembered_set_action,
86 SaveFPRegsMode fp_mode)
87 : PlatformCodeStub(isolate),
88 regs_(object, // An input reg.
89 address, // An input reg.
90 value) { // One scratch reg.
91 minor_key_ = ObjectBits::encode(object.code()) |
92 ValueBits::encode(value.code()) |
93 AddressBits::encode(address.code()) |
94 RememberedSetActionBits::encode(remembered_set_action) |
95 SaveFPRegsModeBits::encode(fp_mode);
98 RecordWriteStub(uint32_t key, Isolate* isolate)
99 : PlatformCodeStub(key, isolate), regs_(object(), address(), value()) {}
104 INCREMENTAL_COMPACTION
107 bool SometimesSetsUpAFrame() override { return false; }
109 static void PatchBranchIntoNop(MacroAssembler* masm, int pos) {
110 const unsigned offset = masm->instr_at(pos) & kImm16Mask;
111 masm->instr_at_put(pos, BNE | (zero_reg.code() << kRsShift) |
112 (zero_reg.code() << kRtShift) | (offset & kImm16Mask));
113 DCHECK(Assembler::IsBne(masm->instr_at(pos)));
116 static void PatchNopIntoBranch(MacroAssembler* masm, int pos) {
117 const unsigned offset = masm->instr_at(pos) & kImm16Mask;
118 masm->instr_at_put(pos, BEQ | (zero_reg.code() << kRsShift) |
119 (zero_reg.code() << kRtShift) | (offset & kImm16Mask));
120 DCHECK(Assembler::IsBeq(masm->instr_at(pos)));
123 static Mode GetMode(Code* stub) {
124 Instr first_instruction = Assembler::instr_at(stub->instruction_start());
125 Instr second_instruction = Assembler::instr_at(stub->instruction_start() +
126 2 * Assembler::kInstrSize);
128 if (Assembler::IsBeq(first_instruction)) {
132 DCHECK(Assembler::IsBne(first_instruction));
134 if (Assembler::IsBeq(second_instruction)) {
135 return INCREMENTAL_COMPACTION;
138 DCHECK(Assembler::IsBne(second_instruction));
140 return STORE_BUFFER_ONLY;
143 static void Patch(Code* stub, Mode mode) {
144 MacroAssembler masm(NULL,
145 stub->instruction_start(),
146 stub->instruction_size());
148 case STORE_BUFFER_ONLY:
149 DCHECK(GetMode(stub) == INCREMENTAL ||
150 GetMode(stub) == INCREMENTAL_COMPACTION);
151 PatchBranchIntoNop(&masm, 0);
152 PatchBranchIntoNop(&masm, 2 * Assembler::kInstrSize);
155 DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
156 PatchNopIntoBranch(&masm, 0);
158 case INCREMENTAL_COMPACTION:
159 DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
160 PatchNopIntoBranch(&masm, 2 * Assembler::kInstrSize);
163 DCHECK(GetMode(stub) == mode);
164 CpuFeatures::FlushICache(stub->instruction_start(),
165 4 * Assembler::kInstrSize);
168 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
171 // This is a helper class for freeing up 3 scratch registers. The input is
172 // two registers that must be preserved and one scratch register provided by
174 class RegisterAllocation {
176 RegisterAllocation(Register object,
181 scratch0_(scratch0) {
182 DCHECK(!AreAliased(scratch0, object, address, no_reg));
183 scratch1_ = GetRegisterThatIsNotOneOf(object_, address_, scratch0_);
186 void Save(MacroAssembler* masm) {
187 DCHECK(!AreAliased(object_, address_, scratch1_, scratch0_));
188 // We don't have to save scratch0_ because it was given to us as
189 // a scratch register.
190 masm->push(scratch1_);
193 void Restore(MacroAssembler* masm) {
194 masm->pop(scratch1_);
197 // If we have to call into C then we need to save and restore all caller-
198 // saved registers that were not already preserved. The scratch registers
199 // will be restored by other means so we don't bother pushing them here.
200 void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
201 masm->MultiPush((kJSCallerSaved | ra.bit()) & ~scratch1_.bit());
202 if (mode == kSaveFPRegs) {
203 masm->MultiPushFPU(kCallerSavedFPU);
207 inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
208 SaveFPRegsMode mode) {
209 if (mode == kSaveFPRegs) {
210 masm->MultiPopFPU(kCallerSavedFPU);
212 masm->MultiPop((kJSCallerSaved | ra.bit()) & ~scratch1_.bit());
215 inline Register object() { return object_; }
216 inline Register address() { return address_; }
217 inline Register scratch0() { return scratch0_; }
218 inline Register scratch1() { return scratch1_; }
226 friend class RecordWriteStub;
229 enum OnNoNeedToInformIncrementalMarker {
230 kReturnOnNoNeedToInformIncrementalMarker,
231 kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
234 inline Major MajorKey() const final { return RecordWrite; }
236 void Generate(MacroAssembler* masm) override;
237 void GenerateIncremental(MacroAssembler* masm, Mode mode);
238 void CheckNeedsToInformIncrementalMarker(
239 MacroAssembler* masm,
240 OnNoNeedToInformIncrementalMarker on_no_need,
242 void InformIncrementalMarker(MacroAssembler* masm);
244 void Activate(Code* code) override {
245 code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
248 Register object() const {
249 return Register::from_code(ObjectBits::decode(minor_key_));
252 Register value() const {
253 return Register::from_code(ValueBits::decode(minor_key_));
256 Register address() const {
257 return Register::from_code(AddressBits::decode(minor_key_));
260 RememberedSetAction remembered_set_action() const {
261 return RememberedSetActionBits::decode(minor_key_);
264 SaveFPRegsMode save_fp_regs_mode() const {
265 return SaveFPRegsModeBits::decode(minor_key_);
268 class ObjectBits: public BitField<int, 0, 5> {};
269 class ValueBits: public BitField<int, 5, 5> {};
270 class AddressBits: public BitField<int, 10, 5> {};
271 class RememberedSetActionBits: public BitField<RememberedSetAction, 15, 1> {};
272 class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 16, 1> {};
275 RegisterAllocation regs_;
277 DISALLOW_COPY_AND_ASSIGN(RecordWriteStub);
281 // Trampoline stub to call into native code. To call safely into native code
282 // in the presence of compacting GC (which can move code objects) we need to
283 // keep the code which called into native pinned in the memory. Currently the
284 // simplest approach is to generate such stub early enough so it can never be
286 class DirectCEntryStub: public PlatformCodeStub {
288 explicit DirectCEntryStub(Isolate* isolate) : PlatformCodeStub(isolate) {}
289 void GenerateCall(MacroAssembler* masm, Register target);
292 bool NeedsImmovableCode() override { return true; }
294 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
295 DEFINE_PLATFORM_CODE_STUB(DirectCEntry, PlatformCodeStub);
299 class NameDictionaryLookupStub: public PlatformCodeStub {
301 enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
303 NameDictionaryLookupStub(Isolate* isolate, LookupMode mode)
304 : PlatformCodeStub(isolate) {
305 minor_key_ = LookupModeBits::encode(mode);
308 static void GenerateNegativeLookup(MacroAssembler* masm,
316 static void GeneratePositiveLookup(MacroAssembler* masm,
324 bool SometimesSetsUpAFrame() override { return false; }
327 static const int kInlinedProbes = 4;
328 static const int kTotalProbes = 20;
330 static const int kCapacityOffset =
331 NameDictionary::kHeaderSize +
332 NameDictionary::kCapacityIndex * kPointerSize;
334 static const int kElementsStartOffset =
335 NameDictionary::kHeaderSize +
336 NameDictionary::kElementsStartIndex * kPointerSize;
338 LookupMode mode() const { return LookupModeBits::decode(minor_key_); }
340 class LookupModeBits: public BitField<LookupMode, 0, 1> {};
342 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
343 DEFINE_PLATFORM_CODE_STUB(NameDictionaryLookup, PlatformCodeStub);
347 } } // namespace v8::internal
349 #endif // V8_MIPS_CODE_STUBS_MIPS64_H_