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