code-stubs-arm.h revision 80d68eab642096c1a48b6474d6ec33064b0ad1f5
1// Copyright 2010 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 37// Compute a transcendental math function natively, or call the 38// TranscendentalCache runtime function. 39class TranscendentalCacheStub: public CodeStub { 40 public: 41 explicit TranscendentalCacheStub(TranscendentalCache::Type type) 42 : type_(type) {} 43 void Generate(MacroAssembler* masm); 44 private: 45 TranscendentalCache::Type type_; 46 Major MajorKey() { return TranscendentalCache; } 47 int MinorKey() { return type_; } 48 Runtime::FunctionId RuntimeFunction(); 49}; 50 51 52class ToBooleanStub: public CodeStub { 53 public: 54 explicit ToBooleanStub(Register tos) : tos_(tos) { } 55 56 void Generate(MacroAssembler* masm); 57 58 private: 59 Register tos_; 60 Major MajorKey() { return ToBoolean; } 61 int MinorKey() { return tos_.code(); } 62}; 63 64 65class GenericBinaryOpStub : public CodeStub { 66 public: 67 static const int kUnknownIntValue = -1; 68 69 GenericBinaryOpStub(Token::Value op, 70 OverwriteMode mode, 71 Register lhs, 72 Register rhs, 73 int constant_rhs = kUnknownIntValue) 74 : op_(op), 75 mode_(mode), 76 lhs_(lhs), 77 rhs_(rhs), 78 constant_rhs_(constant_rhs), 79 specialized_on_rhs_(RhsIsOneWeWantToOptimizeFor(op, constant_rhs)), 80 runtime_operands_type_(BinaryOpIC::DEFAULT), 81 name_(NULL) { } 82 83 GenericBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) 84 : op_(OpBits::decode(key)), 85 mode_(ModeBits::decode(key)), 86 lhs_(LhsRegister(RegisterBits::decode(key))), 87 rhs_(RhsRegister(RegisterBits::decode(key))), 88 constant_rhs_(KnownBitsForMinorKey(KnownIntBits::decode(key))), 89 specialized_on_rhs_(RhsIsOneWeWantToOptimizeFor(op_, constant_rhs_)), 90 runtime_operands_type_(type_info), 91 name_(NULL) { } 92 93 private: 94 Token::Value op_; 95 OverwriteMode mode_; 96 Register lhs_; 97 Register rhs_; 98 int constant_rhs_; 99 bool specialized_on_rhs_; 100 BinaryOpIC::TypeInfo runtime_operands_type_; 101 char* name_; 102 103 static const int kMaxKnownRhs = 0x40000000; 104 static const int kKnownRhsKeyBits = 6; 105 106 // Minor key encoding in 17 bits. 107 class ModeBits: public BitField<OverwriteMode, 0, 2> {}; 108 class OpBits: public BitField<Token::Value, 2, 6> {}; 109 class TypeInfoBits: public BitField<int, 8, 2> {}; 110 class RegisterBits: public BitField<bool, 10, 1> {}; 111 class KnownIntBits: public BitField<int, 11, kKnownRhsKeyBits> {}; 112 113 Major MajorKey() { return GenericBinaryOp; } 114 int MinorKey() { 115 ASSERT((lhs_.is(r0) && rhs_.is(r1)) || 116 (lhs_.is(r1) && rhs_.is(r0))); 117 // Encode the parameters in a unique 18 bit value. 118 return OpBits::encode(op_) 119 | ModeBits::encode(mode_) 120 | KnownIntBits::encode(MinorKeyForKnownInt()) 121 | TypeInfoBits::encode(runtime_operands_type_) 122 | RegisterBits::encode(lhs_.is(r0)); 123 } 124 125 void Generate(MacroAssembler* masm); 126 void HandleNonSmiBitwiseOp(MacroAssembler* masm, 127 Register lhs, 128 Register rhs); 129 void HandleBinaryOpSlowCases(MacroAssembler* masm, 130 Label* not_smi, 131 Register lhs, 132 Register rhs, 133 const Builtins::JavaScript& builtin); 134 void GenerateTypeTransition(MacroAssembler* masm); 135 136 static bool RhsIsOneWeWantToOptimizeFor(Token::Value op, int constant_rhs) { 137 if (constant_rhs == kUnknownIntValue) return false; 138 if (op == Token::DIV) return constant_rhs >= 2 && constant_rhs <= 3; 139 if (op == Token::MOD) { 140 if (constant_rhs <= 1) return false; 141 if (constant_rhs <= 10) return true; 142 if (constant_rhs <= kMaxKnownRhs && IsPowerOf2(constant_rhs)) return true; 143 return false; 144 } 145 return false; 146 } 147 148 int MinorKeyForKnownInt() { 149 if (!specialized_on_rhs_) return 0; 150 if (constant_rhs_ <= 10) return constant_rhs_ + 1; 151 ASSERT(IsPowerOf2(constant_rhs_)); 152 int key = 12; 153 int d = constant_rhs_; 154 while ((d & 1) == 0) { 155 key++; 156 d >>= 1; 157 } 158 ASSERT(key >= 0 && key < (1 << kKnownRhsKeyBits)); 159 return key; 160 } 161 162 int KnownBitsForMinorKey(int key) { 163 if (!key) return 0; 164 if (key <= 11) return key - 1; 165 int d = 1; 166 while (key != 12) { 167 key--; 168 d <<= 1; 169 } 170 return d; 171 } 172 173 Register LhsRegister(bool lhs_is_r0) { 174 return lhs_is_r0 ? r0 : r1; 175 } 176 177 Register RhsRegister(bool lhs_is_r0) { 178 return lhs_is_r0 ? r1 : r0; 179 } 180 181 bool ShouldGenerateSmiCode() { 182 return ((op_ != Token::DIV && op_ != Token::MOD) || specialized_on_rhs_) && 183 runtime_operands_type_ != BinaryOpIC::HEAP_NUMBERS && 184 runtime_operands_type_ != BinaryOpIC::STRINGS; 185 } 186 187 bool ShouldGenerateFPCode() { 188 return runtime_operands_type_ != BinaryOpIC::STRINGS; 189 } 190 191 virtual int GetCodeKind() { return Code::BINARY_OP_IC; } 192 193 virtual InlineCacheState GetICState() { 194 return BinaryOpIC::ToState(runtime_operands_type_); 195 } 196 197 const char* GetName(); 198 199#ifdef DEBUG 200 void Print() { 201 if (!specialized_on_rhs_) { 202 PrintF("GenericBinaryOpStub (%s)\n", Token::String(op_)); 203 } else { 204 PrintF("GenericBinaryOpStub (%s by %d)\n", 205 Token::String(op_), 206 constant_rhs_); 207 } 208 } 209#endif 210}; 211 212 213// Flag that indicates how to generate code for the stub StringAddStub. 214enum StringAddFlags { 215 NO_STRING_ADD_FLAGS = 0, 216 NO_STRING_CHECK_IN_STUB = 1 << 0 // Omit string check in stub. 217}; 218 219 220class StringAddStub: public CodeStub { 221 public: 222 explicit StringAddStub(StringAddFlags flags) { 223 string_check_ = ((flags & NO_STRING_CHECK_IN_STUB) == 0); 224 } 225 226 private: 227 Major MajorKey() { return StringAdd; } 228 int MinorKey() { return string_check_ ? 0 : 1; } 229 230 void Generate(MacroAssembler* masm); 231 232 // Should the stub check whether arguments are strings? 233 bool string_check_; 234}; 235 236 237class SubStringStub: public CodeStub { 238 public: 239 SubStringStub() {} 240 241 private: 242 Major MajorKey() { return SubString; } 243 int MinorKey() { return 0; } 244 245 void Generate(MacroAssembler* masm); 246}; 247 248 249 250class StringCompareStub: public CodeStub { 251 public: 252 StringCompareStub() { } 253 254 // Compare two flat ASCII strings and returns result in r0. 255 // Does not use the stack. 256 static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm, 257 Register left, 258 Register right, 259 Register scratch1, 260 Register scratch2, 261 Register scratch3, 262 Register scratch4); 263 264 private: 265 Major MajorKey() { return StringCompare; } 266 int MinorKey() { return 0; } 267 268 void Generate(MacroAssembler* masm); 269}; 270 271 272// This stub can do a fast mod operation without using fp. 273// It is tail called from the GenericBinaryOpStub and it always 274// returns an answer. It never causes GC so it doesn't need a real frame. 275// 276// The inputs are always positive Smis. This is never called 277// where the denominator is a power of 2. We handle that separately. 278// 279// If we consider the denominator as an odd number multiplied by a power of 2, 280// then: 281// * The exponent (power of 2) is in the shift_distance register. 282// * The odd number is in the odd_number register. It is always in the range 283// of 3 to 25. 284// * The bits from the numerator that are to be copied to the answer (there are 285// shift_distance of them) are in the mask_bits register. 286// * The other bits of the numerator have been shifted down and are in the lhs 287// register. 288class IntegerModStub : public CodeStub { 289 public: 290 IntegerModStub(Register result, 291 Register shift_distance, 292 Register odd_number, 293 Register mask_bits, 294 Register lhs, 295 Register scratch) 296 : result_(result), 297 shift_distance_(shift_distance), 298 odd_number_(odd_number), 299 mask_bits_(mask_bits), 300 lhs_(lhs), 301 scratch_(scratch) { 302 // We don't code these in the minor key, so they should always be the same. 303 // We don't really want to fix that since this stub is rather large and we 304 // don't want many copies of it. 305 ASSERT(shift_distance_.is(r9)); 306 ASSERT(odd_number_.is(r4)); 307 ASSERT(mask_bits_.is(r3)); 308 ASSERT(scratch_.is(r5)); 309 } 310 311 private: 312 Register result_; 313 Register shift_distance_; 314 Register odd_number_; 315 Register mask_bits_; 316 Register lhs_; 317 Register scratch_; 318 319 // Minor key encoding in 16 bits. 320 class ResultRegisterBits: public BitField<int, 0, 4> {}; 321 class LhsRegisterBits: public BitField<int, 4, 4> {}; 322 323 Major MajorKey() { return IntegerMod; } 324 int MinorKey() { 325 // Encode the parameters in a unique 16 bit value. 326 return ResultRegisterBits::encode(result_.code()) 327 | LhsRegisterBits::encode(lhs_.code()); 328 } 329 330 void Generate(MacroAssembler* masm); 331 332 const char* GetName() { return "IntegerModStub"; } 333 334 // Utility functions. 335 void DigitSum(MacroAssembler* masm, 336 Register lhs, 337 int mask, 338 int shift, 339 Label* entry); 340 void DigitSum(MacroAssembler* masm, 341 Register lhs, 342 Register scratch, 343 int mask, 344 int shift1, 345 int shift2, 346 Label* entry); 347 void ModGetInRangeBySubtraction(MacroAssembler* masm, 348 Register lhs, 349 int shift, 350 int rhs); 351 void ModReduce(MacroAssembler* masm, 352 Register lhs, 353 int max, 354 int denominator); 355 void ModAnswer(MacroAssembler* masm, 356 Register result, 357 Register shift_distance, 358 Register mask_bits, 359 Register sum_of_digits); 360 361 362#ifdef DEBUG 363 void Print() { PrintF("IntegerModStub\n"); } 364#endif 365}; 366 367 368// This stub can convert a signed int32 to a heap number (double). It does 369// not work for int32s that are in Smi range! No GC occurs during this stub 370// so you don't have to set up the frame. 371class WriteInt32ToHeapNumberStub : public CodeStub { 372 public: 373 WriteInt32ToHeapNumberStub(Register the_int, 374 Register the_heap_number, 375 Register scratch) 376 : the_int_(the_int), 377 the_heap_number_(the_heap_number), 378 scratch_(scratch) { } 379 380 private: 381 Register the_int_; 382 Register the_heap_number_; 383 Register scratch_; 384 385 // Minor key encoding in 16 bits. 386 class IntRegisterBits: public BitField<int, 0, 4> {}; 387 class HeapNumberRegisterBits: public BitField<int, 4, 4> {}; 388 class ScratchRegisterBits: public BitField<int, 8, 4> {}; 389 390 Major MajorKey() { return WriteInt32ToHeapNumber; } 391 int MinorKey() { 392 // Encode the parameters in a unique 16 bit value. 393 return IntRegisterBits::encode(the_int_.code()) 394 | HeapNumberRegisterBits::encode(the_heap_number_.code()) 395 | ScratchRegisterBits::encode(scratch_.code()); 396 } 397 398 void Generate(MacroAssembler* masm); 399 400 const char* GetName() { return "WriteInt32ToHeapNumberStub"; } 401 402#ifdef DEBUG 403 void Print() { PrintF("WriteInt32ToHeapNumberStub\n"); } 404#endif 405}; 406 407 408class NumberToStringStub: public CodeStub { 409 public: 410 NumberToStringStub() { } 411 412 // Generate code to do a lookup in the number string cache. If the number in 413 // the register object is found in the cache the generated code falls through 414 // with the result in the result register. The object and the result register 415 // can be the same. If the number is not found in the cache the code jumps to 416 // the label not_found with only the content of register object unchanged. 417 static void GenerateLookupNumberStringCache(MacroAssembler* masm, 418 Register object, 419 Register result, 420 Register scratch1, 421 Register scratch2, 422 Register scratch3, 423 bool object_is_smi, 424 Label* not_found); 425 426 private: 427 Major MajorKey() { return NumberToString; } 428 int MinorKey() { return 0; } 429 430 void Generate(MacroAssembler* masm); 431 432 const char* GetName() { return "NumberToStringStub"; } 433}; 434 435 436class RecordWriteStub : public CodeStub { 437 public: 438 RecordWriteStub(Register object, Register offset, Register scratch) 439 : object_(object), offset_(offset), scratch_(scratch) { } 440 441 void Generate(MacroAssembler* masm); 442 443 private: 444 Register object_; 445 Register offset_; 446 Register scratch_; 447 448 // Minor key encoding in 12 bits. 4 bits for each of the three 449 // registers (object, offset and scratch) OOOOAAAASSSS. 450 class ScratchBits: public BitField<uint32_t, 0, 4> {}; 451 class OffsetBits: public BitField<uint32_t, 4, 4> {}; 452 class ObjectBits: public BitField<uint32_t, 8, 4> {}; 453 454 Major MajorKey() { return RecordWrite; } 455 456 int MinorKey() { 457 // Encode the registers. 458 return ObjectBits::encode(object_.code()) | 459 OffsetBits::encode(offset_.code()) | 460 ScratchBits::encode(scratch_.code()); 461 } 462 463#ifdef DEBUG 464 void Print() { 465 PrintF("RecordWriteStub (object reg %d), (offset reg %d)," 466 " (scratch reg %d)\n", 467 object_.code(), offset_.code(), scratch_.code()); 468 } 469#endif 470}; 471 472 473// Enter C code from generated RegExp code in a way that allows 474// the C code to fix the return address in case of a GC. 475// Currently only needed on ARM. 476class RegExpCEntryStub: public CodeStub { 477 public: 478 RegExpCEntryStub() {} 479 virtual ~RegExpCEntryStub() {} 480 void Generate(MacroAssembler* masm); 481 482 private: 483 Major MajorKey() { return RegExpCEntry; } 484 int MinorKey() { return 0; } 485 const char* GetName() { return "RegExpCEntryStub"; } 486}; 487 488 489} } // namespace v8::internal 490 491#endif // V8_ARM_CODE_STUBS_ARM_H_ 492