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: TranscendentalCacheStub(TranscendentalCache::Type type)42 explicit TranscendentalCacheStub(TranscendentalCache::Type type) 43 : type_(type) {} 44 void Generate(MacroAssembler* masm); 45 private: 46 TranscendentalCache::Type type_; MajorKey()47 Major MajorKey() { return TranscendentalCache; } MinorKey()48 int MinorKey() { return type_; } 49 Runtime::FunctionId RuntimeFunction(); 50 }; 51 52 53 class ToBooleanStub: public CodeStub { 54 public: ToBooleanStub(Register tos)55 explicit ToBooleanStub(Register tos) : tos_(tos) { } 56 57 void Generate(MacroAssembler* masm); 58 59 private: 60 Register tos_; MajorKey()61 Major MajorKey() { return ToBoolean; } MinorKey()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) op_(op)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 GenericBinaryOpStub(int key,BinaryOpIC::TypeInfo type_info)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 MajorKey()114 Major MajorKey() { return GenericBinaryOp; } MinorKey()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 RhsIsOneWeWantToOptimizeFor(Token::Value op,int constant_rhs)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 MinorKeyForKnownInt()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 KnownBitsForMinorKey(int key)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 LhsRegister(bool lhs_is_a0)174 Register LhsRegister(bool lhs_is_a0) { 175 return lhs_is_a0 ? a0 : a1; 176 } 177 RhsRegister(bool lhs_is_a0)178 Register RhsRegister(bool lhs_is_a0) { 179 return lhs_is_a0 ? a1 : a0; 180 } 181 HasSmiSmiFastPath()182 bool HasSmiSmiFastPath() { 183 return op_ != Token::DIV; 184 } 185 ShouldGenerateSmiCode()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 ShouldGenerateFPCode()192 bool ShouldGenerateFPCode() { 193 return runtime_operands_type_ != BinaryOpIC::STRINGS; 194 } 195 GetCodeKind()196 virtual int GetCodeKind() { return Code::BINARY_OP_IC; } 197 GetICState()198 virtual InlineCacheState GetICState() { 199 return BinaryOpIC::ToState(runtime_operands_type_); 200 } 201 202 const char* GetName(); 203 FinishCode(Code * code)204 virtual void FinishCode(Code* code) { 205 code->set_binary_op_type(runtime_operands_type_); 206 } 207 208 #ifdef DEBUG Print()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: TypeRecordingBinaryOpStub(Token::Value op,OverwriteMode mode)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) op_(OpBits::decode (key))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 Print()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 MajorKey()279 Major MajorKey() { return TypeRecordingBinaryOp; } MinorKey()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 GetCodeKind()319 virtual int GetCodeKind() { return Code::TYPE_RECORDING_BINARY_OP_IC; } 320 GetICState()321 virtual InlineCacheState GetICState() { 322 return TRBinaryOpIC::ToState(operands_type_); 323 } 324 FinishCode(Code * code)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: StringAddStub(StringAddFlags flags)343 explicit StringAddStub(StringAddFlags flags) { 344 string_check_ = ((flags & NO_STRING_CHECK_IN_STUB) == 0); 345 } 346 347 private: MajorKey()348 Major MajorKey() { return StringAdd; } MinorKey()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: SubStringStub()360 SubStringStub() {} 361 362 private: MajorKey()363 Major MajorKey() { return SubString; } MinorKey()364 int MinorKey() { return 0; } 365 366 void Generate(MacroAssembler* masm); 367 }; 368 369 370 class StringCompareStub: public CodeStub { 371 public: StringCompareStub()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: MajorKey()385 Major MajorKey() { return StringCompare; } MinorKey()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: WriteInt32ToHeapNumberStub(Register the_int,Register the_heap_number,Register scratch,Register scratch2)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 MajorKey()417 Major MajorKey() { return WriteInt32ToHeapNumber; } MinorKey()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 GetName()427 const char* GetName() { return "WriteInt32ToHeapNumberStub"; } 428 429 #ifdef DEBUG Print()430 void Print() { PrintF("WriteInt32ToHeapNumberStub\n"); } 431 #endif 432 }; 433 434 435 class NumberToStringStub: public CodeStub { 436 public: NumberToStringStub()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: MajorKey()454 Major MajorKey() { return NumberToString; } MinorKey()455 int MinorKey() { return 0; } 456 457 void Generate(MacroAssembler* masm); 458 GetName()459 const char* GetName() { return "NumberToStringStub"; } 460 461 #ifdef DEBUG Print()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: RegExpCEntryStub()474 RegExpCEntryStub() {} ~RegExpCEntryStub()475 virtual ~RegExpCEntryStub() {} 476 void Generate(MacroAssembler* masm); 477 478 private: MajorKey()479 Major MajorKey() { return RegExpCEntry; } MinorKey()480 int MinorKey() { return 0; } 481 NeedsImmovableCode()482 bool NeedsImmovableCode() { return true; } 483 GetName()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_ 512