• 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_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:
42   enum ArgumentType {
43     TAGGED = 0 << TranscendentalCache::kTranscendentalTypeBits,
44     UNTAGGED = 1 << TranscendentalCache::kTranscendentalTypeBits
45   };
46 
TranscendentalCacheStub(TranscendentalCache::Type type,ArgumentType argument_type)47   TranscendentalCacheStub(TranscendentalCache::Type type,
48                           ArgumentType argument_type)
49       : type_(type), argument_type_(argument_type) { }
50   void Generate(MacroAssembler* masm);
51  private:
52   TranscendentalCache::Type type_;
53   ArgumentType argument_type_;
54   void GenerateCallCFunction(MacroAssembler* masm, Register scratch);
55 
MajorKey()56   Major MajorKey() { return TranscendentalCache; }
MinorKey()57   int MinorKey() { return type_ | argument_type_; }
58   Runtime::FunctionId RuntimeFunction();
59 };
60 
61 
62 class StoreBufferOverflowStub: public CodeStub {
63  public:
StoreBufferOverflowStub(SaveFPRegsMode save_fp)64   explicit StoreBufferOverflowStub(SaveFPRegsMode save_fp)
65       : save_doubles_(save_fp) { }
66 
67   void Generate(MacroAssembler* masm);
68 
69   virtual bool IsPregenerated();
70   static void GenerateFixedRegStubsAheadOfTime();
SometimesSetsUpAFrame()71   virtual bool SometimesSetsUpAFrame() { return false; }
72 
73  private:
74   SaveFPRegsMode save_doubles_;
75 
MajorKey()76   Major MajorKey() { return StoreBufferOverflow; }
MinorKey()77   int MinorKey() { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; }
78 };
79 
80 
81 class UnaryOpStub: public CodeStub {
82  public:
83   UnaryOpStub(Token::Value op,
84               UnaryOverwriteMode mode,
85               UnaryOpIC::TypeInfo operand_type = UnaryOpIC::UNINITIALIZED)
op_(op)86       : op_(op),
87         mode_(mode),
88         operand_type_(operand_type) {
89   }
90 
91  private:
92   Token::Value op_;
93   UnaryOverwriteMode mode_;
94 
95   // Operand type information determined at runtime.
96   UnaryOpIC::TypeInfo operand_type_;
97 
98   virtual void PrintName(StringStream* stream);
99 
100   class ModeBits: public BitField<UnaryOverwriteMode, 0, 1> {};
101   class OpBits: public BitField<Token::Value, 1, 7> {};
102   class OperandTypeInfoBits: public BitField<UnaryOpIC::TypeInfo, 8, 3> {};
103 
MajorKey()104   Major MajorKey() { return UnaryOp; }
MinorKey()105   int MinorKey() {
106     return ModeBits::encode(mode_)
107            | OpBits::encode(op_)
108            | OperandTypeInfoBits::encode(operand_type_);
109   }
110 
111   // Note: A lot of the helper functions below will vanish when we use virtual
112   // function instead of switch more often.
113   void Generate(MacroAssembler* masm);
114 
115   void GenerateTypeTransition(MacroAssembler* masm);
116 
117   void GenerateSmiStub(MacroAssembler* masm);
118   void GenerateSmiStubSub(MacroAssembler* masm);
119   void GenerateSmiStubBitNot(MacroAssembler* masm);
120   void GenerateSmiCodeSub(MacroAssembler* masm, Label* non_smi, Label* slow);
121   void GenerateSmiCodeBitNot(MacroAssembler* masm, Label* slow);
122 
123   void GenerateHeapNumberStub(MacroAssembler* masm);
124   void GenerateHeapNumberStubSub(MacroAssembler* masm);
125   void GenerateHeapNumberStubBitNot(MacroAssembler* masm);
126   void GenerateHeapNumberCodeSub(MacroAssembler* masm, Label* slow);
127   void GenerateHeapNumberCodeBitNot(MacroAssembler* masm, Label* slow);
128 
129   void GenerateGenericStub(MacroAssembler* masm);
130   void GenerateGenericStubSub(MacroAssembler* masm);
131   void GenerateGenericStubBitNot(MacroAssembler* masm);
132   void GenerateGenericCodeFallback(MacroAssembler* masm);
133 
GetCodeKind()134   virtual int GetCodeKind() { return Code::UNARY_OP_IC; }
135 
GetICState()136   virtual InlineCacheState GetICState() {
137     return UnaryOpIC::ToState(operand_type_);
138   }
139 
FinishCode(Handle<Code> code)140   virtual void FinishCode(Handle<Code> code) {
141     code->set_unary_op_type(operand_type_);
142   }
143 };
144 
145 
146 class BinaryOpStub: public CodeStub {
147  public:
BinaryOpStub(Token::Value op,OverwriteMode mode)148   BinaryOpStub(Token::Value op, OverwriteMode mode)
149       : op_(op),
150         mode_(mode),
151         operands_type_(BinaryOpIC::UNINITIALIZED),
152         result_type_(BinaryOpIC::UNINITIALIZED) {
153     use_fpu_ = CpuFeatures::IsSupported(FPU);
154     ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
155   }
156 
157   BinaryOpStub(
158       int key,
159       BinaryOpIC::TypeInfo operands_type,
160       BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED)
op_(OpBits::decode (key))161       : op_(OpBits::decode(key)),
162         mode_(ModeBits::decode(key)),
163         use_fpu_(FPUBits::decode(key)),
164         operands_type_(operands_type),
165         result_type_(result_type) { }
166 
167  private:
168   enum SmiCodeGenerateHeapNumberResults {
169     ALLOW_HEAPNUMBER_RESULTS,
170     NO_HEAPNUMBER_RESULTS
171   };
172 
173   Token::Value op_;
174   OverwriteMode mode_;
175   bool use_fpu_;
176 
177   // Operand type information determined at runtime.
178   BinaryOpIC::TypeInfo operands_type_;
179   BinaryOpIC::TypeInfo result_type_;
180 
181   virtual void PrintName(StringStream* stream);
182 
183   // Minor key encoding in 16 bits RRRTTTVOOOOOOOMM.
184   class ModeBits: public BitField<OverwriteMode, 0, 2> {};
185   class OpBits: public BitField<Token::Value, 2, 7> {};
186   class FPUBits: public BitField<bool, 9, 1> {};
187   class OperandTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 10, 3> {};
188   class ResultTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 13, 3> {};
189 
MajorKey()190   Major MajorKey() { return BinaryOp; }
MinorKey()191   int MinorKey() {
192     return OpBits::encode(op_)
193            | ModeBits::encode(mode_)
194            | FPUBits::encode(use_fpu_)
195            | OperandTypeInfoBits::encode(operands_type_)
196            | ResultTypeInfoBits::encode(result_type_);
197   }
198 
199   void Generate(MacroAssembler* masm);
200   void GenerateGeneric(MacroAssembler* masm);
201   void GenerateSmiSmiOperation(MacroAssembler* masm);
202   void GenerateFPOperation(MacroAssembler* masm,
203                            bool smi_operands,
204                            Label* not_numbers,
205                            Label* gc_required);
206   void GenerateSmiCode(MacroAssembler* masm,
207                        Label* use_runtime,
208                        Label* gc_required,
209                        SmiCodeGenerateHeapNumberResults heapnumber_results);
210   void GenerateLoadArguments(MacroAssembler* masm);
211   void GenerateReturn(MacroAssembler* masm);
212   void GenerateUninitializedStub(MacroAssembler* masm);
213   void GenerateSmiStub(MacroAssembler* masm);
214   void GenerateInt32Stub(MacroAssembler* masm);
215   void GenerateHeapNumberStub(MacroAssembler* masm);
216   void GenerateOddballStub(MacroAssembler* masm);
217   void GenerateStringStub(MacroAssembler* masm);
218   void GenerateBothStringStub(MacroAssembler* masm);
219   void GenerateGenericStub(MacroAssembler* masm);
220   void GenerateAddStrings(MacroAssembler* masm);
221   void GenerateCallRuntime(MacroAssembler* masm);
222 
223   void GenerateHeapResultAllocation(MacroAssembler* masm,
224                                     Register result,
225                                     Register heap_number_map,
226                                     Register scratch1,
227                                     Register scratch2,
228                                     Label* gc_required);
229   void GenerateRegisterArgsPush(MacroAssembler* masm);
230   void GenerateTypeTransition(MacroAssembler* masm);
231   void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm);
232 
GetCodeKind()233   virtual int GetCodeKind() { return Code::BINARY_OP_IC; }
234 
GetICState()235   virtual InlineCacheState GetICState() {
236     return BinaryOpIC::ToState(operands_type_);
237   }
238 
FinishCode(Handle<Code> code)239   virtual void FinishCode(Handle<Code> code) {
240     code->set_binary_op_type(operands_type_);
241     code->set_binary_op_result_type(result_type_);
242   }
243 
244   friend class CodeGenerator;
245 };
246 
247 
248 class StringHelper : public AllStatic {
249  public:
250   // Generate code for copying characters using a simple loop. This should only
251   // be used in places where the number of characters is small and the
252   // additional setup and checking in GenerateCopyCharactersLong adds too much
253   // overhead. Copying of overlapping regions is not supported.
254   // Dest register ends at the position after the last character written.
255   static void GenerateCopyCharacters(MacroAssembler* masm,
256                                      Register dest,
257                                      Register src,
258                                      Register count,
259                                      Register scratch,
260                                      bool ascii);
261 
262   // Generate code for copying a large number of characters. This function
263   // is allowed to spend extra time setting up conditions to make copying
264   // faster. Copying of overlapping regions is not supported.
265   // Dest register ends at the position after the last character written.
266   static void GenerateCopyCharactersLong(MacroAssembler* masm,
267                                          Register dest,
268                                          Register src,
269                                          Register count,
270                                          Register scratch1,
271                                          Register scratch2,
272                                          Register scratch3,
273                                          Register scratch4,
274                                          Register scratch5,
275                                          int flags);
276 
277 
278   // Probe the symbol table for a two character string. If the string is
279   // not found by probing a jump to the label not_found is performed. This jump
280   // does not guarantee that the string is not in the symbol table. If the
281   // string is found the code falls through with the string in register r0.
282   // Contents of both c1 and c2 registers are modified. At the exit c1 is
283   // guaranteed to contain halfword with low and high bytes equal to
284   // initial contents of c1 and c2 respectively.
285   static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
286                                                    Register c1,
287                                                    Register c2,
288                                                    Register scratch1,
289                                                    Register scratch2,
290                                                    Register scratch3,
291                                                    Register scratch4,
292                                                    Register scratch5,
293                                                    Label* not_found);
294 
295   // Generate string hash.
296   static void GenerateHashInit(MacroAssembler* masm,
297                                Register hash,
298                                Register character);
299 
300   static void GenerateHashAddCharacter(MacroAssembler* masm,
301                                        Register hash,
302                                        Register character);
303 
304   static void GenerateHashGetHash(MacroAssembler* masm,
305                                   Register hash);
306 
307  private:
308   DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
309 };
310 
311 
312 // Flag that indicates how to generate code for the stub StringAddStub.
313 enum StringAddFlags {
314   NO_STRING_ADD_FLAGS = 0,
315   // Omit left string check in stub (left is definitely a string).
316   NO_STRING_CHECK_LEFT_IN_STUB = 1 << 0,
317   // Omit right string check in stub (right is definitely a string).
318   NO_STRING_CHECK_RIGHT_IN_STUB = 1 << 1,
319   // Omit both string checks in stub.
320   NO_STRING_CHECK_IN_STUB =
321       NO_STRING_CHECK_LEFT_IN_STUB | NO_STRING_CHECK_RIGHT_IN_STUB
322 };
323 
324 
325 class StringAddStub: public CodeStub {
326  public:
StringAddStub(StringAddFlags flags)327   explicit StringAddStub(StringAddFlags flags) : flags_(flags) {}
328 
329  private:
MajorKey()330   Major MajorKey() { return StringAdd; }
MinorKey()331   int MinorKey() { return flags_; }
332 
333   void Generate(MacroAssembler* masm);
334 
335   void GenerateConvertArgument(MacroAssembler* masm,
336                                int stack_offset,
337                                Register arg,
338                                Register scratch1,
339                                Register scratch2,
340                                Register scratch3,
341                                Register scratch4,
342                                Label* slow);
343 
344   const StringAddFlags flags_;
345 };
346 
347 
348 class SubStringStub: public CodeStub {
349  public:
SubStringStub()350   SubStringStub() {}
351 
352  private:
MajorKey()353   Major MajorKey() { return SubString; }
MinorKey()354   int MinorKey() { return 0; }
355 
356   void Generate(MacroAssembler* masm);
357 };
358 
359 
360 class StringCompareStub: public CodeStub {
361  public:
StringCompareStub()362   StringCompareStub() { }
363 
364   // Compare two flat ASCII strings and returns result in v0.
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 v0.
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                                             Register scratch3,
394                                             Label* chars_not_equal);
395 };
396 
397 
398 // This stub can convert a signed int32 to a heap number (double).  It does
399 // not work for int32s that are in Smi range!  No GC occurs during this stub
400 // so you don't have to set up the frame.
401 class WriteInt32ToHeapNumberStub : public CodeStub {
402  public:
WriteInt32ToHeapNumberStub(Register the_int,Register the_heap_number,Register scratch,Register scratch2)403   WriteInt32ToHeapNumberStub(Register the_int,
404                              Register the_heap_number,
405                              Register scratch,
406                              Register scratch2)
407       : the_int_(the_int),
408         the_heap_number_(the_heap_number),
409         scratch_(scratch),
410         sign_(scratch2) {
411     ASSERT(IntRegisterBits::is_valid(the_int_.code()));
412     ASSERT(HeapNumberRegisterBits::is_valid(the_heap_number_.code()));
413     ASSERT(ScratchRegisterBits::is_valid(scratch_.code()));
414     ASSERT(SignRegisterBits::is_valid(sign_.code()));
415   }
416 
417   bool IsPregenerated();
418   static void GenerateFixedRegStubsAheadOfTime();
419 
420  private:
421   Register the_int_;
422   Register the_heap_number_;
423   Register scratch_;
424   Register sign_;
425 
426   // Minor key encoding in 16 bits.
427   class IntRegisterBits: public BitField<int, 0, 4> {};
428   class HeapNumberRegisterBits: public BitField<int, 4, 4> {};
429   class ScratchRegisterBits: public BitField<int, 8, 4> {};
430   class SignRegisterBits: public BitField<int, 12, 4> {};
431 
MajorKey()432   Major MajorKey() { return WriteInt32ToHeapNumber; }
MinorKey()433   int MinorKey() {
434     // Encode the parameters in a unique 16 bit value.
435     return IntRegisterBits::encode(the_int_.code())
436            | HeapNumberRegisterBits::encode(the_heap_number_.code())
437            | ScratchRegisterBits::encode(scratch_.code())
438            | SignRegisterBits::encode(sign_.code());
439   }
440 
441   void Generate(MacroAssembler* masm);
442 };
443 
444 
445 class NumberToStringStub: public CodeStub {
446  public:
NumberToStringStub()447   NumberToStringStub() { }
448 
449   // Generate code to do a lookup in the number string cache. If the number in
450   // the register object is found in the cache the generated code falls through
451   // with the result in the result register. The object and the result register
452   // can be the same. If the number is not found in the cache the code jumps to
453   // the label not_found with only the content of register object unchanged.
454   static void GenerateLookupNumberStringCache(MacroAssembler* masm,
455                                               Register object,
456                                               Register result,
457                                               Register scratch1,
458                                               Register scratch2,
459                                               Register scratch3,
460                                               bool object_is_smi,
461                                               Label* not_found);
462 
463  private:
MajorKey()464   Major MajorKey() { return NumberToString; }
MinorKey()465   int MinorKey() { return 0; }
466 
467   void Generate(MacroAssembler* masm);
468 };
469 
470 
471 class RecordWriteStub: public CodeStub {
472  public:
RecordWriteStub(Register object,Register value,Register address,RememberedSetAction remembered_set_action,SaveFPRegsMode fp_mode)473   RecordWriteStub(Register object,
474                   Register value,
475                   Register address,
476                   RememberedSetAction remembered_set_action,
477                   SaveFPRegsMode fp_mode)
478       : object_(object),
479         value_(value),
480         address_(address),
481         remembered_set_action_(remembered_set_action),
482         save_fp_regs_mode_(fp_mode),
483         regs_(object,   // An input reg.
484               address,  // An input reg.
485               value) {  // One scratch reg.
486   }
487 
488   enum Mode {
489     STORE_BUFFER_ONLY,
490     INCREMENTAL,
491     INCREMENTAL_COMPACTION
492   };
493 
494   virtual bool IsPregenerated();
495   static void GenerateFixedRegStubsAheadOfTime();
SometimesSetsUpAFrame()496   virtual bool SometimesSetsUpAFrame() { return false; }
497 
PatchBranchIntoNop(MacroAssembler * masm,int pos)498   static void PatchBranchIntoNop(MacroAssembler* masm, int pos) {
499     const unsigned offset = masm->instr_at(pos) & kImm16Mask;
500     masm->instr_at_put(pos, BNE | (zero_reg.code() << kRsShift) |
501         (zero_reg.code() << kRtShift) | (offset & kImm16Mask));
502     ASSERT(Assembler::IsBne(masm->instr_at(pos)));
503   }
504 
PatchNopIntoBranch(MacroAssembler * masm,int pos)505   static void PatchNopIntoBranch(MacroAssembler* masm, int pos) {
506     const unsigned offset = masm->instr_at(pos) & kImm16Mask;
507     masm->instr_at_put(pos, BEQ | (zero_reg.code() << kRsShift) |
508         (zero_reg.code() << kRtShift) | (offset & kImm16Mask));
509     ASSERT(Assembler::IsBeq(masm->instr_at(pos)));
510   }
511 
GetMode(Code * stub)512   static Mode GetMode(Code* stub) {
513     Instr first_instruction = Assembler::instr_at(stub->instruction_start());
514     Instr second_instruction = Assembler::instr_at(stub->instruction_start() +
515                                                    2 * Assembler::kInstrSize);
516 
517     if (Assembler::IsBeq(first_instruction)) {
518       return INCREMENTAL;
519     }
520 
521     ASSERT(Assembler::IsBne(first_instruction));
522 
523     if (Assembler::IsBeq(second_instruction)) {
524       return INCREMENTAL_COMPACTION;
525     }
526 
527     ASSERT(Assembler::IsBne(second_instruction));
528 
529     return STORE_BUFFER_ONLY;
530   }
531 
Patch(Code * stub,Mode mode)532   static void Patch(Code* stub, Mode mode) {
533     MacroAssembler masm(NULL,
534                         stub->instruction_start(),
535                         stub->instruction_size());
536     switch (mode) {
537       case STORE_BUFFER_ONLY:
538         ASSERT(GetMode(stub) == INCREMENTAL ||
539                GetMode(stub) == INCREMENTAL_COMPACTION);
540         PatchBranchIntoNop(&masm, 0);
541         PatchBranchIntoNop(&masm, 2 * Assembler::kInstrSize);
542         break;
543       case INCREMENTAL:
544         ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
545         PatchNopIntoBranch(&masm, 0);
546         break;
547       case INCREMENTAL_COMPACTION:
548         ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
549         PatchNopIntoBranch(&masm, 2 * Assembler::kInstrSize);
550         break;
551     }
552     ASSERT(GetMode(stub) == mode);
553     CPU::FlushICache(stub->instruction_start(), 4 * Assembler::kInstrSize);
554   }
555 
556  private:
557   // This is a helper class for freeing up 3 scratch registers.  The input is
558   // two registers that must be preserved and one scratch register provided by
559   // the caller.
560   class RegisterAllocation {
561    public:
RegisterAllocation(Register object,Register address,Register scratch0)562     RegisterAllocation(Register object,
563                        Register address,
564                        Register scratch0)
565         : object_(object),
566           address_(address),
567           scratch0_(scratch0) {
568       ASSERT(!AreAliased(scratch0, object, address, no_reg));
569       scratch1_ = GetRegThatIsNotOneOf(object_, address_, scratch0_);
570     }
571 
Save(MacroAssembler * masm)572     void Save(MacroAssembler* masm) {
573       ASSERT(!AreAliased(object_, address_, scratch1_, scratch0_));
574       // We don't have to save scratch0_ because it was given to us as
575       // a scratch register.
576       masm->push(scratch1_);
577     }
578 
Restore(MacroAssembler * masm)579     void Restore(MacroAssembler* masm) {
580       masm->pop(scratch1_);
581     }
582 
583     // If we have to call into C then we need to save and restore all caller-
584     // saved registers that were not already preserved.  The scratch registers
585     // will be restored by other means so we don't bother pushing them here.
SaveCallerSaveRegisters(MacroAssembler * masm,SaveFPRegsMode mode)586     void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
587       masm->MultiPush((kJSCallerSaved | ra.bit()) & ~scratch1_.bit());
588       if (mode == kSaveFPRegs) {
589         CpuFeatures::Scope scope(FPU);
590         masm->MultiPushFPU(kCallerSavedFPU);
591       }
592     }
593 
RestoreCallerSaveRegisters(MacroAssembler * masm,SaveFPRegsMode mode)594     inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
595                                            SaveFPRegsMode mode) {
596       if (mode == kSaveFPRegs) {
597         CpuFeatures::Scope scope(FPU);
598         masm->MultiPopFPU(kCallerSavedFPU);
599       }
600       masm->MultiPop((kJSCallerSaved | ra.bit()) & ~scratch1_.bit());
601     }
602 
object()603     inline Register object() { return object_; }
address()604     inline Register address() { return address_; }
scratch0()605     inline Register scratch0() { return scratch0_; }
scratch1()606     inline Register scratch1() { return scratch1_; }
607 
608    private:
609     Register object_;
610     Register address_;
611     Register scratch0_;
612     Register scratch1_;
613 
GetRegThatIsNotOneOf(Register r1,Register r2,Register r3)614     Register GetRegThatIsNotOneOf(Register r1,
615                                   Register r2,
616                                   Register r3) {
617       for (int i = 0; i < Register::kNumAllocatableRegisters; i++) {
618         Register candidate = Register::FromAllocationIndex(i);
619         if (candidate.is(r1)) continue;
620         if (candidate.is(r2)) continue;
621         if (candidate.is(r3)) continue;
622         return candidate;
623       }
624       UNREACHABLE();
625       return no_reg;
626     }
627     friend class RecordWriteStub;
628   };
629 
630   enum OnNoNeedToInformIncrementalMarker {
631     kReturnOnNoNeedToInformIncrementalMarker,
632     kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
633   };
634 
635   void Generate(MacroAssembler* masm);
636   void GenerateIncremental(MacroAssembler* masm, Mode mode);
637   void CheckNeedsToInformIncrementalMarker(
638       MacroAssembler* masm,
639       OnNoNeedToInformIncrementalMarker on_no_need,
640       Mode mode);
641   void InformIncrementalMarker(MacroAssembler* masm, Mode mode);
642 
MajorKey()643   Major MajorKey() { return RecordWrite; }
644 
MinorKey()645   int MinorKey() {
646     return ObjectBits::encode(object_.code()) |
647         ValueBits::encode(value_.code()) |
648         AddressBits::encode(address_.code()) |
649         RememberedSetActionBits::encode(remembered_set_action_) |
650         SaveFPRegsModeBits::encode(save_fp_regs_mode_);
651   }
652 
Activate(Code * code)653   void Activate(Code* code) {
654     code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
655   }
656 
657   class ObjectBits: public BitField<int, 0, 5> {};
658   class ValueBits: public BitField<int, 5, 5> {};
659   class AddressBits: public BitField<int, 10, 5> {};
660   class RememberedSetActionBits: public BitField<RememberedSetAction, 15, 1> {};
661   class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 16, 1> {};
662 
663   Register object_;
664   Register value_;
665   Register address_;
666   RememberedSetAction remembered_set_action_;
667   SaveFPRegsMode save_fp_regs_mode_;
668   Label slow_;
669   RegisterAllocation regs_;
670 };
671 
672 
673 // Enter C code from generated RegExp code in a way that allows
674 // the C code to fix the return address in case of a GC.
675 // Currently only needed on ARM and MIPS.
676 class RegExpCEntryStub: public CodeStub {
677  public:
RegExpCEntryStub()678   RegExpCEntryStub() {}
~RegExpCEntryStub()679   virtual ~RegExpCEntryStub() {}
680   void Generate(MacroAssembler* masm);
681 
682  private:
MajorKey()683   Major MajorKey() { return RegExpCEntry; }
MinorKey()684   int MinorKey() { return 0; }
685 
NeedsImmovableCode()686   bool NeedsImmovableCode() { return true; }
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,
699                                 ExternalReference function);
700   void GenerateCall(MacroAssembler* masm, Register target);
701 
702  private:
MajorKey()703   Major MajorKey() { return DirectCEntry; }
MinorKey()704   int MinorKey() { return 0; }
705 
NeedsImmovableCode()706   bool NeedsImmovableCode() { return true; }
707 };
708 
709 class FloatingPointHelper : public AllStatic {
710  public:
711   enum Destination {
712     kFPURegisters,
713     kCoreRegisters
714   };
715 
716 
717   // Loads smis from a0 and a1 (right and left in binary operations) into
718   // floating point registers. Depending on the destination the values ends up
719   // either f14 and f12 or in a2/a3 and a0/a1 respectively. If the destination
720   // is floating point registers FPU must be supported. If core registers are
721   // requested when FPU is supported f12 and f14 will be scratched.
722   static void LoadSmis(MacroAssembler* masm,
723                        Destination destination,
724                        Register scratch1,
725                        Register scratch2);
726 
727   // Loads objects from a0 and a1 (right and left in binary operations) into
728   // floating point registers. Depending on the destination the values ends up
729   // either f14 and f12 or in a2/a3 and a0/a1 respectively. If the destination
730   // is floating point registers FPU must be supported. If core registers are
731   // requested when FPU is supported f12 and f14 will still be scratched. If
732   // either a0 or a1 is not a number (not smi and not heap number object) the
733   // not_number label is jumped to with a0 and a1 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                                    FPURegister 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                                  FPURegister double_dst,
762                                  Register dst1,
763                                  Register dst2,
764                                  Register scratch2,
765                                  FPURegister 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                                       FPURegister double_dst,
776                                       Register dst1,
777                                       Register dst2,
778                                       Register heap_number_map,
779                                       Register scratch1,
780                                       Register scratch2,
781                                       FPURegister 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 FPU 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                                 FPURegister double_scratch,
798                                 Label* not_int32);
799 
800   // Generate non FPU 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 FPU is not supported.)
823   // This code never falls through, but returns with a heap number containing
824   // the result in v0.
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   // a0: Left value (least significant part of mantissa).
829   // a1: Left value (sign, exponent, top of mantissa).
830   // a2: Right value (least significant part of mantissa).
831   // a3: 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                          FPURegister 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_MIPS_CODE_STUBS_ARM_H_
904