1 // 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. 4 5 #ifndef V8_ARM_CODE_STUBS_ARM_H_ 6 #define V8_ARM_CODE_STUBS_ARM_H_ 7 8 #include "src/arm/frames-arm.h" 9 10 namespace v8 { 11 namespace internal { 12 13 14 void ArrayNativeCode(MacroAssembler* masm, Label* call_generic_code); 15 16 17 class StringHelper : public AllStatic { 18 public: 19 // Compares two flat one-byte strings and returns result in r0. 20 static void GenerateCompareFlatOneByteStrings( 21 MacroAssembler* masm, Register left, Register right, Register scratch1, 22 Register scratch2, Register scratch3, Register scratch4); 23 24 // Compares two flat one-byte strings for equality and returns result in r0. 25 static void GenerateFlatOneByteStringEquals(MacroAssembler* masm, 26 Register left, Register right, 27 Register scratch1, 28 Register scratch2, 29 Register scratch3); 30 31 private: 32 static void GenerateOneByteCharsCompareLoop( 33 MacroAssembler* masm, Register left, Register right, Register length, 34 Register scratch1, Register scratch2, Label* chars_not_equal); 35 36 DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper); 37 }; 38 39 40 class RecordWriteStub: public PlatformCodeStub { 41 public: RecordWriteStub(Isolate * isolate,Register object,Register value,Register address,RememberedSetAction remembered_set_action,SaveFPRegsMode fp_mode)42 RecordWriteStub(Isolate* isolate, 43 Register object, 44 Register value, 45 Register address, 46 RememberedSetAction remembered_set_action, 47 SaveFPRegsMode fp_mode) 48 : PlatformCodeStub(isolate), 49 regs_(object, // An input reg. 50 address, // An input reg. 51 value) { // One scratch reg. 52 minor_key_ = ObjectBits::encode(object.code()) | 53 ValueBits::encode(value.code()) | 54 AddressBits::encode(address.code()) | 55 RememberedSetActionBits::encode(remembered_set_action) | 56 SaveFPRegsModeBits::encode(fp_mode); 57 } 58 RecordWriteStub(uint32_t key,Isolate * isolate)59 RecordWriteStub(uint32_t key, Isolate* isolate) 60 : PlatformCodeStub(key, isolate), regs_(object(), address(), value()) {} 61 62 enum Mode { 63 STORE_BUFFER_ONLY, 64 INCREMENTAL, 65 INCREMENTAL_COMPACTION 66 }; 67 SometimesSetsUpAFrame()68 bool SometimesSetsUpAFrame() override { return false; } 69 PatchBranchIntoNop(MacroAssembler * masm,int pos)70 static void PatchBranchIntoNop(MacroAssembler* masm, int pos) { 71 masm->instr_at_put(pos, (masm->instr_at(pos) & ~B27) | (B24 | B20)); 72 DCHECK(Assembler::IsTstImmediate(masm->instr_at(pos))); 73 } 74 PatchNopIntoBranch(MacroAssembler * masm,int pos)75 static void PatchNopIntoBranch(MacroAssembler* masm, int pos) { 76 masm->instr_at_put(pos, (masm->instr_at(pos) & ~(B24 | B20)) | B27); 77 DCHECK(Assembler::IsBranch(masm->instr_at(pos))); 78 } 79 GetMode(Code * stub)80 static Mode GetMode(Code* stub) { 81 Instr first_instruction = Assembler::instr_at(stub->instruction_start()); 82 Instr second_instruction = Assembler::instr_at(stub->instruction_start() + 83 Assembler::kInstrSize); 84 85 if (Assembler::IsBranch(first_instruction)) { 86 return INCREMENTAL; 87 } 88 89 DCHECK(Assembler::IsTstImmediate(first_instruction)); 90 91 if (Assembler::IsBranch(second_instruction)) { 92 return INCREMENTAL_COMPACTION; 93 } 94 95 DCHECK(Assembler::IsTstImmediate(second_instruction)); 96 97 return STORE_BUFFER_ONLY; 98 } 99 Patch(Code * stub,Mode mode)100 static void Patch(Code* stub, Mode mode) { 101 MacroAssembler masm(stub->GetIsolate(), stub->instruction_start(), 102 stub->instruction_size(), CodeObjectRequired::kNo); 103 switch (mode) { 104 case STORE_BUFFER_ONLY: 105 DCHECK(GetMode(stub) == INCREMENTAL || 106 GetMode(stub) == INCREMENTAL_COMPACTION); 107 PatchBranchIntoNop(&masm, 0); 108 PatchBranchIntoNop(&masm, Assembler::kInstrSize); 109 break; 110 case INCREMENTAL: 111 DCHECK(GetMode(stub) == STORE_BUFFER_ONLY); 112 PatchNopIntoBranch(&masm, 0); 113 break; 114 case INCREMENTAL_COMPACTION: 115 DCHECK(GetMode(stub) == STORE_BUFFER_ONLY); 116 PatchNopIntoBranch(&masm, Assembler::kInstrSize); 117 break; 118 } 119 DCHECK(GetMode(stub) == mode); 120 Assembler::FlushICache(stub->GetIsolate(), stub->instruction_start(), 121 2 * Assembler::kInstrSize); 122 } 123 124 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR(); 125 126 private: 127 // This is a helper class for freeing up 3 scratch registers. The input is 128 // two registers that must be preserved and one scratch register provided by 129 // the caller. 130 class RegisterAllocation { 131 public: RegisterAllocation(Register object,Register address,Register scratch0)132 RegisterAllocation(Register object, 133 Register address, 134 Register scratch0) 135 : object_(object), 136 address_(address), 137 scratch0_(scratch0) { 138 DCHECK(!AreAliased(scratch0, object, address, no_reg)); 139 scratch1_ = GetRegisterThatIsNotOneOf(object_, address_, scratch0_); 140 } 141 Save(MacroAssembler * masm)142 void Save(MacroAssembler* masm) { 143 DCHECK(!AreAliased(object_, address_, scratch1_, scratch0_)); 144 // We don't have to save scratch0_ because it was given to us as 145 // a scratch register. 146 masm->push(scratch1_); 147 } 148 Restore(MacroAssembler * masm)149 void Restore(MacroAssembler* masm) { 150 masm->pop(scratch1_); 151 } 152 153 // If we have to call into C then we need to save and restore all caller- 154 // saved registers that were not already preserved. The scratch registers 155 // will be restored by other means so we don't bother pushing them here. SaveCallerSaveRegisters(MacroAssembler * masm,SaveFPRegsMode mode)156 void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) { 157 masm->stm(db_w, sp, (kCallerSaved | lr.bit()) & ~scratch1_.bit()); 158 if (mode == kSaveFPRegs) { 159 masm->SaveFPRegs(sp, scratch0_); 160 } 161 } 162 RestoreCallerSaveRegisters(MacroAssembler * masm,SaveFPRegsMode mode)163 inline void RestoreCallerSaveRegisters(MacroAssembler*masm, 164 SaveFPRegsMode mode) { 165 if (mode == kSaveFPRegs) { 166 masm->RestoreFPRegs(sp, scratch0_); 167 } 168 masm->ldm(ia_w, sp, (kCallerSaved | lr.bit()) & ~scratch1_.bit()); 169 } 170 object()171 inline Register object() { return object_; } address()172 inline Register address() { return address_; } scratch0()173 inline Register scratch0() { return scratch0_; } scratch1()174 inline Register scratch1() { return scratch1_; } 175 176 private: 177 Register object_; 178 Register address_; 179 Register scratch0_; 180 Register scratch1_; 181 182 friend class RecordWriteStub; 183 }; 184 185 enum OnNoNeedToInformIncrementalMarker { 186 kReturnOnNoNeedToInformIncrementalMarker, 187 kUpdateRememberedSetOnNoNeedToInformIncrementalMarker 188 }; 189 MajorKey()190 inline Major MajorKey() const final { return RecordWrite; } 191 192 void Generate(MacroAssembler* masm) override; 193 void GenerateIncremental(MacroAssembler* masm, Mode mode); 194 void CheckNeedsToInformIncrementalMarker( 195 MacroAssembler* masm, 196 OnNoNeedToInformIncrementalMarker on_no_need, 197 Mode mode); 198 void InformIncrementalMarker(MacroAssembler* masm); 199 Activate(Code * code)200 void Activate(Code* code) override { 201 code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code); 202 } 203 object()204 Register object() const { 205 return Register::from_code(ObjectBits::decode(minor_key_)); 206 } 207 value()208 Register value() const { 209 return Register::from_code(ValueBits::decode(minor_key_)); 210 } 211 address()212 Register address() const { 213 return Register::from_code(AddressBits::decode(minor_key_)); 214 } 215 remembered_set_action()216 RememberedSetAction remembered_set_action() const { 217 return RememberedSetActionBits::decode(minor_key_); 218 } 219 save_fp_regs_mode()220 SaveFPRegsMode save_fp_regs_mode() const { 221 return SaveFPRegsModeBits::decode(minor_key_); 222 } 223 224 class ObjectBits: public BitField<int, 0, 4> {}; 225 class ValueBits: public BitField<int, 4, 4> {}; 226 class AddressBits: public BitField<int, 8, 4> {}; 227 class RememberedSetActionBits: public BitField<RememberedSetAction, 12, 1> {}; 228 class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 13, 1> {}; 229 230 Label slow_; 231 RegisterAllocation regs_; 232 233 DISALLOW_COPY_AND_ASSIGN(RecordWriteStub); 234 }; 235 236 237 // Trampoline stub to call into native code. To call safely into native code 238 // in the presence of compacting GC (which can move code objects) we need to 239 // keep the code which called into native pinned in the memory. Currently the 240 // simplest approach is to generate such stub early enough so it can never be 241 // moved by GC 242 class DirectCEntryStub: public PlatformCodeStub { 243 public: DirectCEntryStub(Isolate * isolate)244 explicit DirectCEntryStub(Isolate* isolate) : PlatformCodeStub(isolate) {} 245 void GenerateCall(MacroAssembler* masm, Register target); 246 247 private: NeedsImmovableCode()248 bool NeedsImmovableCode() override { return true; } 249 250 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR(); 251 DEFINE_PLATFORM_CODE_STUB(DirectCEntry, PlatformCodeStub); 252 }; 253 254 255 class NameDictionaryLookupStub: public PlatformCodeStub { 256 public: 257 enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP }; 258 NameDictionaryLookupStub(Isolate * isolate,LookupMode mode)259 NameDictionaryLookupStub(Isolate* isolate, LookupMode mode) 260 : PlatformCodeStub(isolate) { 261 minor_key_ = LookupModeBits::encode(mode); 262 } 263 264 static void GenerateNegativeLookup(MacroAssembler* masm, 265 Label* miss, 266 Label* done, 267 Register receiver, 268 Register properties, 269 Handle<Name> name, 270 Register scratch0); 271 SometimesSetsUpAFrame()272 bool SometimesSetsUpAFrame() override { return false; } 273 274 private: 275 static const int kInlinedProbes = 4; 276 static const int kTotalProbes = 20; 277 278 static const int kCapacityOffset = 279 NameDictionary::kHeaderSize + 280 NameDictionary::kCapacityIndex * kPointerSize; 281 282 static const int kElementsStartOffset = 283 NameDictionary::kHeaderSize + 284 NameDictionary::kElementsStartIndex * kPointerSize; 285 mode()286 LookupMode mode() const { return LookupModeBits::decode(minor_key_); } 287 288 class LookupModeBits: public BitField<LookupMode, 0, 1> {}; 289 290 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR(); 291 DEFINE_PLATFORM_CODE_STUB(NameDictionaryLookup, PlatformCodeStub); 292 }; 293 294 } // namespace internal 295 } // namespace v8 296 297 #endif // V8_ARM_CODE_STUBS_ARM_H_ 298