blob: bf7d63548733b69a06ed102dea5f7ddc01b3d16c [file] [log] [blame]
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001// 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 "ic-inl.h"
32
33namespace v8 {
34namespace internal {
35
36
37// Compute a transcendental math function natively, or call the
38// TranscendentalCache runtime function.
39class TranscendentalCacheStub: public CodeStub {
40 public:
41 explicit TranscendentalCacheStub(TranscendentalCache::Type type)
42 : type_(type) {}
43 void Generate(MacroAssembler* masm);
44 private:
45 TranscendentalCache::Type type_;
46 Major MajorKey() { return TranscendentalCache; }
47 int MinorKey() { return type_; }
48 Runtime::FunctionId RuntimeFunction();
49};
50
51
52class ToBooleanStub: public CodeStub {
53 public:
54 explicit ToBooleanStub(Register tos) : tos_(tos) { }
55
56 void Generate(MacroAssembler* masm);
57
58 private:
59 Register tos_;
60 Major MajorKey() { return ToBoolean; }
61 int MinorKey() { return tos_.code(); }
62};
63
64
65class GenericBinaryOpStub : public CodeStub {
66 public:
67 static const int kUnknownIntValue = -1;
68
69 GenericBinaryOpStub(Token::Value op,
70 OverwriteMode mode,
71 Register lhs,
72 Register rhs,
73 int constant_rhs = 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)),
Steve Block9fac8402011-05-12 15:51:54 +010080 runtime_operands_type_(BinaryOpIC::UNINIT_OR_SMI),
Kristian Monsen80d68ea2010-09-08 11:05:35 +010081 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> {};
Ben Murdochb0fe1622011-05-05 13:52:32 +0100109 class TypeInfoBits: public BitField<int, 8, 3> {};
110 class RegisterBits: public BitField<bool, 11, 1> {};
111 class KnownIntBits: public BitField<int, 12, kKnownRhsKeyBits> {};
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100112
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 == 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
Steve Block9fac8402011-05-12 15:51:54 +0100181 bool HasSmiSmiFastPath() {
182 return op_ != Token::DIV;
183 }
184
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100185 bool ShouldGenerateSmiCode() {
186 return ((op_ != Token::DIV && op_ != Token::MOD) || specialized_on_rhs_) &&
187 runtime_operands_type_ != BinaryOpIC::HEAP_NUMBERS &&
188 runtime_operands_type_ != BinaryOpIC::STRINGS;
189 }
190
191 bool ShouldGenerateFPCode() {
192 return runtime_operands_type_ != BinaryOpIC::STRINGS;
193 }
194
195 virtual int GetCodeKind() { return Code::BINARY_OP_IC; }
196
197 virtual InlineCacheState GetICState() {
198 return BinaryOpIC::ToState(runtime_operands_type_);
199 }
200
201 const char* GetName();
202
Ben Murdochb0fe1622011-05-05 13:52:32 +0100203 virtual void FinishCode(Code* code) {
204 code->set_binary_op_type(runtime_operands_type_);
205 }
206
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100207#ifdef DEBUG
208 void Print() {
209 if (!specialized_on_rhs_) {
210 PrintF("GenericBinaryOpStub (%s)\n", Token::String(op_));
211 } else {
212 PrintF("GenericBinaryOpStub (%s by %d)\n",
213 Token::String(op_),
214 constant_rhs_);
215 }
216 }
217#endif
218};
219
220
Steve Block1e0659c2011-05-24 12:43:12 +0100221class 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 use_vfp3_ = CpuFeatures::IsSupported(VFP3);
230 ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
231 }
232
233 TypeRecordingBinaryOpStub(
234 int key,
235 TRBinaryOpIC::TypeInfo operands_type,
236 TRBinaryOpIC::TypeInfo result_type = TRBinaryOpIC::UNINITIALIZED)
237 : op_(OpBits::decode(key)),
238 mode_(ModeBits::decode(key)),
239 use_vfp3_(VFP3Bits::decode(key)),
240 operands_type_(operands_type),
241 result_type_(result_type),
242 name_(NULL) { }
243
244 private:
245 enum SmiCodeGenerateHeapNumberResults {
246 ALLOW_HEAPNUMBER_RESULTS,
247 NO_HEAPNUMBER_RESULTS
248 };
249
250 Token::Value op_;
251 OverwriteMode mode_;
252 bool use_vfp3_;
253
254 // Operand type information determined at runtime.
255 TRBinaryOpIC::TypeInfo operands_type_;
256 TRBinaryOpIC::TypeInfo result_type_;
257
258 char* name_;
259
260 const char* GetName();
261
262#ifdef DEBUG
263 void Print() {
264 PrintF("TypeRecordingBinaryOpStub %d (op %s), "
265 "(mode %d, runtime_type_info %s)\n",
266 MinorKey(),
267 Token::String(op_),
268 static_cast<int>(mode_),
269 TRBinaryOpIC::GetName(operands_type_));
270 }
271#endif
272
273 // Minor key encoding in 16 bits RRRTTTVOOOOOOOMM.
274 class ModeBits: public BitField<OverwriteMode, 0, 2> {};
275 class OpBits: public BitField<Token::Value, 2, 7> {};
276 class VFP3Bits: public BitField<bool, 9, 1> {};
277 class OperandTypeInfoBits: public BitField<TRBinaryOpIC::TypeInfo, 10, 3> {};
278 class ResultTypeInfoBits: public BitField<TRBinaryOpIC::TypeInfo, 13, 3> {};
279
280 Major MajorKey() { return TypeRecordingBinaryOp; }
281 int MinorKey() {
282 return OpBits::encode(op_)
283 | ModeBits::encode(mode_)
284 | VFP3Bits::encode(use_vfp3_)
285 | OperandTypeInfoBits::encode(operands_type_)
286 | ResultTypeInfoBits::encode(result_type_);
287 }
288
289 void Generate(MacroAssembler* masm);
290 void GenerateGeneric(MacroAssembler* masm);
291 void GenerateSmiSmiOperation(MacroAssembler* masm);
292 void GenerateFPOperation(MacroAssembler* masm,
293 bool smi_operands,
294 Label* not_numbers,
295 Label* gc_required);
296 void GenerateSmiCode(MacroAssembler* masm,
297 Label* gc_required,
298 SmiCodeGenerateHeapNumberResults heapnumber_results);
299 void GenerateLoadArguments(MacroAssembler* masm);
300 void GenerateReturn(MacroAssembler* masm);
301 void GenerateUninitializedStub(MacroAssembler* masm);
302 void GenerateSmiStub(MacroAssembler* masm);
303 void GenerateInt32Stub(MacroAssembler* masm);
304 void GenerateHeapNumberStub(MacroAssembler* masm);
305 void GenerateStringStub(MacroAssembler* masm);
306 void GenerateGenericStub(MacroAssembler* masm);
307 void GenerateAddStrings(MacroAssembler* masm);
308 void GenerateCallRuntime(MacroAssembler* masm);
309
310 void GenerateHeapResultAllocation(MacroAssembler* masm,
311 Register result,
312 Register heap_number_map,
313 Register scratch1,
314 Register scratch2,
315 Label* gc_required);
316 void GenerateRegisterArgsPush(MacroAssembler* masm);
317 void GenerateTypeTransition(MacroAssembler* masm);
318 void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm);
319
320 virtual int GetCodeKind() { return Code::TYPE_RECORDING_BINARY_OP_IC; }
321
322 virtual InlineCacheState GetICState() {
323 return TRBinaryOpIC::ToState(operands_type_);
324 }
325
326 virtual void FinishCode(Code* code) {
327 code->set_type_recording_binary_op_type(operands_type_);
328 code->set_type_recording_binary_op_result_type(result_type_);
329 }
330
331 friend class CodeGenerator;
332};
333
334
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100335// Flag that indicates how to generate code for the stub StringAddStub.
336enum StringAddFlags {
337 NO_STRING_ADD_FLAGS = 0,
338 NO_STRING_CHECK_IN_STUB = 1 << 0 // Omit string check in stub.
339};
340
341
342class StringAddStub: public CodeStub {
343 public:
344 explicit StringAddStub(StringAddFlags flags) {
345 string_check_ = ((flags & NO_STRING_CHECK_IN_STUB) == 0);
346 }
347
348 private:
349 Major MajorKey() { return StringAdd; }
350 int MinorKey() { return string_check_ ? 0 : 1; }
351
352 void Generate(MacroAssembler* masm);
353
354 // Should the stub check whether arguments are strings?
355 bool string_check_;
356};
357
358
359class SubStringStub: public CodeStub {
360 public:
361 SubStringStub() {}
362
363 private:
364 Major MajorKey() { return SubString; }
365 int MinorKey() { return 0; }
366
367 void Generate(MacroAssembler* masm);
368};
369
370
371
372class StringCompareStub: public CodeStub {
373 public:
374 StringCompareStub() { }
375
376 // Compare two flat ASCII strings and returns result in r0.
377 // Does not use the stack.
378 static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
379 Register left,
380 Register right,
381 Register scratch1,
382 Register scratch2,
383 Register scratch3,
384 Register scratch4);
385
386 private:
387 Major MajorKey() { return StringCompare; }
388 int MinorKey() { return 0; }
389
390 void Generate(MacroAssembler* masm);
391};
392
393
394// This stub can do a fast mod operation without using fp.
395// It is tail called from the GenericBinaryOpStub and it always
396// returns an answer. It never causes GC so it doesn't need a real frame.
397//
398// The inputs are always positive Smis. This is never called
399// where the denominator is a power of 2. We handle that separately.
400//
401// If we consider the denominator as an odd number multiplied by a power of 2,
402// then:
403// * The exponent (power of 2) is in the shift_distance register.
404// * The odd number is in the odd_number register. It is always in the range
405// of 3 to 25.
406// * The bits from the numerator that are to be copied to the answer (there are
407// shift_distance of them) are in the mask_bits register.
408// * The other bits of the numerator have been shifted down and are in the lhs
409// register.
410class IntegerModStub : public CodeStub {
411 public:
412 IntegerModStub(Register result,
413 Register shift_distance,
414 Register odd_number,
415 Register mask_bits,
416 Register lhs,
417 Register scratch)
418 : result_(result),
419 shift_distance_(shift_distance),
420 odd_number_(odd_number),
421 mask_bits_(mask_bits),
422 lhs_(lhs),
423 scratch_(scratch) {
424 // We don't code these in the minor key, so they should always be the same.
425 // We don't really want to fix that since this stub is rather large and we
426 // don't want many copies of it.
427 ASSERT(shift_distance_.is(r9));
428 ASSERT(odd_number_.is(r4));
429 ASSERT(mask_bits_.is(r3));
430 ASSERT(scratch_.is(r5));
431 }
432
433 private:
434 Register result_;
435 Register shift_distance_;
436 Register odd_number_;
437 Register mask_bits_;
438 Register lhs_;
439 Register scratch_;
440
441 // Minor key encoding in 16 bits.
442 class ResultRegisterBits: public BitField<int, 0, 4> {};
443 class LhsRegisterBits: public BitField<int, 4, 4> {};
444
445 Major MajorKey() { return IntegerMod; }
446 int MinorKey() {
447 // Encode the parameters in a unique 16 bit value.
448 return ResultRegisterBits::encode(result_.code())
449 | LhsRegisterBits::encode(lhs_.code());
450 }
451
452 void Generate(MacroAssembler* masm);
453
454 const char* GetName() { return "IntegerModStub"; }
455
456 // Utility functions.
457 void DigitSum(MacroAssembler* masm,
458 Register lhs,
459 int mask,
460 int shift,
461 Label* entry);
462 void DigitSum(MacroAssembler* masm,
463 Register lhs,
464 Register scratch,
465 int mask,
466 int shift1,
467 int shift2,
468 Label* entry);
469 void ModGetInRangeBySubtraction(MacroAssembler* masm,
470 Register lhs,
471 int shift,
472 int rhs);
473 void ModReduce(MacroAssembler* masm,
474 Register lhs,
475 int max,
476 int denominator);
477 void ModAnswer(MacroAssembler* masm,
478 Register result,
479 Register shift_distance,
480 Register mask_bits,
481 Register sum_of_digits);
482
483
484#ifdef DEBUG
485 void Print() { PrintF("IntegerModStub\n"); }
486#endif
487};
488
489
490// This stub can convert a signed int32 to a heap number (double). It does
491// not work for int32s that are in Smi range! No GC occurs during this stub
492// so you don't have to set up the frame.
493class WriteInt32ToHeapNumberStub : public CodeStub {
494 public:
495 WriteInt32ToHeapNumberStub(Register the_int,
496 Register the_heap_number,
497 Register scratch)
498 : the_int_(the_int),
499 the_heap_number_(the_heap_number),
500 scratch_(scratch) { }
501
502 private:
503 Register the_int_;
504 Register the_heap_number_;
505 Register scratch_;
506
507 // Minor key encoding in 16 bits.
508 class IntRegisterBits: public BitField<int, 0, 4> {};
509 class HeapNumberRegisterBits: public BitField<int, 4, 4> {};
510 class ScratchRegisterBits: public BitField<int, 8, 4> {};
511
512 Major MajorKey() { return WriteInt32ToHeapNumber; }
513 int MinorKey() {
514 // Encode the parameters in a unique 16 bit value.
515 return IntRegisterBits::encode(the_int_.code())
516 | HeapNumberRegisterBits::encode(the_heap_number_.code())
517 | ScratchRegisterBits::encode(scratch_.code());
518 }
519
520 void Generate(MacroAssembler* masm);
521
522 const char* GetName() { return "WriteInt32ToHeapNumberStub"; }
523
524#ifdef DEBUG
525 void Print() { PrintF("WriteInt32ToHeapNumberStub\n"); }
526#endif
527};
528
529
530class NumberToStringStub: public CodeStub {
531 public:
532 NumberToStringStub() { }
533
534 // Generate code to do a lookup in the number string cache. If the number in
535 // the register object is found in the cache the generated code falls through
536 // with the result in the result register. The object and the result register
537 // can be the same. If the number is not found in the cache the code jumps to
538 // the label not_found with only the content of register object unchanged.
539 static void GenerateLookupNumberStringCache(MacroAssembler* masm,
540 Register object,
541 Register result,
542 Register scratch1,
543 Register scratch2,
544 Register scratch3,
545 bool object_is_smi,
546 Label* not_found);
547
548 private:
549 Major MajorKey() { return NumberToString; }
550 int MinorKey() { return 0; }
551
552 void Generate(MacroAssembler* masm);
553
554 const char* GetName() { return "NumberToStringStub"; }
555};
556
557
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100558// Enter C code from generated RegExp code in a way that allows
559// the C code to fix the return address in case of a GC.
560// Currently only needed on ARM.
561class RegExpCEntryStub: public CodeStub {
562 public:
563 RegExpCEntryStub() {}
564 virtual ~RegExpCEntryStub() {}
565 void Generate(MacroAssembler* masm);
566
567 private:
568 Major MajorKey() { return RegExpCEntry; }
569 int MinorKey() { return 0; }
570 const char* GetName() { return "RegExpCEntryStub"; }
571};
572
573
Steve Block1e0659c2011-05-24 12:43:12 +0100574// Trampoline stub to call into native code. To call safely into native code
575// in the presence of compacting GC (which can move code objects) we need to
576// keep the code which called into native pinned in the memory. Currently the
577// simplest approach is to generate such stub early enough so it can never be
578// moved by GC
579class DirectCEntryStub: public CodeStub {
580 public:
581 DirectCEntryStub() {}
582 void Generate(MacroAssembler* masm);
583 void GenerateCall(MacroAssembler* masm, ApiFunction *function);
584
585 private:
586 Major MajorKey() { return DirectCEntry; }
587 int MinorKey() { return 0; }
588 const char* GetName() { return "DirectCEntryStub"; }
589};
590
591
592// Generate code the to load an element from a pixel array. The receiver is
593// assumed to not be a smi and to have elements, the caller must guarantee this
594// precondition. If the receiver does not have elements that are pixel arrays,
595// the generated code jumps to not_pixel_array. If key is not a smi, then the
596// generated code branches to key_not_smi. Callers can specify NULL for
597// key_not_smi to signal that a smi check has already been performed on key so
598// that the smi check is not generated . If key is not a valid index within the
599// bounds of the pixel array, the generated code jumps to out_of_range.
600void GenerateFastPixelArrayLoad(MacroAssembler* masm,
601 Register receiver,
602 Register key,
603 Register elements_map,
604 Register elements,
605 Register scratch1,
606 Register scratch2,
607 Register result,
608 Label* not_pixel_array,
609 Label* key_not_smi,
610 Label* out_of_range);
611
612
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100613} } // namespace v8::internal
614
615#endif // V8_ARM_CODE_STUBS_ARM_H_