OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
64 | 64 |
65 void Generate(MacroAssembler* masm); | 65 void Generate(MacroAssembler* masm); |
66 | 66 |
67 private: | 67 private: |
68 Register tos_; | 68 Register tos_; |
69 Major MajorKey() { return ToBoolean; } | 69 Major MajorKey() { return ToBoolean; } |
70 int MinorKey() { return tos_.code(); } | 70 int MinorKey() { return tos_.code(); } |
71 }; | 71 }; |
72 | 72 |
73 | 73 |
74 class GenericBinaryOpStub : public CodeStub { | |
75 public: | |
76 static const int kUnknownIntValue = -1; | |
77 | |
78 GenericBinaryOpStub(Token::Value op, | |
79 OverwriteMode mode, | |
80 Register lhs, | |
81 Register rhs, | |
82 int constant_rhs = kUnknownIntValue) | |
83 : op_(op), | |
84 mode_(mode), | |
85 lhs_(lhs), | |
86 rhs_(rhs), | |
87 constant_rhs_(constant_rhs), | |
88 specialized_on_rhs_(RhsIsOneWeWantToOptimizeFor(op, constant_rhs)), | |
89 runtime_operands_type_(BinaryOpIC::UNINIT_OR_SMI), | |
90 name_(NULL) { } | |
91 | |
92 GenericBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) | |
93 : op_(OpBits::decode(key)), | |
94 mode_(ModeBits::decode(key)), | |
95 lhs_(LhsRegister(RegisterBits::decode(key))), | |
96 rhs_(RhsRegister(RegisterBits::decode(key))), | |
97 constant_rhs_(KnownBitsForMinorKey(KnownIntBits::decode(key))), | |
98 specialized_on_rhs_(RhsIsOneWeWantToOptimizeFor(op_, constant_rhs_)), | |
99 runtime_operands_type_(type_info), | |
100 name_(NULL) { } | |
101 | |
102 private: | |
103 Token::Value op_; | |
104 OverwriteMode mode_; | |
105 Register lhs_; | |
106 Register rhs_; | |
107 int constant_rhs_; | |
108 bool specialized_on_rhs_; | |
109 BinaryOpIC::TypeInfo runtime_operands_type_; | |
110 char* name_; | |
111 | |
112 static const int kMaxKnownRhs = 0x40000000; | |
113 static const int kKnownRhsKeyBits = 6; | |
114 | |
115 // Minor key encoding in 17 bits. | |
116 class ModeBits: public BitField<OverwriteMode, 0, 2> {}; | |
117 class OpBits: public BitField<Token::Value, 2, 6> {}; | |
118 class TypeInfoBits: public BitField<int, 8, 3> {}; | |
119 class RegisterBits: public BitField<bool, 11, 1> {}; | |
120 class KnownIntBits: public BitField<int, 12, kKnownRhsKeyBits> {}; | |
121 | |
122 Major MajorKey() { return GenericBinaryOp; } | |
123 int MinorKey() { | |
124 ASSERT((lhs_.is(r0) && rhs_.is(r1)) || | |
125 (lhs_.is(r1) && rhs_.is(r0))); | |
126 // Encode the parameters in a unique 18 bit value. | |
127 return OpBits::encode(op_) | |
128 | ModeBits::encode(mode_) | |
129 | KnownIntBits::encode(MinorKeyForKnownInt()) | |
130 | TypeInfoBits::encode(runtime_operands_type_) | |
131 | RegisterBits::encode(lhs_.is(r0)); | |
132 } | |
133 | |
134 void Generate(MacroAssembler* masm); | |
135 void HandleNonSmiBitwiseOp(MacroAssembler* masm, | |
136 Register lhs, | |
137 Register rhs); | |
138 void HandleBinaryOpSlowCases(MacroAssembler* masm, | |
139 Label* not_smi, | |
140 Register lhs, | |
141 Register rhs, | |
142 const Builtins::JavaScript& builtin); | |
143 void GenerateTypeTransition(MacroAssembler* masm); | |
144 | |
145 static bool RhsIsOneWeWantToOptimizeFor(Token::Value op, int constant_rhs) { | |
146 if (constant_rhs == kUnknownIntValue) return false; | |
147 if (op == Token::DIV) return constant_rhs >= 2 && constant_rhs <= 3; | |
148 if (op == Token::MOD) { | |
149 if (constant_rhs <= 1) return false; | |
150 if (constant_rhs <= 10) return true; | |
151 if (constant_rhs <= kMaxKnownRhs && IsPowerOf2(constant_rhs)) return true; | |
152 return false; | |
153 } | |
154 return false; | |
155 } | |
156 | |
157 int MinorKeyForKnownInt() { | |
158 if (!specialized_on_rhs_) return 0; | |
159 if (constant_rhs_ <= 10) return constant_rhs_ + 1; | |
160 ASSERT(IsPowerOf2(constant_rhs_)); | |
161 int key = 12; | |
162 int d = constant_rhs_; | |
163 while ((d & 1) == 0) { | |
164 key++; | |
165 d >>= 1; | |
166 } | |
167 ASSERT(key >= 0 && key < (1 << kKnownRhsKeyBits)); | |
168 return key; | |
169 } | |
170 | |
171 int KnownBitsForMinorKey(int key) { | |
172 if (!key) return 0; | |
173 if (key <= 11) return key - 1; | |
174 int d = 1; | |
175 while (key != 12) { | |
176 key--; | |
177 d <<= 1; | |
178 } | |
179 return d; | |
180 } | |
181 | |
182 Register LhsRegister(bool lhs_is_r0) { | |
183 return lhs_is_r0 ? r0 : r1; | |
184 } | |
185 | |
186 Register RhsRegister(bool lhs_is_r0) { | |
187 return lhs_is_r0 ? r1 : r0; | |
188 } | |
189 | |
190 bool HasSmiSmiFastPath() { | |
191 return op_ != Token::DIV; | |
192 } | |
193 | |
194 bool ShouldGenerateSmiCode() { | |
195 return ((op_ != Token::DIV && op_ != Token::MOD) || specialized_on_rhs_) && | |
196 runtime_operands_type_ != BinaryOpIC::HEAP_NUMBERS && | |
197 runtime_operands_type_ != BinaryOpIC::STRINGS; | |
198 } | |
199 | |
200 bool ShouldGenerateFPCode() { | |
201 return runtime_operands_type_ != BinaryOpIC::STRINGS; | |
202 } | |
203 | |
204 virtual int GetCodeKind() { return Code::BINARY_OP_IC; } | |
205 | |
206 virtual InlineCacheState GetICState() { | |
207 return BinaryOpIC::ToState(runtime_operands_type_); | |
208 } | |
209 | |
210 const char* GetName(); | |
211 | |
212 virtual void FinishCode(Code* code) { | |
213 code->set_binary_op_type(runtime_operands_type_); | |
214 } | |
215 | |
216 #ifdef DEBUG | |
217 void Print() { | |
218 if (!specialized_on_rhs_) { | |
219 PrintF("GenericBinaryOpStub (%s)\n", Token::String(op_)); | |
220 } else { | |
221 PrintF("GenericBinaryOpStub (%s by %d)\n", | |
222 Token::String(op_), | |
223 constant_rhs_); | |
224 } | |
225 } | |
226 #endif | |
227 }; | |
228 | |
229 | |
230 class TypeRecordingBinaryOpStub: public CodeStub { | 74 class TypeRecordingBinaryOpStub: public CodeStub { |
231 public: | 75 public: |
232 TypeRecordingBinaryOpStub(Token::Value op, OverwriteMode mode) | 76 TypeRecordingBinaryOpStub(Token::Value op, OverwriteMode mode) |
233 : op_(op), | 77 : op_(op), |
234 mode_(mode), | 78 mode_(mode), |
235 operands_type_(TRBinaryOpIC::UNINITIALIZED), | 79 operands_type_(TRBinaryOpIC::UNINITIALIZED), |
236 result_type_(TRBinaryOpIC::UNINITIALIZED), | 80 result_type_(TRBinaryOpIC::UNINITIALIZED), |
237 name_(NULL) { | 81 name_(NULL) { |
238 use_vfp3_ = CpuFeatures::IsSupported(VFP3); | 82 use_vfp3_ = CpuFeatures::IsSupported(VFP3); |
239 ASSERT(OpBits::is_valid(Token::NUM_TOKENS)); | 83 ASSERT(OpBits::is_valid(Token::NUM_TOKENS)); |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
406 Register scratch4); | 250 Register scratch4); |
407 | 251 |
408 private: | 252 private: |
409 Major MajorKey() { return StringCompare; } | 253 Major MajorKey() { return StringCompare; } |
410 int MinorKey() { return 0; } | 254 int MinorKey() { return 0; } |
411 | 255 |
412 void Generate(MacroAssembler* masm); | 256 void Generate(MacroAssembler* masm); |
413 }; | 257 }; |
414 | 258 |
415 | 259 |
416 // This stub can do a fast mod operation without using fp. | |
417 // It is tail called from the GenericBinaryOpStub and it always | |
418 // returns an answer. It never causes GC so it doesn't need a real frame. | |
419 // | |
420 // The inputs are always positive Smis. This is never called | |
421 // where the denominator is a power of 2. We handle that separately. | |
422 // | |
423 // If we consider the denominator as an odd number multiplied by a power of 2, | |
424 // then: | |
425 // * The exponent (power of 2) is in the shift_distance register. | |
426 // * The odd number is in the odd_number register. It is always in the range | |
427 // of 3 to 25. | |
428 // * The bits from the numerator that are to be copied to the answer (there are | |
429 // shift_distance of them) are in the mask_bits register. | |
430 // * The other bits of the numerator have been shifted down and are in the lhs | |
431 // register. | |
432 class IntegerModStub : public CodeStub { | |
433 public: | |
434 IntegerModStub(Register result, | |
435 Register shift_distance, | |
436 Register odd_number, | |
437 Register mask_bits, | |
438 Register lhs, | |
439 Register scratch) | |
440 : result_(result), | |
441 shift_distance_(shift_distance), | |
442 odd_number_(odd_number), | |
443 mask_bits_(mask_bits), | |
444 lhs_(lhs), | |
445 scratch_(scratch) { | |
446 // We don't code these in the minor key, so they should always be the same. | |
447 // We don't really want to fix that since this stub is rather large and we | |
448 // don't want many copies of it. | |
449 ASSERT(shift_distance_.is(r9)); | |
450 ASSERT(odd_number_.is(r4)); | |
451 ASSERT(mask_bits_.is(r3)); | |
452 ASSERT(scratch_.is(r5)); | |
453 } | |
454 | |
455 private: | |
456 Register result_; | |
457 Register shift_distance_; | |
458 Register odd_number_; | |
459 Register mask_bits_; | |
460 Register lhs_; | |
461 Register scratch_; | |
462 | |
463 // Minor key encoding in 16 bits. | |
464 class ResultRegisterBits: public BitField<int, 0, 4> {}; | |
465 class LhsRegisterBits: public BitField<int, 4, 4> {}; | |
466 | |
467 Major MajorKey() { return IntegerMod; } | |
468 int MinorKey() { | |
469 // Encode the parameters in a unique 16 bit value. | |
470 return ResultRegisterBits::encode(result_.code()) | |
471 | LhsRegisterBits::encode(lhs_.code()); | |
472 } | |
473 | |
474 void Generate(MacroAssembler* masm); | |
475 | |
476 const char* GetName() { return "IntegerModStub"; } | |
477 | |
478 // Utility functions. | |
479 void DigitSum(MacroAssembler* masm, | |
480 Register lhs, | |
481 int mask, | |
482 int shift, | |
483 Label* entry); | |
484 void DigitSum(MacroAssembler* masm, | |
485 Register lhs, | |
486 Register scratch, | |
487 int mask, | |
488 int shift1, | |
489 int shift2, | |
490 Label* entry); | |
491 void ModGetInRangeBySubtraction(MacroAssembler* masm, | |
492 Register lhs, | |
493 int shift, | |
494 int rhs); | |
495 void ModReduce(MacroAssembler* masm, | |
496 Register lhs, | |
497 int max, | |
498 int denominator); | |
499 void ModAnswer(MacroAssembler* masm, | |
500 Register result, | |
501 Register shift_distance, | |
502 Register mask_bits, | |
503 Register sum_of_digits); | |
504 | |
505 | |
506 #ifdef DEBUG | |
507 void Print() { PrintF("IntegerModStub\n"); } | |
508 #endif | |
509 }; | |
510 | |
511 | |
512 // This stub can convert a signed int32 to a heap number (double). It does | 260 // This stub can convert a signed int32 to a heap number (double). It does |
513 // not work for int32s that are in Smi range! No GC occurs during this stub | 261 // not work for int32s that are in Smi range! No GC occurs during this stub |
514 // so you don't have to set up the frame. | 262 // so you don't have to set up the frame. |
515 class WriteInt32ToHeapNumberStub : public CodeStub { | 263 class WriteInt32ToHeapNumberStub : public CodeStub { |
516 public: | 264 public: |
517 WriteInt32ToHeapNumberStub(Register the_int, | 265 WriteInt32ToHeapNumberStub(Register the_int, |
518 Register the_heap_number, | 266 Register the_heap_number, |
519 Register scratch) | 267 Register scratch) |
520 : the_int_(the_int), | 268 : the_int_(the_int), |
521 the_heap_number_(the_heap_number), | 269 the_heap_number_(the_heap_number), |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
614 | 362 |
615 bool NeedsImmovableCode() { return true; } | 363 bool NeedsImmovableCode() { return true; } |
616 | 364 |
617 const char* GetName() { return "DirectCEntryStub"; } | 365 const char* GetName() { return "DirectCEntryStub"; } |
618 }; | 366 }; |
619 | 367 |
620 | 368 |
621 } } // namespace v8::internal | 369 } } // namespace v8::internal |
622 | 370 |
623 #endif // V8_ARM_CODE_STUBS_ARM_H_ | 371 #endif // V8_ARM_CODE_STUBS_ARM_H_ |
OLD | NEW |