code-stubs-arm.h revision 80d68eab642096c1a48b6474d6ec33064b0ad1f5
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_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)),
80        runtime_operands_type_(BinaryOpIC::DEFAULT),
81        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> {};
109  class TypeInfoBits: public BitField<int, 8, 2> {};
110  class RegisterBits: public BitField<bool, 10, 1> {};
111  class KnownIntBits: public BitField<int, 11, kKnownRhsKeyBits> {};
112
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
181  bool ShouldGenerateSmiCode() {
182    return ((op_ != Token::DIV && op_ != Token::MOD) || specialized_on_rhs_) &&
183        runtime_operands_type_ != BinaryOpIC::HEAP_NUMBERS &&
184        runtime_operands_type_ != BinaryOpIC::STRINGS;
185  }
186
187  bool ShouldGenerateFPCode() {
188    return runtime_operands_type_ != BinaryOpIC::STRINGS;
189  }
190
191  virtual int GetCodeKind() { return Code::BINARY_OP_IC; }
192
193  virtual InlineCacheState GetICState() {
194    return BinaryOpIC::ToState(runtime_operands_type_);
195  }
196
197  const char* GetName();
198
199#ifdef DEBUG
200  void Print() {
201    if (!specialized_on_rhs_) {
202      PrintF("GenericBinaryOpStub (%s)\n", Token::String(op_));
203    } else {
204      PrintF("GenericBinaryOpStub (%s by %d)\n",
205             Token::String(op_),
206             constant_rhs_);
207    }
208  }
209#endif
210};
211
212
213// Flag that indicates how to generate code for the stub StringAddStub.
214enum StringAddFlags {
215  NO_STRING_ADD_FLAGS = 0,
216  NO_STRING_CHECK_IN_STUB = 1 << 0  // Omit string check in stub.
217};
218
219
220class StringAddStub: public CodeStub {
221 public:
222  explicit StringAddStub(StringAddFlags flags) {
223    string_check_ = ((flags & NO_STRING_CHECK_IN_STUB) == 0);
224  }
225
226 private:
227  Major MajorKey() { return StringAdd; }
228  int MinorKey() { return string_check_ ? 0 : 1; }
229
230  void Generate(MacroAssembler* masm);
231
232  // Should the stub check whether arguments are strings?
233  bool string_check_;
234};
235
236
237class SubStringStub: public CodeStub {
238 public:
239  SubStringStub() {}
240
241 private:
242  Major MajorKey() { return SubString; }
243  int MinorKey() { return 0; }
244
245  void Generate(MacroAssembler* masm);
246};
247
248
249
250class StringCompareStub: public CodeStub {
251 public:
252  StringCompareStub() { }
253
254  // Compare two flat ASCII strings and returns result in r0.
255  // Does not use the stack.
256  static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
257                                              Register left,
258                                              Register right,
259                                              Register scratch1,
260                                              Register scratch2,
261                                              Register scratch3,
262                                              Register scratch4);
263
264 private:
265  Major MajorKey() { return StringCompare; }
266  int MinorKey() { return 0; }
267
268  void Generate(MacroAssembler* masm);
269};
270
271
272// This stub can do a fast mod operation without using fp.
273// It is tail called from the GenericBinaryOpStub and it always
274// returns an answer.  It never causes GC so it doesn't need a real frame.
275//
276// The inputs are always positive Smis.  This is never called
277// where the denominator is a power of 2.  We handle that separately.
278//
279// If we consider the denominator as an odd number multiplied by a power of 2,
280// then:
281// * The exponent (power of 2) is in the shift_distance register.
282// * The odd number is in the odd_number register.  It is always in the range
283//   of 3 to 25.
284// * The bits from the numerator that are to be copied to the answer (there are
285//   shift_distance of them) are in the mask_bits register.
286// * The other bits of the numerator have been shifted down and are in the lhs
287//   register.
288class IntegerModStub : public CodeStub {
289 public:
290  IntegerModStub(Register result,
291                 Register shift_distance,
292                 Register odd_number,
293                 Register mask_bits,
294                 Register lhs,
295                 Register scratch)
296      : result_(result),
297        shift_distance_(shift_distance),
298        odd_number_(odd_number),
299        mask_bits_(mask_bits),
300        lhs_(lhs),
301        scratch_(scratch) {
302    // We don't code these in the minor key, so they should always be the same.
303    // We don't really want to fix that since this stub is rather large and we
304    // don't want many copies of it.
305    ASSERT(shift_distance_.is(r9));
306    ASSERT(odd_number_.is(r4));
307    ASSERT(mask_bits_.is(r3));
308    ASSERT(scratch_.is(r5));
309  }
310
311 private:
312  Register result_;
313  Register shift_distance_;
314  Register odd_number_;
315  Register mask_bits_;
316  Register lhs_;
317  Register scratch_;
318
319  // Minor key encoding in 16 bits.
320  class ResultRegisterBits: public BitField<int, 0, 4> {};
321  class LhsRegisterBits: public BitField<int, 4, 4> {};
322
323  Major MajorKey() { return IntegerMod; }
324  int MinorKey() {
325    // Encode the parameters in a unique 16 bit value.
326    return ResultRegisterBits::encode(result_.code())
327           | LhsRegisterBits::encode(lhs_.code());
328  }
329
330  void Generate(MacroAssembler* masm);
331
332  const char* GetName() { return "IntegerModStub"; }
333
334  // Utility functions.
335  void DigitSum(MacroAssembler* masm,
336                Register lhs,
337                int mask,
338                int shift,
339                Label* entry);
340  void DigitSum(MacroAssembler* masm,
341                Register lhs,
342                Register scratch,
343                int mask,
344                int shift1,
345                int shift2,
346                Label* entry);
347  void ModGetInRangeBySubtraction(MacroAssembler* masm,
348                                  Register lhs,
349                                  int shift,
350                                  int rhs);
351  void ModReduce(MacroAssembler* masm,
352                 Register lhs,
353                 int max,
354                 int denominator);
355  void ModAnswer(MacroAssembler* masm,
356                 Register result,
357                 Register shift_distance,
358                 Register mask_bits,
359                 Register sum_of_digits);
360
361
362#ifdef DEBUG
363  void Print() { PrintF("IntegerModStub\n"); }
364#endif
365};
366
367
368// This stub can convert a signed int32 to a heap number (double).  It does
369// not work for int32s that are in Smi range!  No GC occurs during this stub
370// so you don't have to set up the frame.
371class WriteInt32ToHeapNumberStub : public CodeStub {
372 public:
373  WriteInt32ToHeapNumberStub(Register the_int,
374                             Register the_heap_number,
375                             Register scratch)
376      : the_int_(the_int),
377        the_heap_number_(the_heap_number),
378        scratch_(scratch) { }
379
380 private:
381  Register the_int_;
382  Register the_heap_number_;
383  Register scratch_;
384
385  // Minor key encoding in 16 bits.
386  class IntRegisterBits: public BitField<int, 0, 4> {};
387  class HeapNumberRegisterBits: public BitField<int, 4, 4> {};
388  class ScratchRegisterBits: public BitField<int, 8, 4> {};
389
390  Major MajorKey() { return WriteInt32ToHeapNumber; }
391  int MinorKey() {
392    // Encode the parameters in a unique 16 bit value.
393    return IntRegisterBits::encode(the_int_.code())
394           | HeapNumberRegisterBits::encode(the_heap_number_.code())
395           | ScratchRegisterBits::encode(scratch_.code());
396  }
397
398  void Generate(MacroAssembler* masm);
399
400  const char* GetName() { return "WriteInt32ToHeapNumberStub"; }
401
402#ifdef DEBUG
403  void Print() { PrintF("WriteInt32ToHeapNumberStub\n"); }
404#endif
405};
406
407
408class NumberToStringStub: public CodeStub {
409 public:
410  NumberToStringStub() { }
411
412  // Generate code to do a lookup in the number string cache. If the number in
413  // the register object is found in the cache the generated code falls through
414  // with the result in the result register. The object and the result register
415  // can be the same. If the number is not found in the cache the code jumps to
416  // the label not_found with only the content of register object unchanged.
417  static void GenerateLookupNumberStringCache(MacroAssembler* masm,
418                                              Register object,
419                                              Register result,
420                                              Register scratch1,
421                                              Register scratch2,
422                                              Register scratch3,
423                                              bool object_is_smi,
424                                              Label* not_found);
425
426 private:
427  Major MajorKey() { return NumberToString; }
428  int MinorKey() { return 0; }
429
430  void Generate(MacroAssembler* masm);
431
432  const char* GetName() { return "NumberToStringStub"; }
433};
434
435
436class RecordWriteStub : public CodeStub {
437 public:
438  RecordWriteStub(Register object, Register offset, Register scratch)
439      : object_(object), offset_(offset), scratch_(scratch) { }
440
441  void Generate(MacroAssembler* masm);
442
443 private:
444  Register object_;
445  Register offset_;
446  Register scratch_;
447
448  // Minor key encoding in 12 bits. 4 bits for each of the three
449  // registers (object, offset and scratch) OOOOAAAASSSS.
450  class ScratchBits: public BitField<uint32_t, 0, 4> {};
451  class OffsetBits: public BitField<uint32_t, 4, 4> {};
452  class ObjectBits: public BitField<uint32_t, 8, 4> {};
453
454  Major MajorKey() { return RecordWrite; }
455
456  int MinorKey() {
457    // Encode the registers.
458    return ObjectBits::encode(object_.code()) |
459           OffsetBits::encode(offset_.code()) |
460           ScratchBits::encode(scratch_.code());
461  }
462
463#ifdef DEBUG
464  void Print() {
465    PrintF("RecordWriteStub (object reg %d), (offset reg %d),"
466           " (scratch reg %d)\n",
467           object_.code(), offset_.code(), scratch_.code());
468  }
469#endif
470};
471
472
473// Enter C code from generated RegExp code in a way that allows
474// the C code to fix the return address in case of a GC.
475// Currently only needed on ARM.
476class RegExpCEntryStub: public CodeStub {
477 public:
478  RegExpCEntryStub() {}
479  virtual ~RegExpCEntryStub() {}
480  void Generate(MacroAssembler* masm);
481
482 private:
483  Major MajorKey() { return RegExpCEntry; }
484  int MinorKey() { return 0; }
485  const char* GetName() { return "RegExpCEntryStub"; }
486};
487
488
489} }  // namespace v8::internal
490
491#endif  // V8_ARM_CODE_STUBS_ARM_H_
492