• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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