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_MIPS_CODE_STUBS_ARM_H_ |
| 29 #define V8_MIPS_CODE_STUBS_ARM_H_ |
| 30 |
| 31 #include "ic-inl.h" |
| 32 |
| 33 |
| 34 namespace v8 { |
| 35 namespace internal { |
| 36 |
| 37 |
| 38 // Compute a transcendental math function natively, or call the |
| 39 // TranscendentalCache runtime function. |
| 40 class TranscendentalCacheStub: public CodeStub { |
| 41 public: |
| 42 explicit TranscendentalCacheStub(TranscendentalCache::Type type) |
| 43 : type_(type) {} |
| 44 void Generate(MacroAssembler* masm); |
| 45 private: |
| 46 TranscendentalCache::Type type_; |
| 47 Major MajorKey() { return TranscendentalCache; } |
| 48 int MinorKey() { return type_; } |
| 49 Runtime::FunctionId RuntimeFunction(); |
| 50 }; |
| 51 |
| 52 |
| 53 class ToBooleanStub: public CodeStub { |
| 54 public: |
| 55 explicit ToBooleanStub(Register tos) : tos_(tos) { } |
| 56 |
| 57 void Generate(MacroAssembler* masm); |
| 58 |
| 59 private: |
| 60 Register tos_; |
| 61 Major MajorKey() { return ToBoolean; } |
| 62 int MinorKey() { return tos_.code(); } |
| 63 }; |
| 64 |
| 65 |
| 66 class GenericBinaryOpStub : public CodeStub { |
| 67 public: |
| 68 static const int kUnknownIntValue = -1; |
| 69 |
| 70 GenericBinaryOpStub(Token::Value op, |
| 71 OverwriteMode mode, |
| 72 Register lhs, |
| 73 Register rhs, |
| 74 int constant_rhs = kUnknownIntValue) |
| 75 : op_(op), |
| 76 mode_(mode), |
| 77 lhs_(lhs), |
| 78 rhs_(rhs), |
| 79 constant_rhs_(constant_rhs), |
| 80 specialized_on_rhs_(RhsIsOneWeWantToOptimizeFor(op, constant_rhs)), |
| 81 runtime_operands_type_(BinaryOpIC::UNINIT_OR_SMI), |
| 82 name_(NULL) { } |
| 83 |
| 84 GenericBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) |
| 85 : op_(OpBits::decode(key)), |
| 86 mode_(ModeBits::decode(key)), |
| 87 lhs_(LhsRegister(RegisterBits::decode(key))), |
| 88 rhs_(RhsRegister(RegisterBits::decode(key))), |
| 89 constant_rhs_(KnownBitsForMinorKey(KnownIntBits::decode(key))), |
| 90 specialized_on_rhs_(RhsIsOneWeWantToOptimizeFor(op_, constant_rhs_)), |
| 91 runtime_operands_type_(type_info), |
| 92 name_(NULL) { } |
| 93 |
| 94 private: |
| 95 Token::Value op_; |
| 96 OverwriteMode mode_; |
| 97 Register lhs_; |
| 98 Register rhs_; |
| 99 int constant_rhs_; |
| 100 bool specialized_on_rhs_; |
| 101 BinaryOpIC::TypeInfo runtime_operands_type_; |
| 102 char* name_; |
| 103 |
| 104 static const int kMaxKnownRhs = 0x40000000; |
| 105 static const int kKnownRhsKeyBits = 6; |
| 106 |
| 107 // Minor key encoding in 16 bits. |
| 108 class ModeBits: public BitField<OverwriteMode, 0, 2> {}; |
| 109 class OpBits: public BitField<Token::Value, 2, 6> {}; |
| 110 class TypeInfoBits: public BitField<int, 8, 3> {}; |
| 111 class RegisterBits: public BitField<bool, 11, 1> {}; |
| 112 class KnownIntBits: public BitField<int, 12, kKnownRhsKeyBits> {}; |
| 113 |
| 114 Major MajorKey() { return GenericBinaryOp; } |
| 115 int MinorKey() { |
| 116 ASSERT((lhs_.is(a0) && rhs_.is(a1)) || |
| 117 (lhs_.is(a1) && rhs_.is(a0))); |
| 118 // Encode the parameters in a unique 16 bit value. |
| 119 return OpBits::encode(op_) |
| 120 | ModeBits::encode(mode_) |
| 121 | KnownIntBits::encode(MinorKeyForKnownInt()) |
| 122 | TypeInfoBits::encode(runtime_operands_type_) |
| 123 | RegisterBits::encode(lhs_.is(a0)); |
| 124 } |
| 125 |
| 126 void Generate(MacroAssembler* masm); |
| 127 void HandleNonSmiBitwiseOp(MacroAssembler* masm, |
| 128 Register lhs, |
| 129 Register rhs); |
| 130 void HandleBinaryOpSlowCases(MacroAssembler* masm, |
| 131 Label* not_smi, |
| 132 Register lhs, |
| 133 Register rhs, |
| 134 const Builtins::JavaScript& builtin); |
| 135 void GenerateTypeTransition(MacroAssembler* masm); |
| 136 |
| 137 static bool RhsIsOneWeWantToOptimizeFor(Token::Value op, int constant_rhs) { |
| 138 if (constant_rhs == kUnknownIntValue) return false; |
| 139 if (op == Token::DIV) return constant_rhs >= 2 && constant_rhs <= 3; |
| 140 if (op == Token::MOD) { |
| 141 if (constant_rhs <= 1) return false; |
| 142 if (constant_rhs <= 10) return true; |
| 143 if (constant_rhs <= kMaxKnownRhs && IsPowerOf2(constant_rhs)) return true; |
| 144 return false; |
| 145 } |
| 146 return false; |
| 147 } |
| 148 |
| 149 int MinorKeyForKnownInt() { |
| 150 if (!specialized_on_rhs_) return 0; |
| 151 if (constant_rhs_ <= 10) return constant_rhs_ + 1; |
| 152 ASSERT(IsPowerOf2(constant_rhs_)); |
| 153 int key = 12; |
| 154 int d = constant_rhs_; |
| 155 while ((d & 1) == 0) { |
| 156 key++; |
| 157 d >>= 1; |
| 158 } |
| 159 ASSERT(key >= 0 && key < (1 << kKnownRhsKeyBits)); |
| 160 return key; |
| 161 } |
| 162 |
| 163 int KnownBitsForMinorKey(int key) { |
| 164 if (!key) return 0; |
| 165 if (key <= 11) return key - 1; |
| 166 int d = 1; |
| 167 while (key != 12) { |
| 168 key--; |
| 169 d <<= 1; |
| 170 } |
| 171 return d; |
| 172 } |
| 173 |
| 174 Register LhsRegister(bool lhs_is_a0) { |
| 175 return lhs_is_a0 ? a0 : a1; |
| 176 } |
| 177 |
| 178 Register RhsRegister(bool lhs_is_a0) { |
| 179 return lhs_is_a0 ? a1 : a0; |
| 180 } |
| 181 |
| 182 bool HasSmiSmiFastPath() { |
| 183 return op_ != Token::DIV; |
| 184 } |
| 185 |
| 186 bool ShouldGenerateSmiCode() { |
| 187 return ((op_ != Token::DIV && op_ != Token::MOD) || specialized_on_rhs_) && |
| 188 runtime_operands_type_ != BinaryOpIC::HEAP_NUMBERS && |
| 189 runtime_operands_type_ != BinaryOpIC::STRINGS; |
| 190 } |
| 191 |
| 192 bool ShouldGenerateFPCode() { |
| 193 return runtime_operands_type_ != BinaryOpIC::STRINGS; |
| 194 } |
| 195 |
| 196 virtual int GetCodeKind() { return Code::BINARY_OP_IC; } |
| 197 |
| 198 virtual InlineCacheState GetICState() { |
| 199 return BinaryOpIC::ToState(runtime_operands_type_); |
| 200 } |
| 201 |
| 202 const char* GetName(); |
| 203 |
| 204 virtual void FinishCode(Code* code) { |
| 205 code->set_binary_op_type(runtime_operands_type_); |
| 206 } |
| 207 |
| 208 #ifdef DEBUG |
| 209 void Print() { |
| 210 if (!specialized_on_rhs_) { |
| 211 PrintF("GenericBinaryOpStub (%s)\n", Token::String(op_)); |
| 212 } else { |
| 213 PrintF("GenericBinaryOpStub (%s by %d)\n", |
| 214 Token::String(op_), |
| 215 constant_rhs_); |
| 216 } |
| 217 } |
| 218 #endif |
| 219 }; |
| 220 |
| 221 class TypeRecordingBinaryOpStub: public CodeStub { |
| 222 public: |
| 223 TypeRecordingBinaryOpStub(Token::Value op, OverwriteMode mode) |
| 224 : op_(op), |
| 225 mode_(mode), |
| 226 operands_type_(TRBinaryOpIC::UNINITIALIZED), |
| 227 result_type_(TRBinaryOpIC::UNINITIALIZED), |
| 228 name_(NULL) { |
| 229 UNIMPLEMENTED_MIPS(); |
| 230 } |
| 231 |
| 232 TypeRecordingBinaryOpStub( |
| 233 int key, |
| 234 TRBinaryOpIC::TypeInfo operands_type, |
| 235 TRBinaryOpIC::TypeInfo result_type = TRBinaryOpIC::UNINITIALIZED) |
| 236 : op_(OpBits::decode(key)), |
| 237 mode_(ModeBits::decode(key)), |
| 238 use_fpu_(FPUBits::decode(key)), |
| 239 operands_type_(operands_type), |
| 240 result_type_(result_type), |
| 241 name_(NULL) { } |
| 242 |
| 243 private: |
| 244 enum SmiCodeGenerateHeapNumberResults { |
| 245 ALLOW_HEAPNUMBER_RESULTS, |
| 246 NO_HEAPNUMBER_RESULTS |
| 247 }; |
| 248 |
| 249 Token::Value op_; |
| 250 OverwriteMode mode_; |
| 251 bool use_fpu_; |
| 252 |
| 253 // Operand type information determined at runtime. |
| 254 TRBinaryOpIC::TypeInfo operands_type_; |
| 255 TRBinaryOpIC::TypeInfo result_type_; |
| 256 |
| 257 char* name_; |
| 258 |
| 259 const char* GetName(); |
| 260 |
| 261 #ifdef DEBUG |
| 262 void Print() { |
| 263 PrintF("TypeRecordingBinaryOpStub %d (op %s), " |
| 264 "(mode %d, runtime_type_info %s)\n", |
| 265 MinorKey(), |
| 266 Token::String(op_), |
| 267 static_cast<int>(mode_), |
| 268 TRBinaryOpIC::GetName(operands_type_)); |
| 269 } |
| 270 #endif |
| 271 |
| 272 // Minor key encoding in 16 bits RRRTTTVOOOOOOOMM. |
| 273 class ModeBits: public BitField<OverwriteMode, 0, 2> {}; |
| 274 class OpBits: public BitField<Token::Value, 2, 7> {}; |
| 275 class FPUBits: public BitField<bool, 9, 1> {}; |
| 276 class OperandTypeInfoBits: public BitField<TRBinaryOpIC::TypeInfo, 10, 3> {}; |
| 277 class ResultTypeInfoBits: public BitField<TRBinaryOpIC::TypeInfo, 13, 3> {}; |
| 278 |
| 279 Major MajorKey() { return TypeRecordingBinaryOp; } |
| 280 int MinorKey() { |
| 281 return OpBits::encode(op_) |
| 282 | ModeBits::encode(mode_) |
| 283 | FPUBits::encode(use_fpu_) |
| 284 | OperandTypeInfoBits::encode(operands_type_) |
| 285 | ResultTypeInfoBits::encode(result_type_); |
| 286 } |
| 287 |
| 288 void Generate(MacroAssembler* masm); |
| 289 void GenerateGeneric(MacroAssembler* masm); |
| 290 void GenerateSmiSmiOperation(MacroAssembler* masm); |
| 291 void GenerateFPOperation(MacroAssembler* masm, |
| 292 bool smi_operands, |
| 293 Label* not_numbers, |
| 294 Label* gc_required); |
| 295 void GenerateSmiCode(MacroAssembler* masm, |
| 296 Label* gc_required, |
| 297 SmiCodeGenerateHeapNumberResults heapnumber_results); |
| 298 void GenerateLoadArguments(MacroAssembler* masm); |
| 299 void GenerateReturn(MacroAssembler* masm); |
| 300 void GenerateUninitializedStub(MacroAssembler* masm); |
| 301 void GenerateSmiStub(MacroAssembler* masm); |
| 302 void GenerateInt32Stub(MacroAssembler* masm); |
| 303 void GenerateHeapNumberStub(MacroAssembler* masm); |
| 304 void GenerateStringStub(MacroAssembler* masm); |
| 305 void GenerateGenericStub(MacroAssembler* masm); |
| 306 void GenerateAddStrings(MacroAssembler* masm); |
| 307 void GenerateCallRuntime(MacroAssembler* masm); |
| 308 |
| 309 void GenerateHeapResultAllocation(MacroAssembler* masm, |
| 310 Register result, |
| 311 Register heap_number_map, |
| 312 Register scratch1, |
| 313 Register scratch2, |
| 314 Label* gc_required); |
| 315 void GenerateRegisterArgsPush(MacroAssembler* masm); |
| 316 void GenerateTypeTransition(MacroAssembler* masm); |
| 317 void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm); |
| 318 |
| 319 virtual int GetCodeKind() { return Code::TYPE_RECORDING_BINARY_OP_IC; } |
| 320 |
| 321 virtual InlineCacheState GetICState() { |
| 322 return TRBinaryOpIC::ToState(operands_type_); |
| 323 } |
| 324 |
| 325 virtual void FinishCode(Code* code) { |
| 326 code->set_type_recording_binary_op_type(operands_type_); |
| 327 code->set_type_recording_binary_op_result_type(result_type_); |
| 328 } |
| 329 |
| 330 friend class CodeGenerator; |
| 331 }; |
| 332 |
| 333 |
| 334 // Flag that indicates how to generate code for the stub StringAddStub. |
| 335 enum StringAddFlags { |
| 336 NO_STRING_ADD_FLAGS = 0, |
| 337 NO_STRING_CHECK_IN_STUB = 1 << 0 // Omit string check in stub. |
| 338 }; |
| 339 |
| 340 |
| 341 class StringAddStub: public CodeStub { |
| 342 public: |
| 343 explicit StringAddStub(StringAddFlags flags) { |
| 344 string_check_ = ((flags & NO_STRING_CHECK_IN_STUB) == 0); |
| 345 } |
| 346 |
| 347 private: |
| 348 Major MajorKey() { return StringAdd; } |
| 349 int MinorKey() { return string_check_ ? 0 : 1; } |
| 350 |
| 351 void Generate(MacroAssembler* masm); |
| 352 |
| 353 // Should the stub check whether arguments are strings? |
| 354 bool string_check_; |
| 355 }; |
| 356 |
| 357 |
| 358 class SubStringStub: public CodeStub { |
| 359 public: |
| 360 SubStringStub() {} |
| 361 |
| 362 private: |
| 363 Major MajorKey() { return SubString; } |
| 364 int MinorKey() { return 0; } |
| 365 |
| 366 void Generate(MacroAssembler* masm); |
| 367 }; |
| 368 |
| 369 |
| 370 class StringCompareStub: public CodeStub { |
| 371 public: |
| 372 StringCompareStub() { } |
| 373 |
| 374 // Compare two flat ASCII strings and returns result in v0. |
| 375 // Does not use the stack. |
| 376 static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm, |
| 377 Register left, |
| 378 Register right, |
| 379 Register scratch1, |
| 380 Register scratch2, |
| 381 Register scratch3, |
| 382 Register scratch4); |
| 383 |
| 384 private: |
| 385 Major MajorKey() { return StringCompare; } |
| 386 int MinorKey() { return 0; } |
| 387 |
| 388 void Generate(MacroAssembler* masm); |
| 389 }; |
| 390 |
| 391 |
| 392 // This stub can convert a signed int32 to a heap number (double). It does |
| 393 // not work for int32s that are in Smi range! No GC occurs during this stub |
| 394 // so you don't have to set up the frame. |
| 395 class WriteInt32ToHeapNumberStub : public CodeStub { |
| 396 public: |
| 397 WriteInt32ToHeapNumberStub(Register the_int, |
| 398 Register the_heap_number, |
| 399 Register scratch, |
| 400 Register scratch2) |
| 401 : the_int_(the_int), |
| 402 the_heap_number_(the_heap_number), |
| 403 scratch_(scratch), |
| 404 sign_(scratch2) { } |
| 405 |
| 406 private: |
| 407 Register the_int_; |
| 408 Register the_heap_number_; |
| 409 Register scratch_; |
| 410 Register sign_; |
| 411 |
| 412 // Minor key encoding in 16 bits. |
| 413 class IntRegisterBits: public BitField<int, 0, 4> {}; |
| 414 class HeapNumberRegisterBits: public BitField<int, 4, 4> {}; |
| 415 class ScratchRegisterBits: public BitField<int, 8, 4> {}; |
| 416 |
| 417 Major MajorKey() { return WriteInt32ToHeapNumber; } |
| 418 int MinorKey() { |
| 419 // Encode the parameters in a unique 16 bit value. |
| 420 return IntRegisterBits::encode(the_int_.code()) |
| 421 | HeapNumberRegisterBits::encode(the_heap_number_.code()) |
| 422 | ScratchRegisterBits::encode(scratch_.code()); |
| 423 } |
| 424 |
| 425 void Generate(MacroAssembler* masm); |
| 426 |
| 427 const char* GetName() { return "WriteInt32ToHeapNumberStub"; } |
| 428 |
| 429 #ifdef DEBUG |
| 430 void Print() { PrintF("WriteInt32ToHeapNumberStub\n"); } |
| 431 #endif |
| 432 }; |
| 433 |
| 434 |
| 435 class NumberToStringStub: public CodeStub { |
| 436 public: |
| 437 NumberToStringStub() { } |
| 438 |
| 439 // Generate code to do a lookup in the number string cache. If the number in |
| 440 // the register object is found in the cache the generated code falls through |
| 441 // with the result in the result register. The object and the result register |
| 442 // can be the same. If the number is not found in the cache the code jumps to |
| 443 // the label not_found with only the content of register object unchanged. |
| 444 static void GenerateLookupNumberStringCache(MacroAssembler* masm, |
| 445 Register object, |
| 446 Register result, |
| 447 Register scratch1, |
| 448 Register scratch2, |
| 449 Register scratch3, |
| 450 bool object_is_smi, |
| 451 Label* not_found); |
| 452 |
| 453 private: |
| 454 Major MajorKey() { return NumberToString; } |
| 455 int MinorKey() { return 0; } |
| 456 |
| 457 void Generate(MacroAssembler* masm); |
| 458 |
| 459 const char* GetName() { return "NumberToStringStub"; } |
| 460 |
| 461 #ifdef DEBUG |
| 462 void Print() { |
| 463 PrintF("NumberToStringStub\n"); |
| 464 } |
| 465 #endif |
| 466 }; |
| 467 |
| 468 |
| 469 // Enter C code from generated RegExp code in a way that allows |
| 470 // the C code to fix the return address in case of a GC. |
| 471 // Currently only needed on ARM and MIPS. |
| 472 class RegExpCEntryStub: public CodeStub { |
| 473 public: |
| 474 RegExpCEntryStub() {} |
| 475 virtual ~RegExpCEntryStub() {} |
| 476 void Generate(MacroAssembler* masm); |
| 477 |
| 478 private: |
| 479 Major MajorKey() { return RegExpCEntry; } |
| 480 int MinorKey() { return 0; } |
| 481 |
| 482 bool NeedsImmovableCode() { return true; } |
| 483 |
| 484 const char* GetName() { return "RegExpCEntryStub"; } |
| 485 }; |
| 486 |
| 487 |
| 488 // Generate code the to load an element from a pixel array. The receiver is |
| 489 // assumed to not be a smi and to have elements, the caller must guarantee this |
| 490 // precondition. If the receiver does not have elements that are pixel arrays, |
| 491 // the generated code jumps to not_pixel_array. If key is not a smi, then the |
| 492 // generated code branches to key_not_smi. Callers can specify NULL for |
| 493 // key_not_smi to signal that a smi check has already been performed on key so |
| 494 // that the smi check is not generated . If key is not a valid index within the |
| 495 // bounds of the pixel array, the generated code jumps to out_of_range. |
| 496 void GenerateFastPixelArrayLoad(MacroAssembler* masm, |
| 497 Register receiver, |
| 498 Register key, |
| 499 Register elements_map, |
| 500 Register elements, |
| 501 Register scratch1, |
| 502 Register scratch2, |
| 503 Register result, |
| 504 Label* not_pixel_array, |
| 505 Label* key_not_smi, |
| 506 Label* out_of_range); |
| 507 |
| 508 |
| 509 } } // namespace v8::internal |
| 510 |
| 511 #endif // V8_MIPS_CODE_STUBS_ARM_H_ |
OLD | NEW |