• 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 void ArrayNativeCode(MacroAssembler* masm, Label* call_generic_code);
39 
40 
41 // Compute a transcendental math function natively, or call the
42 // TranscendentalCache runtime function.
43 class TranscendentalCacheStub: public PlatformCodeStub {
44  public:
45   enum ArgumentType {
46     TAGGED = 0 << TranscendentalCache::kTranscendentalTypeBits,
47     UNTAGGED = 1 << TranscendentalCache::kTranscendentalTypeBits
48   };
49 
TranscendentalCacheStub(TranscendentalCache::Type type,ArgumentType argument_type)50   TranscendentalCacheStub(TranscendentalCache::Type type,
51                           ArgumentType argument_type)
52       : type_(type), argument_type_(argument_type) { }
53   void Generate(MacroAssembler* masm);
54  private:
55   TranscendentalCache::Type type_;
56   ArgumentType argument_type_;
57   void GenerateCallCFunction(MacroAssembler* masm, Register scratch);
58 
MajorKey()59   Major MajorKey() { return TranscendentalCache; }
MinorKey()60   int MinorKey() { return type_ | argument_type_; }
61   Runtime::FunctionId RuntimeFunction();
62 };
63 
64 
65 class StoreBufferOverflowStub: public PlatformCodeStub {
66  public:
StoreBufferOverflowStub(SaveFPRegsMode save_fp)67   explicit StoreBufferOverflowStub(SaveFPRegsMode save_fp)
68       : save_doubles_(save_fp) {}
69 
70   void Generate(MacroAssembler* masm);
71 
72   static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate);
SometimesSetsUpAFrame()73   virtual bool SometimesSetsUpAFrame() { return false; }
74 
75  private:
76   SaveFPRegsMode save_doubles_;
77 
MajorKey()78   Major MajorKey() { return StoreBufferOverflow; }
MinorKey()79   int MinorKey() { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; }
80 };
81 
82 
83 class StringHelper : public AllStatic {
84  public:
85   // Generate code for copying characters using a simple loop. This should only
86   // be used in places where the number of characters is small and the
87   // additional setup and checking in GenerateCopyCharactersLong adds too much
88   // overhead. Copying of overlapping regions is not supported.
89   // Dest register ends at the position after the last character written.
90   static void GenerateCopyCharacters(MacroAssembler* masm,
91                                      Register dest,
92                                      Register src,
93                                      Register count,
94                                      Register scratch,
95                                      bool ascii);
96 
97   // Generate code for copying a large number of characters. This function
98   // is allowed to spend extra time setting up conditions to make copying
99   // faster. Copying of overlapping regions is not supported.
100   // Dest register ends at the position after the last character written.
101   static void GenerateCopyCharactersLong(MacroAssembler* masm,
102                                          Register dest,
103                                          Register src,
104                                          Register count,
105                                          Register scratch1,
106                                          Register scratch2,
107                                          Register scratch3,
108                                          Register scratch4,
109                                          Register scratch5,
110                                          int flags);
111 
112 
113   // Probe the string table for a two character string. If the string is
114   // not found by probing a jump to the label not_found is performed. This jump
115   // does not guarantee that the string is not in the string table. If the
116   // string is found the code falls through with the string in register r0.
117   // Contents of both c1 and c2 registers are modified. At the exit c1 is
118   // guaranteed to contain halfword with low and high bytes equal to
119   // initial contents of c1 and c2 respectively.
120   static void GenerateTwoCharacterStringTableProbe(MacroAssembler* masm,
121                                                    Register c1,
122                                                    Register c2,
123                                                    Register scratch1,
124                                                    Register scratch2,
125                                                    Register scratch3,
126                                                    Register scratch4,
127                                                    Register scratch5,
128                                                    Label* not_found);
129 
130   // Generate string hash.
131   static void GenerateHashInit(MacroAssembler* masm,
132                                Register hash,
133                                Register character);
134 
135   static void GenerateHashAddCharacter(MacroAssembler* masm,
136                                        Register hash,
137                                        Register character);
138 
139   static void GenerateHashGetHash(MacroAssembler* masm,
140                                   Register hash);
141 
142  private:
143   DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
144 };
145 
146 
147 class StringAddStub: public PlatformCodeStub {
148  public:
StringAddStub(StringAddFlags flags)149   explicit StringAddStub(StringAddFlags flags) : flags_(flags) {}
150 
151  private:
MajorKey()152   Major MajorKey() { return StringAdd; }
MinorKey()153   int MinorKey() { return flags_; }
154 
155   void Generate(MacroAssembler* masm);
156 
157   void GenerateConvertArgument(MacroAssembler* masm,
158                                int stack_offset,
159                                Register arg,
160                                Register scratch1,
161                                Register scratch2,
162                                Register scratch3,
163                                Register scratch4,
164                                Label* slow);
165 
166   void GenerateRegisterArgsPush(MacroAssembler* masm);
167   void GenerateRegisterArgsPop(MacroAssembler* masm);
168 
169   const StringAddFlags flags_;
170 };
171 
172 
173 class SubStringStub: public PlatformCodeStub {
174  public:
SubStringStub()175   SubStringStub() {}
176 
177  private:
MajorKey()178   Major MajorKey() { return SubString; }
MinorKey()179   int MinorKey() { return 0; }
180 
181   void Generate(MacroAssembler* masm);
182 };
183 
184 
185 class StringCompareStub: public PlatformCodeStub {
186  public:
StringCompareStub()187   StringCompareStub() { }
188 
189   // Compare two flat ASCII strings and returns result in v0.
190   static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
191                                               Register left,
192                                               Register right,
193                                               Register scratch1,
194                                               Register scratch2,
195                                               Register scratch3,
196                                               Register scratch4);
197 
198   // Compares two flat ASCII strings for equality and returns result
199   // in v0.
200   static void GenerateFlatAsciiStringEquals(MacroAssembler* masm,
201                                             Register left,
202                                             Register right,
203                                             Register scratch1,
204                                             Register scratch2,
205                                             Register scratch3);
206 
207  private:
MajorKey()208   virtual Major MajorKey() { return StringCompare; }
MinorKey()209   virtual int MinorKey() { return 0; }
210   virtual void Generate(MacroAssembler* masm);
211 
212   static void GenerateAsciiCharsCompareLoop(MacroAssembler* masm,
213                                             Register left,
214                                             Register right,
215                                             Register length,
216                                             Register scratch1,
217                                             Register scratch2,
218                                             Register scratch3,
219                                             Label* chars_not_equal);
220 };
221 
222 
223 // This stub can convert a signed int32 to a heap number (double).  It does
224 // not work for int32s that are in Smi range!  No GC occurs during this stub
225 // so you don't have to set up the frame.
226 class WriteInt32ToHeapNumberStub : public PlatformCodeStub {
227  public:
WriteInt32ToHeapNumberStub(Register the_int,Register the_heap_number,Register scratch,Register scratch2)228   WriteInt32ToHeapNumberStub(Register the_int,
229                              Register the_heap_number,
230                              Register scratch,
231                              Register scratch2)
232       : the_int_(the_int),
233         the_heap_number_(the_heap_number),
234         scratch_(scratch),
235         sign_(scratch2) {
236     ASSERT(IntRegisterBits::is_valid(the_int_.code()));
237     ASSERT(HeapNumberRegisterBits::is_valid(the_heap_number_.code()));
238     ASSERT(ScratchRegisterBits::is_valid(scratch_.code()));
239     ASSERT(SignRegisterBits::is_valid(sign_.code()));
240   }
241 
242   static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate);
243 
244  private:
245   Register the_int_;
246   Register the_heap_number_;
247   Register scratch_;
248   Register sign_;
249 
250   // Minor key encoding in 16 bits.
251   class IntRegisterBits: public BitField<int, 0, 4> {};
252   class HeapNumberRegisterBits: public BitField<int, 4, 4> {};
253   class ScratchRegisterBits: public BitField<int, 8, 4> {};
254   class SignRegisterBits: public BitField<int, 12, 4> {};
255 
MajorKey()256   Major MajorKey() { return WriteInt32ToHeapNumber; }
MinorKey()257   int MinorKey() {
258     // Encode the parameters in a unique 16 bit value.
259     return IntRegisterBits::encode(the_int_.code())
260            | HeapNumberRegisterBits::encode(the_heap_number_.code())
261            | ScratchRegisterBits::encode(scratch_.code())
262            | SignRegisterBits::encode(sign_.code());
263   }
264 
265   void Generate(MacroAssembler* masm);
266 };
267 
268 
269 class RecordWriteStub: public PlatformCodeStub {
270  public:
RecordWriteStub(Register object,Register value,Register address,RememberedSetAction remembered_set_action,SaveFPRegsMode fp_mode)271   RecordWriteStub(Register object,
272                   Register value,
273                   Register address,
274                   RememberedSetAction remembered_set_action,
275                   SaveFPRegsMode fp_mode)
276       : object_(object),
277         value_(value),
278         address_(address),
279         remembered_set_action_(remembered_set_action),
280         save_fp_regs_mode_(fp_mode),
281         regs_(object,   // An input reg.
282               address,  // An input reg.
283               value) {  // One scratch reg.
284   }
285 
286   enum Mode {
287     STORE_BUFFER_ONLY,
288     INCREMENTAL,
289     INCREMENTAL_COMPACTION
290   };
291 
SometimesSetsUpAFrame()292   virtual bool SometimesSetsUpAFrame() { return false; }
293 
PatchBranchIntoNop(MacroAssembler * masm,int pos)294   static void PatchBranchIntoNop(MacroAssembler* masm, int pos) {
295     const unsigned offset = masm->instr_at(pos) & kImm16Mask;
296     masm->instr_at_put(pos, BNE | (zero_reg.code() << kRsShift) |
297         (zero_reg.code() << kRtShift) | (offset & kImm16Mask));
298     ASSERT(Assembler::IsBne(masm->instr_at(pos)));
299   }
300 
PatchNopIntoBranch(MacroAssembler * masm,int pos)301   static void PatchNopIntoBranch(MacroAssembler* masm, int pos) {
302     const unsigned offset = masm->instr_at(pos) & kImm16Mask;
303     masm->instr_at_put(pos, BEQ | (zero_reg.code() << kRsShift) |
304         (zero_reg.code() << kRtShift) | (offset & kImm16Mask));
305     ASSERT(Assembler::IsBeq(masm->instr_at(pos)));
306   }
307 
GetMode(Code * stub)308   static Mode GetMode(Code* stub) {
309     Instr first_instruction = Assembler::instr_at(stub->instruction_start());
310     Instr second_instruction = Assembler::instr_at(stub->instruction_start() +
311                                                    2 * Assembler::kInstrSize);
312 
313     if (Assembler::IsBeq(first_instruction)) {
314       return INCREMENTAL;
315     }
316 
317     ASSERT(Assembler::IsBne(first_instruction));
318 
319     if (Assembler::IsBeq(second_instruction)) {
320       return INCREMENTAL_COMPACTION;
321     }
322 
323     ASSERT(Assembler::IsBne(second_instruction));
324 
325     return STORE_BUFFER_ONLY;
326   }
327 
Patch(Code * stub,Mode mode)328   static void Patch(Code* stub, Mode mode) {
329     MacroAssembler masm(NULL,
330                         stub->instruction_start(),
331                         stub->instruction_size());
332     switch (mode) {
333       case STORE_BUFFER_ONLY:
334         ASSERT(GetMode(stub) == INCREMENTAL ||
335                GetMode(stub) == INCREMENTAL_COMPACTION);
336         PatchBranchIntoNop(&masm, 0);
337         PatchBranchIntoNop(&masm, 2 * Assembler::kInstrSize);
338         break;
339       case INCREMENTAL:
340         ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
341         PatchNopIntoBranch(&masm, 0);
342         break;
343       case INCREMENTAL_COMPACTION:
344         ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
345         PatchNopIntoBranch(&masm, 2 * Assembler::kInstrSize);
346         break;
347     }
348     ASSERT(GetMode(stub) == mode);
349     CPU::FlushICache(stub->instruction_start(), 4 * Assembler::kInstrSize);
350   }
351 
352  private:
353   // This is a helper class for freeing up 3 scratch registers.  The input is
354   // two registers that must be preserved and one scratch register provided by
355   // the caller.
356   class RegisterAllocation {
357    public:
RegisterAllocation(Register object,Register address,Register scratch0)358     RegisterAllocation(Register object,
359                        Register address,
360                        Register scratch0)
361         : object_(object),
362           address_(address),
363           scratch0_(scratch0) {
364       ASSERT(!AreAliased(scratch0, object, address, no_reg));
365       scratch1_ = GetRegisterThatIsNotOneOf(object_, address_, scratch0_);
366     }
367 
Save(MacroAssembler * masm)368     void Save(MacroAssembler* masm) {
369       ASSERT(!AreAliased(object_, address_, scratch1_, scratch0_));
370       // We don't have to save scratch0_ because it was given to us as
371       // a scratch register.
372       masm->push(scratch1_);
373     }
374 
Restore(MacroAssembler * masm)375     void Restore(MacroAssembler* masm) {
376       masm->pop(scratch1_);
377     }
378 
379     // If we have to call into C then we need to save and restore all caller-
380     // saved registers that were not already preserved.  The scratch registers
381     // will be restored by other means so we don't bother pushing them here.
SaveCallerSaveRegisters(MacroAssembler * masm,SaveFPRegsMode mode)382     void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
383       masm->MultiPush((kJSCallerSaved | ra.bit()) & ~scratch1_.bit());
384       if (mode == kSaveFPRegs) {
385         masm->MultiPushFPU(kCallerSavedFPU);
386       }
387     }
388 
RestoreCallerSaveRegisters(MacroAssembler * masm,SaveFPRegsMode mode)389     inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
390                                            SaveFPRegsMode mode) {
391       if (mode == kSaveFPRegs) {
392         masm->MultiPopFPU(kCallerSavedFPU);
393       }
394       masm->MultiPop((kJSCallerSaved | ra.bit()) & ~scratch1_.bit());
395     }
396 
object()397     inline Register object() { return object_; }
address()398     inline Register address() { return address_; }
scratch0()399     inline Register scratch0() { return scratch0_; }
scratch1()400     inline Register scratch1() { return scratch1_; }
401 
402    private:
403     Register object_;
404     Register address_;
405     Register scratch0_;
406     Register scratch1_;
407 
408     friend class RecordWriteStub;
409   };
410 
411   enum OnNoNeedToInformIncrementalMarker {
412     kReturnOnNoNeedToInformIncrementalMarker,
413     kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
414   };
415 
416   void Generate(MacroAssembler* masm);
417   void GenerateIncremental(MacroAssembler* masm, Mode mode);
418   void CheckNeedsToInformIncrementalMarker(
419       MacroAssembler* masm,
420       OnNoNeedToInformIncrementalMarker on_no_need,
421       Mode mode);
422   void InformIncrementalMarker(MacroAssembler* masm, Mode mode);
423 
MajorKey()424   Major MajorKey() { return RecordWrite; }
425 
MinorKey()426   int MinorKey() {
427     return ObjectBits::encode(object_.code()) |
428         ValueBits::encode(value_.code()) |
429         AddressBits::encode(address_.code()) |
430         RememberedSetActionBits::encode(remembered_set_action_) |
431         SaveFPRegsModeBits::encode(save_fp_regs_mode_);
432   }
433 
Activate(Code * code)434   void Activate(Code* code) {
435     code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
436   }
437 
438   class ObjectBits: public BitField<int, 0, 5> {};
439   class ValueBits: public BitField<int, 5, 5> {};
440   class AddressBits: public BitField<int, 10, 5> {};
441   class RememberedSetActionBits: public BitField<RememberedSetAction, 15, 1> {};
442   class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 16, 1> {};
443 
444   Register object_;
445   Register value_;
446   Register address_;
447   RememberedSetAction remembered_set_action_;
448   SaveFPRegsMode save_fp_regs_mode_;
449   Label slow_;
450   RegisterAllocation regs_;
451 };
452 
453 
454 // Trampoline stub to call into native code. To call safely into native code
455 // in the presence of compacting GC (which can move code objects) we need to
456 // keep the code which called into native pinned in the memory. Currently the
457 // simplest approach is to generate such stub early enough so it can never be
458 // moved by GC
459 class DirectCEntryStub: public PlatformCodeStub {
460  public:
DirectCEntryStub()461   DirectCEntryStub() {}
462   void Generate(MacroAssembler* masm);
463   void GenerateCall(MacroAssembler* masm, Register target);
464 
465  private:
MajorKey()466   Major MajorKey() { return DirectCEntry; }
MinorKey()467   int MinorKey() { return 0; }
468 
NeedsImmovableCode()469   bool NeedsImmovableCode() { return true; }
470 };
471 
472 
473 class NameDictionaryLookupStub: public PlatformCodeStub {
474  public:
475   enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
476 
NameDictionaryLookupStub(LookupMode mode)477   explicit NameDictionaryLookupStub(LookupMode mode) : mode_(mode) { }
478 
479   void Generate(MacroAssembler* masm);
480 
481   static void GenerateNegativeLookup(MacroAssembler* masm,
482                                      Label* miss,
483                                      Label* done,
484                                      Register receiver,
485                                      Register properties,
486                                      Handle<Name> name,
487                                      Register scratch0);
488 
489   static void GeneratePositiveLookup(MacroAssembler* masm,
490                                      Label* miss,
491                                      Label* done,
492                                      Register elements,
493                                      Register name,
494                                      Register r0,
495                                      Register r1);
496 
SometimesSetsUpAFrame()497   virtual bool SometimesSetsUpAFrame() { return false; }
498 
499  private:
500   static const int kInlinedProbes = 4;
501   static const int kTotalProbes = 20;
502 
503   static const int kCapacityOffset =
504       NameDictionary::kHeaderSize +
505       NameDictionary::kCapacityIndex * kPointerSize;
506 
507   static const int kElementsStartOffset =
508       NameDictionary::kHeaderSize +
509       NameDictionary::kElementsStartIndex * kPointerSize;
510 
MajorKey()511   Major MajorKey() { return NameDictionaryLookup; }
512 
MinorKey()513   int MinorKey() {
514     return LookupModeBits::encode(mode_);
515   }
516 
517   class LookupModeBits: public BitField<LookupMode, 0, 1> {};
518 
519   LookupMode mode_;
520 };
521 
522 
523 } }  // namespace v8::internal
524 
525 #endif  // V8_MIPS_CODE_STUBS_ARM_H_
526