OLD | NEW |
(Empty) | |
| 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 "codegen-inl.h" |
| 32 #include "ic-inl.h" |
| 33 #include "ast.h" |
| 34 |
| 35 namespace v8 { |
| 36 namespace internal { |
| 37 |
| 38 |
| 39 // Compute a transcendental math function natively, or call the |
| 40 // TranscendentalCache runtime function. |
| 41 class TranscendentalCacheStub: public CodeStub { |
| 42 public: |
| 43 explicit TranscendentalCacheStub(TranscendentalCache::Type type) |
| 44 : type_(type) {} |
| 45 void Generate(MacroAssembler* masm); |
| 46 private: |
| 47 TranscendentalCache::Type type_; |
| 48 Major MajorKey() { return TranscendentalCache; } |
| 49 int MinorKey() { return type_; } |
| 50 Runtime::FunctionId RuntimeFunction(); |
| 51 }; |
| 52 |
| 53 |
| 54 class ToBooleanStub: public CodeStub { |
| 55 public: |
| 56 explicit ToBooleanStub(Register tos) : tos_(tos) { } |
| 57 |
| 58 void Generate(MacroAssembler* masm); |
| 59 |
| 60 private: |
| 61 Register tos_; |
| 62 Major MajorKey() { return ToBoolean; } |
| 63 int MinorKey() { return tos_.code(); } |
| 64 }; |
| 65 |
| 66 |
| 67 class GenericBinaryOpStub : public CodeStub { |
| 68 public: |
| 69 GenericBinaryOpStub(Token::Value op, |
| 70 OverwriteMode mode, |
| 71 Register lhs, |
| 72 Register rhs, |
| 73 int constant_rhs = CodeGenerator::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 == CodeGenerator::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. |
| 214 enum StringAddFlags { |
| 215 NO_STRING_ADD_FLAGS = 0, |
| 216 NO_STRING_CHECK_IN_STUB = 1 << 0 // Omit string check in stub. |
| 217 }; |
| 218 |
| 219 |
| 220 class 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 |
| 237 class 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 |
| 250 class 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. |
| 288 class 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. |
| 371 class 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 |
| 408 class 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 |
| 436 class 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 } } // namespace v8::internal |
| 474 |
| 475 #endif // V8_ARM_CODE_STUBS_ARM_H_ |
OLD | NEW |