• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2011 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 
33 namespace v8 {
34 namespace internal {
35 
36 
37 // Compute a transcendental math function natively, or call the
38 // TranscendentalCache runtime function.
39 class TranscendentalCacheStub: public CodeStub {
40  public:
41   enum ArgumentType {
42     TAGGED = 0 << TranscendentalCache::kTranscendentalTypeBits,
43     UNTAGGED = 1 << TranscendentalCache::kTranscendentalTypeBits
44   };
45 
TranscendentalCacheStub(TranscendentalCache::Type type,ArgumentType argument_type)46   TranscendentalCacheStub(TranscendentalCache::Type type,
47                           ArgumentType argument_type)
48       : type_(type), argument_type_(argument_type) { }
49   void Generate(MacroAssembler* masm);
50  private:
51   TranscendentalCache::Type type_;
52   ArgumentType argument_type_;
53   void GenerateCallCFunction(MacroAssembler* masm, Register scratch);
54 
MajorKey()55   Major MajorKey() { return TranscendentalCache; }
MinorKey()56   int MinorKey() { return type_ | argument_type_; }
57   Runtime::FunctionId RuntimeFunction();
58 };
59 
60 
61 class StoreBufferOverflowStub: public CodeStub {
62  public:
StoreBufferOverflowStub(SaveFPRegsMode save_fp)63   explicit StoreBufferOverflowStub(SaveFPRegsMode save_fp)
64       : save_doubles_(save_fp) { }
65 
66   void Generate(MacroAssembler* masm);
67 
68   virtual bool IsPregenerated();
69   static void GenerateFixedRegStubsAheadOfTime();
SometimesSetsUpAFrame()70   virtual bool SometimesSetsUpAFrame() { return false; }
71 
72  private:
73   SaveFPRegsMode save_doubles_;
74 
MajorKey()75   Major MajorKey() { return StoreBufferOverflow; }
MinorKey()76   int MinorKey() { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; }
77 };
78 
79 
80 class UnaryOpStub: public CodeStub {
81  public:
82   UnaryOpStub(Token::Value op,
83               UnaryOverwriteMode mode,
84               UnaryOpIC::TypeInfo operand_type = UnaryOpIC::UNINITIALIZED)
op_(op)85       : op_(op),
86         mode_(mode),
87         operand_type_(operand_type) {
88   }
89 
90  private:
91   Token::Value op_;
92   UnaryOverwriteMode mode_;
93 
94   // Operand type information determined at runtime.
95   UnaryOpIC::TypeInfo operand_type_;
96 
97   virtual void PrintName(StringStream* stream);
98 
99   class ModeBits: public BitField<UnaryOverwriteMode, 0, 1> {};
100   class OpBits: public BitField<Token::Value, 1, 7> {};
101   class OperandTypeInfoBits: public BitField<UnaryOpIC::TypeInfo, 8, 3> {};
102 
MajorKey()103   Major MajorKey() { return UnaryOp; }
MinorKey()104   int MinorKey() {
105     return ModeBits::encode(mode_)
106            | OpBits::encode(op_)
107            | OperandTypeInfoBits::encode(operand_type_);
108   }
109 
110   // Note: A lot of the helper functions below will vanish when we use virtual
111   // function instead of switch more often.
112   void Generate(MacroAssembler* masm);
113 
114   void GenerateTypeTransition(MacroAssembler* masm);
115 
116   void GenerateSmiStub(MacroAssembler* masm);
117   void GenerateSmiStubSub(MacroAssembler* masm);
118   void GenerateSmiStubBitNot(MacroAssembler* masm);
119   void GenerateSmiCodeSub(MacroAssembler* masm, Label* non_smi, Label* slow);
120   void GenerateSmiCodeBitNot(MacroAssembler* masm, Label* slow);
121 
122   void GenerateHeapNumberStub(MacroAssembler* masm);
123   void GenerateHeapNumberStubSub(MacroAssembler* masm);
124   void GenerateHeapNumberStubBitNot(MacroAssembler* masm);
125   void GenerateHeapNumberCodeSub(MacroAssembler* masm, Label* slow);
126   void GenerateHeapNumberCodeBitNot(MacroAssembler* masm, Label* slow);
127 
128   void GenerateGenericStub(MacroAssembler* masm);
129   void GenerateGenericStubSub(MacroAssembler* masm);
130   void GenerateGenericStubBitNot(MacroAssembler* masm);
131   void GenerateGenericCodeFallback(MacroAssembler* masm);
132 
GetCodeKind()133   virtual int GetCodeKind() { return Code::UNARY_OP_IC; }
134 
GetICState()135   virtual InlineCacheState GetICState() {
136     return UnaryOpIC::ToState(operand_type_);
137   }
138 
FinishCode(Handle<Code> code)139   virtual void FinishCode(Handle<Code> code) {
140     code->set_unary_op_type(operand_type_);
141   }
142 };
143 
144 
145 class BinaryOpStub: public CodeStub {
146  public:
BinaryOpStub(Token::Value op,OverwriteMode mode)147   BinaryOpStub(Token::Value op, OverwriteMode mode)
148       : op_(op),
149         mode_(mode),
150         operands_type_(BinaryOpIC::UNINITIALIZED),
151         result_type_(BinaryOpIC::UNINITIALIZED) {
152     use_vfp3_ = CpuFeatures::IsSupported(VFP3);
153     ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
154   }
155 
156   BinaryOpStub(
157       int key,
158       BinaryOpIC::TypeInfo operands_type,
159       BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED)
op_(OpBits::decode (key))160       : op_(OpBits::decode(key)),
161         mode_(ModeBits::decode(key)),
162         use_vfp3_(VFP3Bits::decode(key)),
163         operands_type_(operands_type),
164         result_type_(result_type) { }
165 
166  private:
167   enum SmiCodeGenerateHeapNumberResults {
168     ALLOW_HEAPNUMBER_RESULTS,
169     NO_HEAPNUMBER_RESULTS
170   };
171 
172   Token::Value op_;
173   OverwriteMode mode_;
174   bool use_vfp3_;
175 
176   // Operand type information determined at runtime.
177   BinaryOpIC::TypeInfo operands_type_;
178   BinaryOpIC::TypeInfo result_type_;
179 
180   virtual void PrintName(StringStream* stream);
181 
182   // Minor key encoding in 16 bits RRRTTTVOOOOOOOMM.
183   class ModeBits: public BitField<OverwriteMode, 0, 2> {};
184   class OpBits: public BitField<Token::Value, 2, 7> {};
185   class VFP3Bits: public BitField<bool, 9, 1> {};
186   class OperandTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 10, 3> {};
187   class ResultTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 13, 3> {};
188 
MajorKey()189   Major MajorKey() { return BinaryOp; }
MinorKey()190   int MinorKey() {
191     return OpBits::encode(op_)
192            | ModeBits::encode(mode_)
193            | VFP3Bits::encode(use_vfp3_)
194            | OperandTypeInfoBits::encode(operands_type_)
195            | ResultTypeInfoBits::encode(result_type_);
196   }
197 
198   void Generate(MacroAssembler* masm);
199   void GenerateGeneric(MacroAssembler* masm);
200   void GenerateSmiSmiOperation(MacroAssembler* masm);
201   void GenerateFPOperation(MacroAssembler* masm,
202                            bool smi_operands,
203                            Label* not_numbers,
204                            Label* gc_required);
205   void GenerateSmiCode(MacroAssembler* masm,
206                        Label* use_runtime,
207                        Label* gc_required,
208                        SmiCodeGenerateHeapNumberResults heapnumber_results);
209   void GenerateLoadArguments(MacroAssembler* masm);
210   void GenerateReturn(MacroAssembler* masm);
211   void GenerateUninitializedStub(MacroAssembler* masm);
212   void GenerateSmiStub(MacroAssembler* masm);
213   void GenerateInt32Stub(MacroAssembler* masm);
214   void GenerateHeapNumberStub(MacroAssembler* masm);
215   void GenerateOddballStub(MacroAssembler* masm);
216   void GenerateStringStub(MacroAssembler* masm);
217   void GenerateBothStringStub(MacroAssembler* masm);
218   void GenerateGenericStub(MacroAssembler* masm);
219   void GenerateAddStrings(MacroAssembler* masm);
220   void GenerateCallRuntime(MacroAssembler* masm);
221 
222   void GenerateHeapResultAllocation(MacroAssembler* masm,
223                                     Register result,
224                                     Register heap_number_map,
225                                     Register scratch1,
226                                     Register scratch2,
227                                     Label* gc_required);
228   void GenerateRegisterArgsPush(MacroAssembler* masm);
229   void GenerateTypeTransition(MacroAssembler* masm);
230   void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm);
231 
GetCodeKind()232   virtual int GetCodeKind() { return Code::BINARY_OP_IC; }
233 
GetICState()234   virtual InlineCacheState GetICState() {
235     return BinaryOpIC::ToState(operands_type_);
236   }
237 
FinishCode(Handle<Code> code)238   virtual void FinishCode(Handle<Code> code) {
239     code->set_binary_op_type(operands_type_);
240     code->set_binary_op_result_type(result_type_);
241   }
242 
243   friend class CodeGenerator;
244 };
245 
246 
247 class StringHelper : public AllStatic {
248  public:
249   // Generate code for copying characters using a simple loop. This should only
250   // be used in places where the number of characters is small and the
251   // additional setup and checking in GenerateCopyCharactersLong adds too much
252   // overhead. Copying of overlapping regions is not supported.
253   // Dest register ends at the position after the last character written.
254   static void GenerateCopyCharacters(MacroAssembler* masm,
255                                      Register dest,
256                                      Register src,
257                                      Register count,
258                                      Register scratch,
259                                      bool ascii);
260 
261   // Generate code for copying a large number of characters. This function
262   // is allowed to spend extra time setting up conditions to make copying
263   // faster. Copying of overlapping regions is not supported.
264   // Dest register ends at the position after the last character written.
265   static void GenerateCopyCharactersLong(MacroAssembler* masm,
266                                          Register dest,
267                                          Register src,
268                                          Register count,
269                                          Register scratch1,
270                                          Register scratch2,
271                                          Register scratch3,
272                                          Register scratch4,
273                                          Register scratch5,
274                                          int flags);
275 
276 
277   // Probe the symbol table for a two character string. If the string is
278   // not found by probing a jump to the label not_found is performed. This jump
279   // does not guarantee that the string is not in the symbol table. If the
280   // string is found the code falls through with the string in register r0.
281   // Contents of both c1 and c2 registers are modified. At the exit c1 is
282   // guaranteed to contain halfword with low and high bytes equal to
283   // initial contents of c1 and c2 respectively.
284   static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
285                                                    Register c1,
286                                                    Register c2,
287                                                    Register scratch1,
288                                                    Register scratch2,
289                                                    Register scratch3,
290                                                    Register scratch4,
291                                                    Register scratch5,
292                                                    Label* not_found);
293 
294   // Generate string hash.
295   static void GenerateHashInit(MacroAssembler* masm,
296                                Register hash,
297                                Register character);
298 
299   static void GenerateHashAddCharacter(MacroAssembler* masm,
300                                        Register hash,
301                                        Register character);
302 
303   static void GenerateHashGetHash(MacroAssembler* masm,
304                                   Register hash);
305 
306  private:
307   DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
308 };
309 
310 
311 // Flag that indicates how to generate code for the stub StringAddStub.
312 enum StringAddFlags {
313   NO_STRING_ADD_FLAGS = 0,
314   // Omit left string check in stub (left is definitely a string).
315   NO_STRING_CHECK_LEFT_IN_STUB = 1 << 0,
316   // Omit right string check in stub (right is definitely a string).
317   NO_STRING_CHECK_RIGHT_IN_STUB = 1 << 1,
318   // Omit both string checks in stub.
319   NO_STRING_CHECK_IN_STUB =
320       NO_STRING_CHECK_LEFT_IN_STUB | NO_STRING_CHECK_RIGHT_IN_STUB
321 };
322 
323 
324 class StringAddStub: public CodeStub {
325  public:
StringAddStub(StringAddFlags flags)326   explicit StringAddStub(StringAddFlags flags) : flags_(flags) {}
327 
328  private:
MajorKey()329   Major MajorKey() { return StringAdd; }
MinorKey()330   int MinorKey() { return flags_; }
331 
332   void Generate(MacroAssembler* masm);
333 
334   void GenerateConvertArgument(MacroAssembler* masm,
335                                int stack_offset,
336                                Register arg,
337                                Register scratch1,
338                                Register scratch2,
339                                Register scratch3,
340                                Register scratch4,
341                                Label* slow);
342 
343   const StringAddFlags flags_;
344 };
345 
346 
347 class SubStringStub: public CodeStub {
348  public:
SubStringStub()349   SubStringStub() {}
350 
351  private:
MajorKey()352   Major MajorKey() { return SubString; }
MinorKey()353   int MinorKey() { return 0; }
354 
355   void Generate(MacroAssembler* masm);
356 };
357 
358 
359 
360 class StringCompareStub: public CodeStub {
361  public:
StringCompareStub()362   StringCompareStub() { }
363 
364   // Compares two flat ASCII strings and returns result in r0.
365   static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
366                                               Register left,
367                                               Register right,
368                                               Register scratch1,
369                                               Register scratch2,
370                                               Register scratch3,
371                                               Register scratch4);
372 
373   // Compares two flat ASCII strings for equality and returns result
374   // in r0.
375   static void GenerateFlatAsciiStringEquals(MacroAssembler* masm,
376                                             Register left,
377                                             Register right,
378                                             Register scratch1,
379                                             Register scratch2,
380                                             Register scratch3);
381 
382  private:
MajorKey()383   virtual Major MajorKey() { return StringCompare; }
MinorKey()384   virtual int MinorKey() { return 0; }
385   virtual void Generate(MacroAssembler* masm);
386 
387   static void GenerateAsciiCharsCompareLoop(MacroAssembler* masm,
388                                             Register left,
389                                             Register right,
390                                             Register length,
391                                             Register scratch1,
392                                             Register scratch2,
393                                             Label* chars_not_equal);
394 };
395 
396 
397 // This stub can convert a signed int32 to a heap number (double).  It does
398 // not work for int32s that are in Smi range!  No GC occurs during this stub
399 // so you don't have to set up the frame.
400 class WriteInt32ToHeapNumberStub : public CodeStub {
401  public:
WriteInt32ToHeapNumberStub(Register the_int,Register the_heap_number,Register scratch)402   WriteInt32ToHeapNumberStub(Register the_int,
403                              Register the_heap_number,
404                              Register scratch)
405       : the_int_(the_int),
406         the_heap_number_(the_heap_number),
407         scratch_(scratch) { }
408 
409   bool IsPregenerated();
410   static void GenerateFixedRegStubsAheadOfTime();
411 
412  private:
413   Register the_int_;
414   Register the_heap_number_;
415   Register scratch_;
416 
417   // Minor key encoding in 16 bits.
418   class IntRegisterBits: public BitField<int, 0, 4> {};
419   class HeapNumberRegisterBits: public BitField<int, 4, 4> {};
420   class ScratchRegisterBits: public BitField<int, 8, 4> {};
421 
MajorKey()422   Major MajorKey() { return WriteInt32ToHeapNumber; }
MinorKey()423   int MinorKey() {
424     // Encode the parameters in a unique 16 bit value.
425     return IntRegisterBits::encode(the_int_.code())
426            | HeapNumberRegisterBits::encode(the_heap_number_.code())
427            | ScratchRegisterBits::encode(scratch_.code());
428   }
429 
430   void Generate(MacroAssembler* masm);
431 };
432 
433 
434 class NumberToStringStub: public CodeStub {
435  public:
NumberToStringStub()436   NumberToStringStub() { }
437 
438   // Generate code to do a lookup in the number string cache. If the number in
439   // the register object is found in the cache the generated code falls through
440   // with the result in the result register. The object and the result register
441   // can be the same. If the number is not found in the cache the code jumps to
442   // the label not_found with only the content of register object unchanged.
443   static void GenerateLookupNumberStringCache(MacroAssembler* masm,
444                                               Register object,
445                                               Register result,
446                                               Register scratch1,
447                                               Register scratch2,
448                                               Register scratch3,
449                                               bool object_is_smi,
450                                               Label* not_found);
451 
452  private:
MajorKey()453   Major MajorKey() { return NumberToString; }
MinorKey()454   int MinorKey() { return 0; }
455 
456   void Generate(MacroAssembler* masm);
457 };
458 
459 
460 class RecordWriteStub: public CodeStub {
461  public:
RecordWriteStub(Register object,Register value,Register address,RememberedSetAction remembered_set_action,SaveFPRegsMode fp_mode)462   RecordWriteStub(Register object,
463                   Register value,
464                   Register address,
465                   RememberedSetAction remembered_set_action,
466                   SaveFPRegsMode fp_mode)
467       : object_(object),
468         value_(value),
469         address_(address),
470         remembered_set_action_(remembered_set_action),
471         save_fp_regs_mode_(fp_mode),
472         regs_(object,   // An input reg.
473               address,  // An input reg.
474               value) {  // One scratch reg.
475   }
476 
477   enum Mode {
478     STORE_BUFFER_ONLY,
479     INCREMENTAL,
480     INCREMENTAL_COMPACTION
481   };
482 
483   virtual bool IsPregenerated();
484   static void GenerateFixedRegStubsAheadOfTime();
SometimesSetsUpAFrame()485   virtual bool SometimesSetsUpAFrame() { return false; }
486 
PatchBranchIntoNop(MacroAssembler * masm,int pos)487   static void PatchBranchIntoNop(MacroAssembler* masm, int pos) {
488     masm->instr_at_put(pos, (masm->instr_at(pos) & ~B27) | (B24 | B20));
489     ASSERT(Assembler::IsTstImmediate(masm->instr_at(pos)));
490   }
491 
PatchNopIntoBranch(MacroAssembler * masm,int pos)492   static void PatchNopIntoBranch(MacroAssembler* masm, int pos) {
493     masm->instr_at_put(pos, (masm->instr_at(pos) & ~(B24 | B20)) | B27);
494     ASSERT(Assembler::IsBranch(masm->instr_at(pos)));
495   }
496 
GetMode(Code * stub)497   static Mode GetMode(Code* stub) {
498     Instr first_instruction = Assembler::instr_at(stub->instruction_start());
499     Instr second_instruction = Assembler::instr_at(stub->instruction_start() +
500                                                    Assembler::kInstrSize);
501 
502     if (Assembler::IsBranch(first_instruction)) {
503       return INCREMENTAL;
504     }
505 
506     ASSERT(Assembler::IsTstImmediate(first_instruction));
507 
508     if (Assembler::IsBranch(second_instruction)) {
509       return INCREMENTAL_COMPACTION;
510     }
511 
512     ASSERT(Assembler::IsTstImmediate(second_instruction));
513 
514     return STORE_BUFFER_ONLY;
515   }
516 
Patch(Code * stub,Mode mode)517   static void Patch(Code* stub, Mode mode) {
518     MacroAssembler masm(NULL,
519                         stub->instruction_start(),
520                         stub->instruction_size());
521     switch (mode) {
522       case STORE_BUFFER_ONLY:
523         ASSERT(GetMode(stub) == INCREMENTAL ||
524                GetMode(stub) == INCREMENTAL_COMPACTION);
525         PatchBranchIntoNop(&masm, 0);
526         PatchBranchIntoNop(&masm, Assembler::kInstrSize);
527         break;
528       case INCREMENTAL:
529         ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
530         PatchNopIntoBranch(&masm, 0);
531         break;
532       case INCREMENTAL_COMPACTION:
533         ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
534         PatchNopIntoBranch(&masm, Assembler::kInstrSize);
535         break;
536     }
537     ASSERT(GetMode(stub) == mode);
538     CPU::FlushICache(stub->instruction_start(), 2 * Assembler::kInstrSize);
539   }
540 
541  private:
542   // This is a helper class for freeing up 3 scratch registers.  The input is
543   // two registers that must be preserved and one scratch register provided by
544   // the caller.
545   class RegisterAllocation {
546    public:
RegisterAllocation(Register object,Register address,Register scratch0)547     RegisterAllocation(Register object,
548                        Register address,
549                        Register scratch0)
550         : object_(object),
551           address_(address),
552           scratch0_(scratch0) {
553       ASSERT(!AreAliased(scratch0, object, address, no_reg));
554       scratch1_ = GetRegThatIsNotOneOf(object_, address_, scratch0_);
555     }
556 
Save(MacroAssembler * masm)557     void Save(MacroAssembler* masm) {
558       ASSERT(!AreAliased(object_, address_, scratch1_, scratch0_));
559       // We don't have to save scratch0_ because it was given to us as
560       // a scratch register.
561       masm->push(scratch1_);
562     }
563 
Restore(MacroAssembler * masm)564     void Restore(MacroAssembler* masm) {
565       masm->pop(scratch1_);
566     }
567 
568     // If we have to call into C then we need to save and restore all caller-
569     // saved registers that were not already preserved.  The scratch registers
570     // will be restored by other means so we don't bother pushing them here.
SaveCallerSaveRegisters(MacroAssembler * masm,SaveFPRegsMode mode)571     void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
572       masm->stm(db_w, sp, (kCallerSaved | lr.bit()) & ~scratch1_.bit());
573       if (mode == kSaveFPRegs) {
574         CpuFeatures::Scope scope(VFP3);
575         masm->sub(sp,
576                   sp,
577                   Operand(kDoubleSize * (DwVfpRegister::kNumRegisters - 1)));
578         // Save all VFP registers except d0.
579         for (int i = DwVfpRegister::kNumRegisters - 1; i > 0; i--) {
580           DwVfpRegister reg = DwVfpRegister::from_code(i);
581           masm->vstr(reg, MemOperand(sp, (i - 1) * kDoubleSize));
582         }
583       }
584     }
585 
RestoreCallerSaveRegisters(MacroAssembler * masm,SaveFPRegsMode mode)586     inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
587                                            SaveFPRegsMode mode) {
588       if (mode == kSaveFPRegs) {
589         CpuFeatures::Scope scope(VFP3);
590         // Restore all VFP registers except d0.
591         for (int i = DwVfpRegister::kNumRegisters - 1; i > 0; i--) {
592           DwVfpRegister reg = DwVfpRegister::from_code(i);
593           masm->vldr(reg, MemOperand(sp, (i - 1) * kDoubleSize));
594         }
595         masm->add(sp,
596                   sp,
597                   Operand(kDoubleSize * (DwVfpRegister::kNumRegisters - 1)));
598       }
599       masm->ldm(ia_w, sp, (kCallerSaved | lr.bit()) & ~scratch1_.bit());
600     }
601 
object()602     inline Register object() { return object_; }
address()603     inline Register address() { return address_; }
scratch0()604     inline Register scratch0() { return scratch0_; }
scratch1()605     inline Register scratch1() { return scratch1_; }
606 
607    private:
608     Register object_;
609     Register address_;
610     Register scratch0_;
611     Register scratch1_;
612 
GetRegThatIsNotOneOf(Register r1,Register r2,Register r3)613     Register GetRegThatIsNotOneOf(Register r1,
614                                   Register r2,
615                                   Register r3) {
616       for (int i = 0; i < Register::kNumAllocatableRegisters; i++) {
617         Register candidate = Register::FromAllocationIndex(i);
618         if (candidate.is(r1)) continue;
619         if (candidate.is(r2)) continue;
620         if (candidate.is(r3)) continue;
621         return candidate;
622       }
623       UNREACHABLE();
624       return no_reg;
625     }
626     friend class RecordWriteStub;
627   };
628 
629   enum OnNoNeedToInformIncrementalMarker {
630     kReturnOnNoNeedToInformIncrementalMarker,
631     kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
632   };
633 
634   void Generate(MacroAssembler* masm);
635   void GenerateIncremental(MacroAssembler* masm, Mode mode);
636   void CheckNeedsToInformIncrementalMarker(
637       MacroAssembler* masm,
638       OnNoNeedToInformIncrementalMarker on_no_need,
639       Mode mode);
640   void InformIncrementalMarker(MacroAssembler* masm, Mode mode);
641 
MajorKey()642   Major MajorKey() { return RecordWrite; }
643 
MinorKey()644   int MinorKey() {
645     return ObjectBits::encode(object_.code()) |
646         ValueBits::encode(value_.code()) |
647         AddressBits::encode(address_.code()) |
648         RememberedSetActionBits::encode(remembered_set_action_) |
649         SaveFPRegsModeBits::encode(save_fp_regs_mode_);
650   }
651 
Activate(Code * code)652   void Activate(Code* code) {
653     code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
654   }
655 
656   class ObjectBits: public BitField<int, 0, 4> {};
657   class ValueBits: public BitField<int, 4, 4> {};
658   class AddressBits: public BitField<int, 8, 4> {};
659   class RememberedSetActionBits: public BitField<RememberedSetAction, 12, 1> {};
660   class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 13, 1> {};
661 
662   Register object_;
663   Register value_;
664   Register address_;
665   RememberedSetAction remembered_set_action_;
666   SaveFPRegsMode save_fp_regs_mode_;
667   Label slow_;
668   RegisterAllocation regs_;
669 };
670 
671 
672 // Enter C code from generated RegExp code in a way that allows
673 // the C code to fix the return address in case of a GC.
674 // Currently only needed on ARM.
675 class RegExpCEntryStub: public CodeStub {
676  public:
RegExpCEntryStub()677   RegExpCEntryStub() {}
~RegExpCEntryStub()678   virtual ~RegExpCEntryStub() {}
679   void Generate(MacroAssembler* masm);
680 
681  private:
MajorKey()682   Major MajorKey() { return RegExpCEntry; }
MinorKey()683   int MinorKey() { return 0; }
684 
NeedsImmovableCode()685   bool NeedsImmovableCode() { return true; }
686 };
687 
688 
689 // Trampoline stub to call into native code. To call safely into native code
690 // in the presence of compacting GC (which can move code objects) we need to
691 // keep the code which called into native pinned in the memory. Currently the
692 // simplest approach is to generate such stub early enough so it can never be
693 // moved by GC
694 class DirectCEntryStub: public CodeStub {
695  public:
DirectCEntryStub()696   DirectCEntryStub() {}
697   void Generate(MacroAssembler* masm);
698   void GenerateCall(MacroAssembler* masm, ExternalReference function);
699   void GenerateCall(MacroAssembler* masm, Register target);
700 
701  private:
MajorKey()702   Major MajorKey() { return DirectCEntry; }
MinorKey()703   int MinorKey() { return 0; }
704 
NeedsImmovableCode()705   bool NeedsImmovableCode() { return true; }
706 };
707 
708 
709 class FloatingPointHelper : public AllStatic {
710  public:
711   enum Destination {
712     kVFPRegisters,
713     kCoreRegisters
714   };
715 
716 
717   // Loads smis from r0 and r1 (right and left in binary operations) into
718   // floating point registers. Depending on the destination the values ends up
719   // either d7 and d6 or in r2/r3 and r0/r1 respectively. If the destination is
720   // floating point registers VFP3 must be supported. If core registers are
721   // requested when VFP3 is supported d6 and d7 will be scratched.
722   static void LoadSmis(MacroAssembler* masm,
723                        Destination destination,
724                        Register scratch1,
725                        Register scratch2);
726 
727   // Loads objects from r0 and r1 (right and left in binary operations) into
728   // floating point registers. Depending on the destination the values ends up
729   // either d7 and d6 or in r2/r3 and r0/r1 respectively. If the destination is
730   // floating point registers VFP3 must be supported. If core registers are
731   // requested when VFP3 is supported d6 and d7 will still be scratched. If
732   // either r0 or r1 is not a number (not smi and not heap number object) the
733   // not_number label is jumped to with r0 and r1 intact.
734   static void LoadOperands(MacroAssembler* masm,
735                            FloatingPointHelper::Destination destination,
736                            Register heap_number_map,
737                            Register scratch1,
738                            Register scratch2,
739                            Label* not_number);
740 
741   // Convert the smi or heap number in object to an int32 using the rules
742   // for ToInt32 as described in ECMAScript 9.5.: the value is truncated
743   // and brought into the range -2^31 .. +2^31 - 1.
744   static void ConvertNumberToInt32(MacroAssembler* masm,
745                                    Register object,
746                                    Register dst,
747                                    Register heap_number_map,
748                                    Register scratch1,
749                                    Register scratch2,
750                                    Register scratch3,
751                                    DwVfpRegister double_scratch,
752                                    Label* not_int32);
753 
754   // Converts the integer (untagged smi) in |int_scratch| to a double, storing
755   // the result either in |double_dst| or |dst2:dst1|, depending on
756   // |destination|.
757   // Warning: The value in |int_scratch| will be changed in the process!
758   static void ConvertIntToDouble(MacroAssembler* masm,
759                                  Register int_scratch,
760                                  Destination destination,
761                                  DwVfpRegister double_dst,
762                                  Register dst1,
763                                  Register dst2,
764                                  Register scratch2,
765                                  SwVfpRegister single_scratch);
766 
767   // Load the number from object into double_dst in the double format.
768   // Control will jump to not_int32 if the value cannot be exactly represented
769   // by a 32-bit integer.
770   // Floating point value in the 32-bit integer range that are not exact integer
771   // won't be loaded.
772   static void LoadNumberAsInt32Double(MacroAssembler* masm,
773                                       Register object,
774                                       Destination destination,
775                                       DwVfpRegister double_dst,
776                                       Register dst1,
777                                       Register dst2,
778                                       Register heap_number_map,
779                                       Register scratch1,
780                                       Register scratch2,
781                                       SwVfpRegister single_scratch,
782                                       Label* not_int32);
783 
784   // Loads the number from object into dst as a 32-bit integer.
785   // Control will jump to not_int32 if the object cannot be exactly represented
786   // by a 32-bit integer.
787   // Floating point value in the 32-bit integer range that are not exact integer
788   // won't be converted.
789   // scratch3 is not used when VFP3 is supported.
790   static void LoadNumberAsInt32(MacroAssembler* masm,
791                                 Register object,
792                                 Register dst,
793                                 Register heap_number_map,
794                                 Register scratch1,
795                                 Register scratch2,
796                                 Register scratch3,
797                                 DwVfpRegister double_scratch,
798                                 Label* not_int32);
799 
800   // Generate non VFP3 code to check if a double can be exactly represented by a
801   // 32-bit integer. This does not check for 0 or -0, which need
802   // to be checked for separately.
803   // Control jumps to not_int32 if the value is not a 32-bit integer, and falls
804   // through otherwise.
805   // src1 and src2 will be cloberred.
806   //
807   // Expected input:
808   // - src1: higher (exponent) part of the double value.
809   // - src2: lower (mantissa) part of the double value.
810   // Output status:
811   // - dst: 32 higher bits of the mantissa. (mantissa[51:20])
812   // - src2: contains 1.
813   // - other registers are clobbered.
814   static void DoubleIs32BitInteger(MacroAssembler* masm,
815                                    Register src1,
816                                    Register src2,
817                                    Register dst,
818                                    Register scratch,
819                                    Label* not_int32);
820 
821   // Generates code to call a C function to do a double operation using core
822   // registers. (Used when VFP3 is not supported.)
823   // This code never falls through, but returns with a heap number containing
824   // the result in r0.
825   // Register heapnumber_result must be a heap number in which the
826   // result of the operation will be stored.
827   // Requires the following layout on entry:
828   // r0: Left value (least significant part of mantissa).
829   // r1: Left value (sign, exponent, top of mantissa).
830   // r2: Right value (least significant part of mantissa).
831   // r3: Right value (sign, exponent, top of mantissa).
832   static void CallCCodeForDoubleOperation(MacroAssembler* masm,
833                                           Token::Value op,
834                                           Register heap_number_result,
835                                           Register scratch);
836 
837  private:
838   static void LoadNumber(MacroAssembler* masm,
839                          FloatingPointHelper::Destination destination,
840                          Register object,
841                          DwVfpRegister dst,
842                          Register dst1,
843                          Register dst2,
844                          Register heap_number_map,
845                          Register scratch1,
846                          Register scratch2,
847                          Label* not_number);
848 };
849 
850 
851 class StringDictionaryLookupStub: public CodeStub {
852  public:
853   enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
854 
StringDictionaryLookupStub(LookupMode mode)855   explicit StringDictionaryLookupStub(LookupMode mode) : mode_(mode) { }
856 
857   void Generate(MacroAssembler* masm);
858 
859   static void GenerateNegativeLookup(MacroAssembler* masm,
860                                      Label* miss,
861                                      Label* done,
862                                      Register receiver,
863                                      Register properties,
864                                      Handle<String> name,
865                                      Register scratch0);
866 
867   static void GeneratePositiveLookup(MacroAssembler* masm,
868                                      Label* miss,
869                                      Label* done,
870                                      Register elements,
871                                      Register name,
872                                      Register r0,
873                                      Register r1);
874 
SometimesSetsUpAFrame()875   virtual bool SometimesSetsUpAFrame() { return false; }
876 
877  private:
878   static const int kInlinedProbes = 4;
879   static const int kTotalProbes = 20;
880 
881   static const int kCapacityOffset =
882       StringDictionary::kHeaderSize +
883       StringDictionary::kCapacityIndex * kPointerSize;
884 
885   static const int kElementsStartOffset =
886       StringDictionary::kHeaderSize +
887       StringDictionary::kElementsStartIndex * kPointerSize;
888 
MajorKey()889   Major MajorKey() { return StringDictionaryLookup; }
890 
MinorKey()891   int MinorKey() {
892     return LookupModeBits::encode(mode_);
893   }
894 
895   class LookupModeBits: public BitField<LookupMode, 0, 1> {};
896 
897   LookupMode mode_;
898 };
899 
900 
901 } }  // namespace v8::internal
902 
903 #endif  // V8_ARM_CODE_STUBS_ARM_H_
904