| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| 11 // with the distribution. | 11 // with the distribution. |
| (...skipping 20 matching lines...) Expand all Loading... |
| 32 | 32 |
| 33 | 33 |
| 34 namespace v8 { | 34 namespace v8 { |
| 35 namespace internal { | 35 namespace internal { |
| 36 | 36 |
| 37 | 37 |
| 38 // Compute a transcendental math function natively, or call the | 38 // Compute a transcendental math function natively, or call the |
| 39 // TranscendentalCache runtime function. | 39 // TranscendentalCache runtime function. |
| 40 class TranscendentalCacheStub: public CodeStub { | 40 class TranscendentalCacheStub: public CodeStub { |
| 41 public: | 41 public: |
| 42 explicit TranscendentalCacheStub(TranscendentalCache::Type type) | 42 enum ArgumentType { |
| 43 : type_(type) {} | 43 TAGGED = 0 << TranscendentalCache::kTranscendentalTypeBits, |
| 44 UNTAGGED = 1 << TranscendentalCache::kTranscendentalTypeBits |
| 45 }; |
| 46 |
| 47 TranscendentalCacheStub(TranscendentalCache::Type type, |
| 48 ArgumentType argument_type) |
| 49 : type_(type), argument_type_(argument_type) { } |
| 44 void Generate(MacroAssembler* masm); | 50 void Generate(MacroAssembler* masm); |
| 45 private: | 51 private: |
| 46 TranscendentalCache::Type type_; | 52 TranscendentalCache::Type type_; |
| 53 ArgumentType argument_type_; |
| 54 void GenerateCallCFunction(MacroAssembler* masm, Register scratch); |
| 55 |
| 47 Major MajorKey() { return TranscendentalCache; } | 56 Major MajorKey() { return TranscendentalCache; } |
| 48 int MinorKey() { return type_; } | 57 int MinorKey() { return type_ | argument_type_; } |
| 49 Runtime::FunctionId RuntimeFunction(); | 58 Runtime::FunctionId RuntimeFunction(); |
| 50 }; | 59 }; |
| 51 | 60 |
| 52 | 61 |
| 53 class ToBooleanStub: public CodeStub { | 62 class ToBooleanStub: public CodeStub { |
| 54 public: | 63 public: |
| 55 explicit ToBooleanStub(Register tos) : tos_(tos) { } | 64 explicit ToBooleanStub(Register tos) : tos_(tos) { } |
| 56 | 65 |
| 57 void Generate(MacroAssembler* masm); | 66 void Generate(MacroAssembler* masm); |
| 58 | 67 |
| 59 private: | 68 private: |
| 60 Register tos_; | 69 Register tos_; |
| 61 Major MajorKey() { return ToBoolean; } | 70 Major MajorKey() { return ToBoolean; } |
| 62 int MinorKey() { return tos_.code(); } | 71 int MinorKey() { return tos_.code(); } |
| 63 }; | 72 }; |
| 64 | 73 |
| 65 | 74 |
| 66 class GenericBinaryOpStub : public CodeStub { | 75 class TypeRecordingUnaryOpStub: public CodeStub { |
| 67 public: | 76 public: |
| 68 static const int kUnknownIntValue = -1; | 77 TypeRecordingUnaryOpStub(Token::Value op, UnaryOverwriteMode mode) |
| 69 | |
| 70 GenericBinaryOpStub(Token::Value op, | |
| 71 OverwriteMode mode, | |
| 72 Register lhs, | |
| 73 Register rhs, | |
| 74 int constant_rhs = kUnknownIntValue) | |
| 75 : op_(op), | 78 : op_(op), |
| 76 mode_(mode), | 79 mode_(mode), |
| 77 lhs_(lhs), | 80 operand_type_(TRUnaryOpIC::UNINITIALIZED), |
| 78 rhs_(rhs), | 81 name_(NULL) { |
| 79 constant_rhs_(constant_rhs), | 82 } |
| 80 specialized_on_rhs_(RhsIsOneWeWantToOptimizeFor(op, constant_rhs)), | |
| 81 runtime_operands_type_(BinaryOpIC::UNINIT_OR_SMI), | |
| 82 name_(NULL) { } | |
| 83 | 83 |
| 84 GenericBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) | 84 TypeRecordingUnaryOpStub( |
| 85 int key, |
| 86 TRUnaryOpIC::TypeInfo operand_type) |
| 85 : op_(OpBits::decode(key)), | 87 : op_(OpBits::decode(key)), |
| 86 mode_(ModeBits::decode(key)), | 88 mode_(ModeBits::decode(key)), |
| 87 lhs_(LhsRegister(RegisterBits::decode(key))), | 89 operand_type_(operand_type), |
| 88 rhs_(RhsRegister(RegisterBits::decode(key))), | 90 name_(NULL) { |
| 89 constant_rhs_(KnownBitsForMinorKey(KnownIntBits::decode(key))), | 91 } |
| 90 specialized_on_rhs_(RhsIsOneWeWantToOptimizeFor(op_, constant_rhs_)), | |
| 91 runtime_operands_type_(type_info), | |
| 92 name_(NULL) { } | |
| 93 | 92 |
| 94 private: | 93 private: |
| 95 Token::Value op_; | 94 Token::Value op_; |
| 96 OverwriteMode mode_; | 95 UnaryOverwriteMode mode_; |
| 97 Register lhs_; | 96 |
| 98 Register rhs_; | 97 // Operand type information determined at runtime. |
| 99 int constant_rhs_; | 98 TRUnaryOpIC::TypeInfo operand_type_; |
| 100 bool specialized_on_rhs_; | 99 |
| 101 BinaryOpIC::TypeInfo runtime_operands_type_; | |
| 102 char* name_; | 100 char* name_; |
| 103 | 101 |
| 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(); | 102 const char* GetName(); |
| 203 | 103 |
| 204 virtual void FinishCode(Code* code) { | 104 #ifdef DEBUG |
| 205 code->set_binary_op_type(runtime_operands_type_); | 105 void Print() { |
| 106 PrintF("TypeRecordingUnaryOpStub %d (op %s), " |
| 107 "(mode %d, runtime_type_info %s)\n", |
| 108 MinorKey(), |
| 109 Token::String(op_), |
| 110 static_cast<int>(mode_), |
| 111 TRUnaryOpIC::GetName(operand_type_)); |
| 112 } |
| 113 #endif |
| 114 |
| 115 class ModeBits: public BitField<UnaryOverwriteMode, 0, 1> {}; |
| 116 class OpBits: public BitField<Token::Value, 1, 7> {}; |
| 117 class OperandTypeInfoBits: public BitField<TRUnaryOpIC::TypeInfo, 8, 3> {}; |
| 118 |
| 119 Major MajorKey() { return TypeRecordingUnaryOp; } |
| 120 int MinorKey() { |
| 121 return ModeBits::encode(mode_) |
| 122 | OpBits::encode(op_) |
| 123 | OperandTypeInfoBits::encode(operand_type_); |
| 206 } | 124 } |
| 207 | 125 |
| 208 #ifdef DEBUG | 126 // Note: A lot of the helper functions below will vanish when we use virtual |
| 209 void Print() { | 127 // function instead of switch more often. |
| 210 if (!specialized_on_rhs_) { | 128 void Generate(MacroAssembler* masm); |
| 211 PrintF("GenericBinaryOpStub (%s)\n", Token::String(op_)); | 129 |
| 212 } else { | 130 void GenerateTypeTransition(MacroAssembler* masm); |
| 213 PrintF("GenericBinaryOpStub (%s by %d)\n", | 131 |
| 214 Token::String(op_), | 132 void GenerateSmiStub(MacroAssembler* masm); |
| 215 constant_rhs_); | 133 void GenerateSmiStubSub(MacroAssembler* masm); |
| 216 } | 134 void GenerateSmiStubBitNot(MacroAssembler* masm); |
| 135 void GenerateSmiCodeSub(MacroAssembler* masm, Label* non_smi, Label* slow); |
| 136 void GenerateSmiCodeBitNot(MacroAssembler* masm, Label* slow); |
| 137 |
| 138 void GenerateHeapNumberStub(MacroAssembler* masm); |
| 139 void GenerateHeapNumberStubSub(MacroAssembler* masm); |
| 140 void GenerateHeapNumberStubBitNot(MacroAssembler* masm); |
| 141 void GenerateHeapNumberCodeSub(MacroAssembler* masm, Label* slow); |
| 142 void GenerateHeapNumberCodeBitNot(MacroAssembler* masm, Label* slow); |
| 143 |
| 144 void GenerateGenericStub(MacroAssembler* masm); |
| 145 void GenerateGenericStubSub(MacroAssembler* masm); |
| 146 void GenerateGenericStubBitNot(MacroAssembler* masm); |
| 147 void GenerateGenericCodeFallback(MacroAssembler* masm); |
| 148 |
| 149 virtual int GetCodeKind() { return Code::TYPE_RECORDING_UNARY_OP_IC; } |
| 150 |
| 151 virtual InlineCacheState GetICState() { |
| 152 return TRUnaryOpIC::ToState(operand_type_); |
| 217 } | 153 } |
| 218 #endif | 154 |
| 155 virtual void FinishCode(Code* code) { |
| 156 code->set_type_recording_unary_op_type(operand_type_); |
| 157 } |
| 219 }; | 158 }; |
| 220 | 159 |
| 160 |
| 221 class TypeRecordingBinaryOpStub: public CodeStub { | 161 class TypeRecordingBinaryOpStub: public CodeStub { |
| 222 public: | 162 public: |
| 223 TypeRecordingBinaryOpStub(Token::Value op, OverwriteMode mode) | 163 TypeRecordingBinaryOpStub(Token::Value op, OverwriteMode mode) |
| 224 : op_(op), | 164 : op_(op), |
| 225 mode_(mode), | 165 mode_(mode), |
| 226 operands_type_(TRBinaryOpIC::UNINITIALIZED), | 166 operands_type_(TRBinaryOpIC::UNINITIALIZED), |
| 227 result_type_(TRBinaryOpIC::UNINITIALIZED), | 167 result_type_(TRBinaryOpIC::UNINITIALIZED), |
| 228 name_(NULL) { | 168 name_(NULL) { |
| 229 UNIMPLEMENTED_MIPS(); | 169 use_fpu_ = CpuFeatures::IsSupported(FPU); |
| 170 ASSERT(OpBits::is_valid(Token::NUM_TOKENS)); |
| 230 } | 171 } |
| 231 | 172 |
| 232 TypeRecordingBinaryOpStub( | 173 TypeRecordingBinaryOpStub( |
| 233 int key, | 174 int key, |
| 234 TRBinaryOpIC::TypeInfo operands_type, | 175 TRBinaryOpIC::TypeInfo operands_type, |
| 235 TRBinaryOpIC::TypeInfo result_type = TRBinaryOpIC::UNINITIALIZED) | 176 TRBinaryOpIC::TypeInfo result_type = TRBinaryOpIC::UNINITIALIZED) |
| 236 : op_(OpBits::decode(key)), | 177 : op_(OpBits::decode(key)), |
| 237 mode_(ModeBits::decode(key)), | 178 mode_(ModeBits::decode(key)), |
| 238 use_fpu_(FPUBits::decode(key)), | 179 use_fpu_(FPUBits::decode(key)), |
| 239 operands_type_(operands_type), | 180 operands_type_(operands_type), |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 286 } | 227 } |
| 287 | 228 |
| 288 void Generate(MacroAssembler* masm); | 229 void Generate(MacroAssembler* masm); |
| 289 void GenerateGeneric(MacroAssembler* masm); | 230 void GenerateGeneric(MacroAssembler* masm); |
| 290 void GenerateSmiSmiOperation(MacroAssembler* masm); | 231 void GenerateSmiSmiOperation(MacroAssembler* masm); |
| 291 void GenerateFPOperation(MacroAssembler* masm, | 232 void GenerateFPOperation(MacroAssembler* masm, |
| 292 bool smi_operands, | 233 bool smi_operands, |
| 293 Label* not_numbers, | 234 Label* not_numbers, |
| 294 Label* gc_required); | 235 Label* gc_required); |
| 295 void GenerateSmiCode(MacroAssembler* masm, | 236 void GenerateSmiCode(MacroAssembler* masm, |
| 237 Label* use_runtime, |
| 296 Label* gc_required, | 238 Label* gc_required, |
| 297 SmiCodeGenerateHeapNumberResults heapnumber_results); | 239 SmiCodeGenerateHeapNumberResults heapnumber_results); |
| 298 void GenerateLoadArguments(MacroAssembler* masm); | 240 void GenerateLoadArguments(MacroAssembler* masm); |
| 299 void GenerateReturn(MacroAssembler* masm); | 241 void GenerateReturn(MacroAssembler* masm); |
| 300 void GenerateUninitializedStub(MacroAssembler* masm); | 242 void GenerateUninitializedStub(MacroAssembler* masm); |
| 301 void GenerateSmiStub(MacroAssembler* masm); | 243 void GenerateSmiStub(MacroAssembler* masm); |
| 302 void GenerateInt32Stub(MacroAssembler* masm); | 244 void GenerateInt32Stub(MacroAssembler* masm); |
| 303 void GenerateHeapNumberStub(MacroAssembler* masm); | 245 void GenerateHeapNumberStub(MacroAssembler* masm); |
| 246 void GenerateOddballStub(MacroAssembler* masm); |
| 304 void GenerateStringStub(MacroAssembler* masm); | 247 void GenerateStringStub(MacroAssembler* masm); |
| 248 void GenerateBothStringStub(MacroAssembler* masm); |
| 305 void GenerateGenericStub(MacroAssembler* masm); | 249 void GenerateGenericStub(MacroAssembler* masm); |
| 306 void GenerateAddStrings(MacroAssembler* masm); | 250 void GenerateAddStrings(MacroAssembler* masm); |
| 307 void GenerateCallRuntime(MacroAssembler* masm); | 251 void GenerateCallRuntime(MacroAssembler* masm); |
| 308 | 252 |
| 309 void GenerateHeapResultAllocation(MacroAssembler* masm, | 253 void GenerateHeapResultAllocation(MacroAssembler* masm, |
| 310 Register result, | 254 Register result, |
| 311 Register heap_number_map, | 255 Register heap_number_map, |
| 312 Register scratch1, | 256 Register scratch1, |
| 313 Register scratch2, | 257 Register scratch2, |
| 314 Label* gc_required); | 258 Label* gc_required); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 327 code->set_type_recording_binary_op_result_type(result_type_); | 271 code->set_type_recording_binary_op_result_type(result_type_); |
| 328 } | 272 } |
| 329 | 273 |
| 330 friend class CodeGenerator; | 274 friend class CodeGenerator; |
| 331 }; | 275 }; |
| 332 | 276 |
| 333 | 277 |
| 334 // Flag that indicates how to generate code for the stub StringAddStub. | 278 // Flag that indicates how to generate code for the stub StringAddStub. |
| 335 enum StringAddFlags { | 279 enum StringAddFlags { |
| 336 NO_STRING_ADD_FLAGS = 0, | 280 NO_STRING_ADD_FLAGS = 0, |
| 337 NO_STRING_CHECK_IN_STUB = 1 << 0 // Omit string check in stub. | 281 // Omit left string check in stub (left is definitely a string). |
| 282 NO_STRING_CHECK_LEFT_IN_STUB = 1 << 0, |
| 283 // Omit right string check in stub (right is definitely a string). |
| 284 NO_STRING_CHECK_RIGHT_IN_STUB = 1 << 1, |
| 285 // Omit both string checks in stub. |
| 286 NO_STRING_CHECK_IN_STUB = |
| 287 NO_STRING_CHECK_LEFT_IN_STUB | NO_STRING_CHECK_RIGHT_IN_STUB |
| 338 }; | 288 }; |
| 339 | 289 |
| 340 | 290 |
| 341 class StringAddStub: public CodeStub { | 291 class StringAddStub: public CodeStub { |
| 342 public: | 292 public: |
| 343 explicit StringAddStub(StringAddFlags flags) { | 293 explicit StringAddStub(StringAddFlags flags) : flags_(flags) {} |
| 344 string_check_ = ((flags & NO_STRING_CHECK_IN_STUB) == 0); | |
| 345 } | |
| 346 | 294 |
| 347 private: | 295 private: |
| 348 Major MajorKey() { return StringAdd; } | 296 Major MajorKey() { return StringAdd; } |
| 349 int MinorKey() { return string_check_ ? 0 : 1; } | 297 int MinorKey() { return flags_; } |
| 350 | 298 |
| 351 void Generate(MacroAssembler* masm); | 299 void Generate(MacroAssembler* masm); |
| 352 | 300 |
| 353 // Should the stub check whether arguments are strings? | 301 void GenerateConvertArgument(MacroAssembler* masm, |
| 354 bool string_check_; | 302 int stack_offset, |
| 303 Register arg, |
| 304 Register scratch1, |
| 305 Register scratch2, |
| 306 Register scratch3, |
| 307 Register scratch4, |
| 308 Label* slow); |
| 309 |
| 310 const StringAddFlags flags_; |
| 355 }; | 311 }; |
| 356 | 312 |
| 357 | 313 |
| 358 class SubStringStub: public CodeStub { | 314 class SubStringStub: public CodeStub { |
| 359 public: | 315 public: |
| 360 SubStringStub() {} | 316 SubStringStub() {} |
| 361 | 317 |
| 362 private: | 318 private: |
| 363 Major MajorKey() { return SubString; } | 319 Major MajorKey() { return SubString; } |
| 364 int MinorKey() { return 0; } | 320 int MinorKey() { return 0; } |
| 365 | 321 |
| 366 void Generate(MacroAssembler* masm); | 322 void Generate(MacroAssembler* masm); |
| 367 }; | 323 }; |
| 368 | 324 |
| 369 | 325 |
| 370 class StringCompareStub: public CodeStub { | 326 class StringCompareStub: public CodeStub { |
| 371 public: | 327 public: |
| 372 StringCompareStub() { } | 328 StringCompareStub() { } |
| 373 | 329 |
| 374 // Compare two flat ASCII strings and returns result in v0. | 330 // Compare two flat ASCII strings and returns result in v0. |
| 375 // Does not use the stack. | |
| 376 static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm, | 331 static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm, |
| 377 Register left, | 332 Register left, |
| 378 Register right, | 333 Register right, |
| 379 Register scratch1, | 334 Register scratch1, |
| 380 Register scratch2, | 335 Register scratch2, |
| 381 Register scratch3, | 336 Register scratch3, |
| 382 Register scratch4); | 337 Register scratch4); |
| 383 | 338 |
| 339 // Compares two flat ASCII strings for equality and returns result |
| 340 // in v0. |
| 341 static void GenerateFlatAsciiStringEquals(MacroAssembler* masm, |
| 342 Register left, |
| 343 Register right, |
| 344 Register scratch1, |
| 345 Register scratch2, |
| 346 Register scratch3); |
| 347 |
| 384 private: | 348 private: |
| 385 Major MajorKey() { return StringCompare; } | 349 virtual Major MajorKey() { return StringCompare; } |
| 386 int MinorKey() { return 0; } | 350 virtual int MinorKey() { return 0; } |
| 351 virtual void Generate(MacroAssembler* masm); |
| 387 | 352 |
| 388 void Generate(MacroAssembler* masm); | 353 static void GenerateAsciiCharsCompareLoop(MacroAssembler* masm, |
| 354 Register left, |
| 355 Register right, |
| 356 Register length, |
| 357 Register scratch1, |
| 358 Register scratch2, |
| 359 Register scratch3, |
| 360 Label* chars_not_equal); |
| 389 }; | 361 }; |
| 390 | 362 |
| 391 | 363 |
| 392 // This stub can convert a signed int32 to a heap number (double). It does | 364 // 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 | 365 // 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. | 366 // so you don't have to set up the frame. |
| 395 class WriteInt32ToHeapNumberStub : public CodeStub { | 367 class WriteInt32ToHeapNumberStub : public CodeStub { |
| 396 public: | 368 public: |
| 397 WriteInt32ToHeapNumberStub(Register the_int, | 369 WriteInt32ToHeapNumberStub(Register the_int, |
| 398 Register the_heap_number, | 370 Register the_heap_number, |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 477 | 449 |
| 478 private: | 450 private: |
| 479 Major MajorKey() { return RegExpCEntry; } | 451 Major MajorKey() { return RegExpCEntry; } |
| 480 int MinorKey() { return 0; } | 452 int MinorKey() { return 0; } |
| 481 | 453 |
| 482 bool NeedsImmovableCode() { return true; } | 454 bool NeedsImmovableCode() { return true; } |
| 483 | 455 |
| 484 const char* GetName() { return "RegExpCEntryStub"; } | 456 const char* GetName() { return "RegExpCEntryStub"; } |
| 485 }; | 457 }; |
| 486 | 458 |
| 487 | 459 // Trampoline stub to call into native code. To call safely into native code |
| 488 // Generate code the to load an element from a pixel array. The receiver is | 460 // in the presence of compacting GC (which can move code objects) we need to |
| 489 // assumed to not be a smi and to have elements, the caller must guarantee this | 461 // keep the code which called into native pinned in the memory. Currently the |
| 490 // precondition. If the receiver does not have elements that are pixel arrays, | 462 // simplest approach is to generate such stub early enough so it can never be |
| 491 // the generated code jumps to not_pixel_array. If key is not a smi, then the | 463 // moved by GC |
| 492 // generated code branches to key_not_smi. Callers can specify NULL for | 464 class DirectCEntryStub: public CodeStub { |
| 493 // key_not_smi to signal that a smi check has already been performed on key so | 465 public: |
| 494 // that the smi check is not generated . If key is not a valid index within the | 466 DirectCEntryStub() {} |
| 495 // bounds of the pixel array, the generated code jumps to out_of_range. | 467 void Generate(MacroAssembler* masm); |
| 496 void GenerateFastPixelArrayLoad(MacroAssembler* masm, | 468 void GenerateCall(MacroAssembler* masm, |
| 497 Register receiver, | 469 ExternalReference function); |
| 498 Register key, | 470 void GenerateCall(MacroAssembler* masm, Register target); |
| 499 Register elements_map, | 471 |
| 500 Register elements, | 472 private: |
| 473 Major MajorKey() { return DirectCEntry; } |
| 474 int MinorKey() { return 0; } |
| 475 |
| 476 bool NeedsImmovableCode() { return true; } |
| 477 |
| 478 const char* GetName() { return "DirectCEntryStub"; } |
| 479 }; |
| 480 |
| 481 class FloatingPointHelper : public AllStatic { |
| 482 public: |
| 483 |
| 484 enum Destination { |
| 485 kFPURegisters, |
| 486 kCoreRegisters |
| 487 }; |
| 488 |
| 489 |
| 490 // Loads smis from a0 and a1 (right and left in binary operations) into |
| 491 // floating point registers. Depending on the destination the values ends up |
| 492 // either f14 and f12 or in a2/a3 and a0/a1 respectively. If the destination |
| 493 // is floating point registers FPU must be supported. If core registers are |
| 494 // requested when FPU is supported f12 and f14 will be scratched. |
| 495 static void LoadSmis(MacroAssembler* masm, |
| 496 Destination destination, |
| 497 Register scratch1, |
| 498 Register scratch2); |
| 499 |
| 500 // Loads objects from a0 and a1 (right and left in binary operations) into |
| 501 // floating point registers. Depending on the destination the values ends up |
| 502 // either f14 and f12 or in a2/a3 and a0/a1 respectively. If the destination |
| 503 // is floating point registers FPU must be supported. If core registers are |
| 504 // requested when FPU is supported f12 and f14 will still be scratched. If |
| 505 // either a0 or a1 is not a number (not smi and not heap number object) the |
| 506 // not_number label is jumped to with a0 and a1 intact. |
| 507 static void LoadOperands(MacroAssembler* masm, |
| 508 FloatingPointHelper::Destination destination, |
| 509 Register heap_number_map, |
| 510 Register scratch1, |
| 511 Register scratch2, |
| 512 Label* not_number); |
| 513 |
| 514 // Convert the smi or heap number in object to an int32 using the rules |
| 515 // for ToInt32 as described in ECMAScript 9.5.: the value is truncated |
| 516 // and brought into the range -2^31 .. +2^31 - 1. |
| 517 static void ConvertNumberToInt32(MacroAssembler* masm, |
| 518 Register object, |
| 519 Register dst, |
| 520 Register heap_number_map, |
| 521 Register scratch1, |
| 522 Register scratch2, |
| 523 Register scratch3, |
| 524 FPURegister double_scratch, |
| 525 Label* not_int32); |
| 526 |
| 527 // Converts the integer (untagged smi) in |int_scratch| to a double, storing |
| 528 // the result either in |double_dst| or |dst2:dst1|, depending on |
| 529 // |destination|. |
| 530 // Warning: The value in |int_scratch| will be changed in the process! |
| 531 static void ConvertIntToDouble(MacroAssembler* masm, |
| 532 Register int_scratch, |
| 533 Destination destination, |
| 534 FPURegister double_dst, |
| 535 Register dst1, |
| 536 Register dst2, |
| 537 Register scratch2, |
| 538 FPURegister single_scratch); |
| 539 |
| 540 // Load the number from object into double_dst in the double format. |
| 541 // Control will jump to not_int32 if the value cannot be exactly represented |
| 542 // by a 32-bit integer. |
| 543 // Floating point value in the 32-bit integer range that are not exact integer |
| 544 // won't be loaded. |
| 545 static void LoadNumberAsInt32Double(MacroAssembler* masm, |
| 546 Register object, |
| 547 Destination destination, |
| 548 FPURegister double_dst, |
| 549 Register dst1, |
| 550 Register dst2, |
| 551 Register heap_number_map, |
| 552 Register scratch1, |
| 553 Register scratch2, |
| 554 FPURegister single_scratch, |
| 555 Label* not_int32); |
| 556 |
| 557 // Loads the number from object into dst as a 32-bit integer. |
| 558 // Control will jump to not_int32 if the object cannot be exactly represented |
| 559 // by a 32-bit integer. |
| 560 // Floating point value in the 32-bit integer range that are not exact integer |
| 561 // won't be converted. |
| 562 // scratch3 is not used when FPU is supported. |
| 563 static void LoadNumberAsInt32(MacroAssembler* masm, |
| 564 Register object, |
| 565 Register dst, |
| 566 Register heap_number_map, |
| 501 Register scratch1, | 567 Register scratch1, |
| 502 Register scratch2, | 568 Register scratch2, |
| 503 Register result, | 569 Register scratch3, |
| 504 Label* not_pixel_array, | 570 FPURegister double_scratch, |
| 505 Label* key_not_smi, | 571 Label* not_int32); |
| 506 Label* out_of_range); | 572 |
| 573 // Generate non FPU code to check if a double can be exactly represented by a |
| 574 // 32-bit integer. This does not check for 0 or -0, which need |
| 575 // to be checked for separately. |
| 576 // Control jumps to not_int32 if the value is not a 32-bit integer, and falls |
| 577 // through otherwise. |
| 578 // src1 and src2 will be cloberred. |
| 579 // |
| 580 // Expected input: |
| 581 // - src1: higher (exponent) part of the double value. |
| 582 // - src2: lower (mantissa) part of the double value. |
| 583 // Output status: |
| 584 // - dst: 32 higher bits of the mantissa. (mantissa[51:20]) |
| 585 // - src2: contains 1. |
| 586 // - other registers are clobbered. |
| 587 static void DoubleIs32BitInteger(MacroAssembler* masm, |
| 588 Register src1, |
| 589 Register src2, |
| 590 Register dst, |
| 591 Register scratch, |
| 592 Label* not_int32); |
| 593 |
| 594 // Generates code to call a C function to do a double operation using core |
| 595 // registers. (Used when FPU is not supported.) |
| 596 // This code never falls through, but returns with a heap number containing |
| 597 // the result in v0. |
| 598 // Register heapnumber_result must be a heap number in which the |
| 599 // result of the operation will be stored. |
| 600 // Requires the following layout on entry: |
| 601 // a0: Left value (least significant part of mantissa). |
| 602 // a1: Left value (sign, exponent, top of mantissa). |
| 603 // a2: Right value (least significant part of mantissa). |
| 604 // a3: Right value (sign, exponent, top of mantissa). |
| 605 static void CallCCodeForDoubleOperation(MacroAssembler* masm, |
| 606 Token::Value op, |
| 607 Register heap_number_result, |
| 608 Register scratch); |
| 609 |
| 610 private: |
| 611 static void LoadNumber(MacroAssembler* masm, |
| 612 FloatingPointHelper::Destination destination, |
| 613 Register object, |
| 614 FPURegister dst, |
| 615 Register dst1, |
| 616 Register dst2, |
| 617 Register heap_number_map, |
| 618 Register scratch1, |
| 619 Register scratch2, |
| 620 Label* not_number); |
| 621 }; |
| 622 |
| 623 |
| 624 class StringDictionaryLookupStub: public CodeStub { |
| 625 public: |
| 626 enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP }; |
| 627 |
| 628 explicit StringDictionaryLookupStub(LookupMode mode) : mode_(mode) { } |
| 629 |
| 630 void Generate(MacroAssembler* masm); |
| 631 |
| 632 MUST_USE_RESULT static MaybeObject* GenerateNegativeLookup( |
| 633 MacroAssembler* masm, |
| 634 Label* miss, |
| 635 Label* done, |
| 636 Register receiver, |
| 637 Register properties, |
| 638 String* name, |
| 639 Register scratch0); |
| 640 |
| 641 static void GeneratePositiveLookup(MacroAssembler* masm, |
| 642 Label* miss, |
| 643 Label* done, |
| 644 Register elements, |
| 645 Register name, |
| 646 Register r0, |
| 647 Register r1); |
| 648 |
| 649 private: |
| 650 static const int kInlinedProbes = 4; |
| 651 static const int kTotalProbes = 20; |
| 652 |
| 653 static const int kCapacityOffset = |
| 654 StringDictionary::kHeaderSize + |
| 655 StringDictionary::kCapacityIndex * kPointerSize; |
| 656 |
| 657 static const int kElementsStartOffset = |
| 658 StringDictionary::kHeaderSize + |
| 659 StringDictionary::kElementsStartIndex * kPointerSize; |
| 660 |
| 661 |
| 662 #ifdef DEBUG |
| 663 void Print() { |
| 664 PrintF("StringDictionaryLookupStub\n"); |
| 665 } |
| 666 #endif |
| 667 |
| 668 Major MajorKey() { return StringDictionaryNegativeLookup; } |
| 669 |
| 670 int MinorKey() { |
| 671 return LookupModeBits::encode(mode_); |
| 672 } |
| 673 |
| 674 class LookupModeBits: public BitField<LookupMode, 0, 1> {}; |
| 675 |
| 676 LookupMode mode_; |
| 677 }; |
| 507 | 678 |
| 508 | 679 |
| 509 } } // namespace v8::internal | 680 } } // namespace v8::internal |
| 510 | 681 |
| 511 #endif // V8_MIPS_CODE_STUBS_ARM_H_ | 682 #endif // V8_MIPS_CODE_STUBS_ARM_H_ |
| OLD | NEW |