1// Copyright 2012 the V8 project authors. All rights reserved. 2// 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_ARM_CODE_STUBS_ARM_H_ 29#define V8_ARM_CODE_STUBS_ARM_H_ 30 31#include "ic-inl.h" 32 33namespace v8 { 34namespace internal { 35 36 37void ArrayNativeCode(MacroAssembler* masm, Label* call_generic_code); 38 39 40// Compute a transcendental math function natively, or call the 41// TranscendentalCache runtime function. 42class TranscendentalCacheStub: public PlatformCodeStub { 43 public: 44 enum ArgumentType { 45 TAGGED = 0 << TranscendentalCache::kTranscendentalTypeBits, 46 UNTAGGED = 1 << TranscendentalCache::kTranscendentalTypeBits 47 }; 48 49 TranscendentalCacheStub(TranscendentalCache::Type type, 50 ArgumentType argument_type) 51 : type_(type), argument_type_(argument_type) { } 52 void Generate(MacroAssembler* masm); 53 private: 54 TranscendentalCache::Type type_; 55 ArgumentType argument_type_; 56 void GenerateCallCFunction(MacroAssembler* masm, Register scratch); 57 58 Major MajorKey() { return TranscendentalCache; } 59 int MinorKey() { return type_ | argument_type_; } 60 Runtime::FunctionId RuntimeFunction(); 61}; 62 63 64class StoreBufferOverflowStub: public PlatformCodeStub { 65 public: 66 explicit StoreBufferOverflowStub(SaveFPRegsMode save_fp) 67 : save_doubles_(save_fp) {} 68 69 void Generate(MacroAssembler* masm); 70 71 static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate); 72 virtual bool SometimesSetsUpAFrame() { return false; } 73 74 private: 75 SaveFPRegsMode save_doubles_; 76 77 Major MajorKey() { return StoreBufferOverflow; } 78 int MinorKey() { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; } 79}; 80 81 82class StringHelper : public AllStatic { 83 public: 84 // Generate code for copying characters using a simple loop. This should only 85 // be used in places where the number of characters is small and the 86 // additional setup and checking in GenerateCopyCharactersLong adds too much 87 // overhead. Copying of overlapping regions is not supported. 88 // Dest register ends at the position after the last character written. 89 static void GenerateCopyCharacters(MacroAssembler* masm, 90 Register dest, 91 Register src, 92 Register count, 93 Register scratch, 94 bool ascii); 95 96 // Generate code for copying a large number of characters. This function 97 // is allowed to spend extra time setting up conditions to make copying 98 // faster. Copying of overlapping regions is not supported. 99 // Dest register ends at the position after the last character written. 100 static void GenerateCopyCharactersLong(MacroAssembler* masm, 101 Register dest, 102 Register src, 103 Register count, 104 Register scratch1, 105 Register scratch2, 106 Register scratch3, 107 Register scratch4, 108 int flags); 109 110 111 // Probe the string table for a two character string. If the string is 112 // not found by probing a jump to the label not_found is performed. This jump 113 // does not guarantee that the string is not in the string table. If the 114 // string is found the code falls through with the string in register r0. 115 // Contents of both c1 and c2 registers are modified. At the exit c1 is 116 // guaranteed to contain halfword with low and high bytes equal to 117 // initial contents of c1 and c2 respectively. 118 static void GenerateTwoCharacterStringTableProbe(MacroAssembler* masm, 119 Register c1, 120 Register c2, 121 Register scratch1, 122 Register scratch2, 123 Register scratch3, 124 Register scratch4, 125 Register scratch5, 126 Label* not_found); 127 128 // Generate string hash. 129 static void GenerateHashInit(MacroAssembler* masm, 130 Register hash, 131 Register character); 132 133 static void GenerateHashAddCharacter(MacroAssembler* masm, 134 Register hash, 135 Register character); 136 137 static void GenerateHashGetHash(MacroAssembler* masm, 138 Register hash); 139 140 private: 141 DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper); 142}; 143 144 145class StringAddStub: public PlatformCodeStub { 146 public: 147 explicit StringAddStub(StringAddFlags flags) : flags_(flags) {} 148 149 private: 150 Major MajorKey() { return StringAdd; } 151 int MinorKey() { return flags_; } 152 153 void Generate(MacroAssembler* masm); 154 155 void GenerateConvertArgument(MacroAssembler* masm, 156 int stack_offset, 157 Register arg, 158 Register scratch1, 159 Register scratch2, 160 Register scratch3, 161 Register scratch4, 162 Label* slow); 163 164 void GenerateRegisterArgsPush(MacroAssembler* masm); 165 void GenerateRegisterArgsPop(MacroAssembler* masm); 166 167 const StringAddFlags flags_; 168}; 169 170 171class SubStringStub: public PlatformCodeStub { 172 public: 173 SubStringStub() {} 174 175 private: 176 Major MajorKey() { return SubString; } 177 int MinorKey() { return 0; } 178 179 void Generate(MacroAssembler* masm); 180}; 181 182 183 184class StringCompareStub: public PlatformCodeStub { 185 public: 186 StringCompareStub() { } 187 188 // Compares two flat ASCII strings and returns result in r0. 189 static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm, 190 Register left, 191 Register right, 192 Register scratch1, 193 Register scratch2, 194 Register scratch3, 195 Register scratch4); 196 197 // Compares two flat ASCII strings for equality and returns result 198 // in r0. 199 static void GenerateFlatAsciiStringEquals(MacroAssembler* masm, 200 Register left, 201 Register right, 202 Register scratch1, 203 Register scratch2, 204 Register scratch3); 205 206 private: 207 virtual Major MajorKey() { return StringCompare; } 208 virtual int MinorKey() { return 0; } 209 virtual void Generate(MacroAssembler* masm); 210 211 static void GenerateAsciiCharsCompareLoop(MacroAssembler* masm, 212 Register left, 213 Register right, 214 Register length, 215 Register scratch1, 216 Register scratch2, 217 Label* chars_not_equal); 218}; 219 220 221// This stub can convert a signed int32 to a heap number (double). It does 222// not work for int32s that are in Smi range! No GC occurs during this stub 223// so you don't have to set up the frame. 224class WriteInt32ToHeapNumberStub : public PlatformCodeStub { 225 public: 226 WriteInt32ToHeapNumberStub(Register the_int, 227 Register the_heap_number, 228 Register scratch) 229 : the_int_(the_int), 230 the_heap_number_(the_heap_number), 231 scratch_(scratch) { } 232 233 static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate); 234 235 private: 236 Register the_int_; 237 Register the_heap_number_; 238 Register scratch_; 239 240 // Minor key encoding in 16 bits. 241 class IntRegisterBits: public BitField<int, 0, 4> {}; 242 class HeapNumberRegisterBits: public BitField<int, 4, 4> {}; 243 class ScratchRegisterBits: public BitField<int, 8, 4> {}; 244 245 Major MajorKey() { return WriteInt32ToHeapNumber; } 246 int MinorKey() { 247 // Encode the parameters in a unique 16 bit value. 248 return IntRegisterBits::encode(the_int_.code()) 249 | HeapNumberRegisterBits::encode(the_heap_number_.code()) 250 | ScratchRegisterBits::encode(scratch_.code()); 251 } 252 253 void Generate(MacroAssembler* masm); 254}; 255 256 257class RecordWriteStub: public PlatformCodeStub { 258 public: 259 RecordWriteStub(Register object, 260 Register value, 261 Register address, 262 RememberedSetAction remembered_set_action, 263 SaveFPRegsMode fp_mode) 264 : object_(object), 265 value_(value), 266 address_(address), 267 remembered_set_action_(remembered_set_action), 268 save_fp_regs_mode_(fp_mode), 269 regs_(object, // An input reg. 270 address, // An input reg. 271 value) { // One scratch reg. 272 } 273 274 enum Mode { 275 STORE_BUFFER_ONLY, 276 INCREMENTAL, 277 INCREMENTAL_COMPACTION 278 }; 279 280 virtual bool SometimesSetsUpAFrame() { return false; } 281 282 static void PatchBranchIntoNop(MacroAssembler* masm, int pos) { 283 masm->instr_at_put(pos, (masm->instr_at(pos) & ~B27) | (B24 | B20)); 284 ASSERT(Assembler::IsTstImmediate(masm->instr_at(pos))); 285 } 286 287 static void PatchNopIntoBranch(MacroAssembler* masm, int pos) { 288 masm->instr_at_put(pos, (masm->instr_at(pos) & ~(B24 | B20)) | B27); 289 ASSERT(Assembler::IsBranch(masm->instr_at(pos))); 290 } 291 292 static Mode GetMode(Code* stub) { 293 Instr first_instruction = Assembler::instr_at(stub->instruction_start()); 294 Instr second_instruction = Assembler::instr_at(stub->instruction_start() + 295 Assembler::kInstrSize); 296 297 if (Assembler::IsBranch(first_instruction)) { 298 return INCREMENTAL; 299 } 300 301 ASSERT(Assembler::IsTstImmediate(first_instruction)); 302 303 if (Assembler::IsBranch(second_instruction)) { 304 return INCREMENTAL_COMPACTION; 305 } 306 307 ASSERT(Assembler::IsTstImmediate(second_instruction)); 308 309 return STORE_BUFFER_ONLY; 310 } 311 312 static void Patch(Code* stub, Mode mode) { 313 MacroAssembler masm(NULL, 314 stub->instruction_start(), 315 stub->instruction_size()); 316 switch (mode) { 317 case STORE_BUFFER_ONLY: 318 ASSERT(GetMode(stub) == INCREMENTAL || 319 GetMode(stub) == INCREMENTAL_COMPACTION); 320 PatchBranchIntoNop(&masm, 0); 321 PatchBranchIntoNop(&masm, Assembler::kInstrSize); 322 break; 323 case INCREMENTAL: 324 ASSERT(GetMode(stub) == STORE_BUFFER_ONLY); 325 PatchNopIntoBranch(&masm, 0); 326 break; 327 case INCREMENTAL_COMPACTION: 328 ASSERT(GetMode(stub) == STORE_BUFFER_ONLY); 329 PatchNopIntoBranch(&masm, Assembler::kInstrSize); 330 break; 331 } 332 ASSERT(GetMode(stub) == mode); 333 CPU::FlushICache(stub->instruction_start(), 2 * Assembler::kInstrSize); 334 } 335 336 private: 337 // This is a helper class for freeing up 3 scratch registers. The input is 338 // two registers that must be preserved and one scratch register provided by 339 // the caller. 340 class RegisterAllocation { 341 public: 342 RegisterAllocation(Register object, 343 Register address, 344 Register scratch0) 345 : object_(object), 346 address_(address), 347 scratch0_(scratch0) { 348 ASSERT(!AreAliased(scratch0, object, address, no_reg)); 349 scratch1_ = GetRegisterThatIsNotOneOf(object_, address_, scratch0_); 350 } 351 352 void Save(MacroAssembler* masm) { 353 ASSERT(!AreAliased(object_, address_, scratch1_, scratch0_)); 354 // We don't have to save scratch0_ because it was given to us as 355 // a scratch register. 356 masm->push(scratch1_); 357 } 358 359 void Restore(MacroAssembler* masm) { 360 masm->pop(scratch1_); 361 } 362 363 // If we have to call into C then we need to save and restore all caller- 364 // saved registers that were not already preserved. The scratch registers 365 // will be restored by other means so we don't bother pushing them here. 366 void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) { 367 masm->stm(db_w, sp, (kCallerSaved | lr.bit()) & ~scratch1_.bit()); 368 if (mode == kSaveFPRegs) { 369 masm->SaveFPRegs(sp, scratch0_); 370 } 371 } 372 373 inline void RestoreCallerSaveRegisters(MacroAssembler*masm, 374 SaveFPRegsMode mode) { 375 if (mode == kSaveFPRegs) { 376 masm->RestoreFPRegs(sp, scratch0_); 377 } 378 masm->ldm(ia_w, sp, (kCallerSaved | lr.bit()) & ~scratch1_.bit()); 379 } 380 381 inline Register object() { return object_; } 382 inline Register address() { return address_; } 383 inline Register scratch0() { return scratch0_; } 384 inline Register scratch1() { return scratch1_; } 385 386 private: 387 Register object_; 388 Register address_; 389 Register scratch0_; 390 Register scratch1_; 391 392 friend class RecordWriteStub; 393 }; 394 395 enum OnNoNeedToInformIncrementalMarker { 396 kReturnOnNoNeedToInformIncrementalMarker, 397 kUpdateRememberedSetOnNoNeedToInformIncrementalMarker 398 }; 399 400 void Generate(MacroAssembler* masm); 401 void GenerateIncremental(MacroAssembler* masm, Mode mode); 402 void CheckNeedsToInformIncrementalMarker( 403 MacroAssembler* masm, 404 OnNoNeedToInformIncrementalMarker on_no_need, 405 Mode mode); 406 void InformIncrementalMarker(MacroAssembler* masm, Mode mode); 407 408 Major MajorKey() { return RecordWrite; } 409 410 int MinorKey() { 411 return ObjectBits::encode(object_.code()) | 412 ValueBits::encode(value_.code()) | 413 AddressBits::encode(address_.code()) | 414 RememberedSetActionBits::encode(remembered_set_action_) | 415 SaveFPRegsModeBits::encode(save_fp_regs_mode_); 416 } 417 418 void Activate(Code* code) { 419 code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code); 420 } 421 422 class ObjectBits: public BitField<int, 0, 4> {}; 423 class ValueBits: public BitField<int, 4, 4> {}; 424 class AddressBits: public BitField<int, 8, 4> {}; 425 class RememberedSetActionBits: public BitField<RememberedSetAction, 12, 1> {}; 426 class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 13, 1> {}; 427 428 Register object_; 429 Register value_; 430 Register address_; 431 RememberedSetAction remembered_set_action_; 432 SaveFPRegsMode save_fp_regs_mode_; 433 Label slow_; 434 RegisterAllocation regs_; 435}; 436 437 438// Trampoline stub to call into native code. To call safely into native code 439// in the presence of compacting GC (which can move code objects) we need to 440// keep the code which called into native pinned in the memory. Currently the 441// simplest approach is to generate such stub early enough so it can never be 442// moved by GC 443class DirectCEntryStub: public PlatformCodeStub { 444 public: 445 DirectCEntryStub() {} 446 void Generate(MacroAssembler* masm); 447 void GenerateCall(MacroAssembler* masm, Register target); 448 449 private: 450 Major MajorKey() { return DirectCEntry; } 451 int MinorKey() { return 0; } 452 453 bool NeedsImmovableCode() { return true; } 454}; 455 456 457class NameDictionaryLookupStub: public PlatformCodeStub { 458 public: 459 enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP }; 460 461 explicit NameDictionaryLookupStub(LookupMode mode) : mode_(mode) { } 462 463 void Generate(MacroAssembler* masm); 464 465 static void GenerateNegativeLookup(MacroAssembler* masm, 466 Label* miss, 467 Label* done, 468 Register receiver, 469 Register properties, 470 Handle<Name> name, 471 Register scratch0); 472 473 static void GeneratePositiveLookup(MacroAssembler* masm, 474 Label* miss, 475 Label* done, 476 Register elements, 477 Register name, 478 Register r0, 479 Register r1); 480 481 virtual bool SometimesSetsUpAFrame() { return false; } 482 483 private: 484 static const int kInlinedProbes = 4; 485 static const int kTotalProbes = 20; 486 487 static const int kCapacityOffset = 488 NameDictionary::kHeaderSize + 489 NameDictionary::kCapacityIndex * kPointerSize; 490 491 static const int kElementsStartOffset = 492 NameDictionary::kHeaderSize + 493 NameDictionary::kElementsStartIndex * kPointerSize; 494 495 Major MajorKey() { return NameDictionaryLookup; } 496 497 int MinorKey() { 498 return LookupModeBits::encode(mode_); 499 } 500 501 class LookupModeBits: public BitField<LookupMode, 0, 1> {}; 502 503 LookupMode mode_; 504}; 505 506 507} } // namespace v8::internal 508 509#endif // V8_ARM_CODE_STUBS_ARM_H_ 510