• 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_IA32_CODE_STUBS_IA32_H_
29 #define V8_IA32_CODE_STUBS_IA32_H_
30 
31 #include "macro-assembler.h"
32 #include "code-stubs.h"
33 #include "ic-inl.h"
34 
35 namespace v8 {
36 namespace internal {
37 
38 
39 // Compute a transcendental math function natively, or call the
40 // TranscendentalCache runtime function.
41 class TranscendentalCacheStub: public CodeStub {
42  public:
43   enum ArgumentType {
44     TAGGED = 0,
45     UNTAGGED = 1 << TranscendentalCache::kTranscendentalTypeBits
46   };
47 
TranscendentalCacheStub(TranscendentalCache::Type type,ArgumentType argument_type)48   TranscendentalCacheStub(TranscendentalCache::Type type,
49                           ArgumentType argument_type)
50       : type_(type), argument_type_(argument_type) {}
51   void Generate(MacroAssembler* masm);
52   static void GenerateOperation(MacroAssembler* masm,
53                                 TranscendentalCache::Type type);
54  private:
55   TranscendentalCache::Type type_;
56   ArgumentType argument_type_;
57 
MajorKey()58   Major MajorKey() { return TranscendentalCache; }
MinorKey()59   int MinorKey() { return type_ | argument_type_; }
60   Runtime::FunctionId RuntimeFunction();
61 };
62 
63 
64 class StoreBufferOverflowStub: public CodeStub {
65  public:
StoreBufferOverflowStub(SaveFPRegsMode save_fp)66   explicit StoreBufferOverflowStub(SaveFPRegsMode save_fp)
67       : save_doubles_(save_fp) { }
68 
69   void Generate(MacroAssembler* masm);
70 
IsPregenerated()71   virtual bool IsPregenerated() { return true; }
72   static void GenerateFixedRegStubsAheadOfTime();
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 UnaryOpStub: public CodeStub {
84  public:
85   UnaryOpStub(Token::Value op,
86               UnaryOverwriteMode mode,
87               UnaryOpIC::TypeInfo operand_type = UnaryOpIC::UNINITIALIZED)
op_(op)88       : op_(op),
89         mode_(mode),
90         operand_type_(operand_type) {
91   }
92 
93  private:
94   Token::Value op_;
95   UnaryOverwriteMode mode_;
96 
97   // Operand type information determined at runtime.
98   UnaryOpIC::TypeInfo operand_type_;
99 
100   virtual void PrintName(StringStream* stream);
101 
102   class ModeBits: public BitField<UnaryOverwriteMode, 0, 1> {};
103   class OpBits: public BitField<Token::Value, 1, 7> {};
104   class OperandTypeInfoBits: public BitField<UnaryOpIC::TypeInfo, 8, 3> {};
105 
MajorKey()106   Major MajorKey() { return UnaryOp; }
MinorKey()107   int MinorKey() {
108     return ModeBits::encode(mode_)
109            | OpBits::encode(op_)
110            | OperandTypeInfoBits::encode(operand_type_);
111   }
112 
113   // Note: A lot of the helper functions below will vanish when we use virtual
114   // function instead of switch more often.
115   void Generate(MacroAssembler* masm);
116 
117   void GenerateTypeTransition(MacroAssembler* masm);
118 
119   void GenerateSmiStub(MacroAssembler* masm);
120   void GenerateSmiStubSub(MacroAssembler* masm);
121   void GenerateSmiStubBitNot(MacroAssembler* masm);
122   void GenerateSmiCodeSub(MacroAssembler* masm,
123                           Label* non_smi,
124                           Label* undo,
125                           Label* slow,
126                           Label::Distance non_smi_near = Label::kFar,
127                           Label::Distance undo_near = Label::kFar,
128                           Label::Distance slow_near = Label::kFar);
129   void GenerateSmiCodeBitNot(MacroAssembler* masm,
130                              Label* non_smi,
131                              Label::Distance non_smi_near = Label::kFar);
132   void GenerateSmiCodeUndo(MacroAssembler* masm);
133 
134   void GenerateHeapNumberStub(MacroAssembler* masm);
135   void GenerateHeapNumberStubSub(MacroAssembler* masm);
136   void GenerateHeapNumberStubBitNot(MacroAssembler* masm);
137   void GenerateHeapNumberCodeSub(MacroAssembler* masm, Label* slow);
138   void GenerateHeapNumberCodeBitNot(MacroAssembler* masm, Label* slow);
139 
140   void GenerateGenericStub(MacroAssembler* masm);
141   void GenerateGenericStubSub(MacroAssembler* masm);
142   void GenerateGenericStubBitNot(MacroAssembler* masm);
143   void GenerateGenericCodeFallback(MacroAssembler* masm);
144 
GetCodeKind()145   virtual int GetCodeKind() { return Code::UNARY_OP_IC; }
146 
GetICState()147   virtual InlineCacheState GetICState() {
148     return UnaryOpIC::ToState(operand_type_);
149   }
150 
FinishCode(Handle<Code> code)151   virtual void FinishCode(Handle<Code> code) {
152     code->set_unary_op_type(operand_type_);
153   }
154 };
155 
156 
157 class BinaryOpStub: public CodeStub {
158  public:
BinaryOpStub(Token::Value op,OverwriteMode mode)159   BinaryOpStub(Token::Value op, OverwriteMode mode)
160       : op_(op),
161         mode_(mode),
162         operands_type_(BinaryOpIC::UNINITIALIZED),
163         result_type_(BinaryOpIC::UNINITIALIZED) {
164     use_sse3_ = CpuFeatures::IsSupported(SSE3);
165     ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
166   }
167 
168   BinaryOpStub(
169       int key,
170       BinaryOpIC::TypeInfo operands_type,
171       BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED)
op_(OpBits::decode (key))172       : op_(OpBits::decode(key)),
173         mode_(ModeBits::decode(key)),
174         use_sse3_(SSE3Bits::decode(key)),
175         operands_type_(operands_type),
176         result_type_(result_type) { }
177 
178  private:
179   enum SmiCodeGenerateHeapNumberResults {
180     ALLOW_HEAPNUMBER_RESULTS,
181     NO_HEAPNUMBER_RESULTS
182   };
183 
184   Token::Value op_;
185   OverwriteMode mode_;
186   bool use_sse3_;
187 
188   // Operand type information determined at runtime.
189   BinaryOpIC::TypeInfo operands_type_;
190   BinaryOpIC::TypeInfo result_type_;
191 
192   virtual void PrintName(StringStream* stream);
193 
194   // Minor key encoding in 16 bits RRRTTTSOOOOOOOMM.
195   class ModeBits: public BitField<OverwriteMode, 0, 2> {};
196   class OpBits: public BitField<Token::Value, 2, 7> {};
197   class SSE3Bits: public BitField<bool, 9, 1> {};
198   class OperandTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 10, 3> {};
199   class ResultTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 13, 3> {};
200 
MajorKey()201   Major MajorKey() { return BinaryOp; }
MinorKey()202   int MinorKey() {
203     return OpBits::encode(op_)
204            | ModeBits::encode(mode_)
205            | SSE3Bits::encode(use_sse3_)
206            | OperandTypeInfoBits::encode(operands_type_)
207            | ResultTypeInfoBits::encode(result_type_);
208   }
209 
210   void Generate(MacroAssembler* masm);
211   void GenerateGeneric(MacroAssembler* masm);
212   void GenerateSmiCode(MacroAssembler* masm,
213                        Label* slow,
214                        SmiCodeGenerateHeapNumberResults heapnumber_results);
215   void GenerateLoadArguments(MacroAssembler* masm);
216   void GenerateReturn(MacroAssembler* masm);
217   void GenerateUninitializedStub(MacroAssembler* masm);
218   void GenerateSmiStub(MacroAssembler* masm);
219   void GenerateInt32Stub(MacroAssembler* masm);
220   void GenerateHeapNumberStub(MacroAssembler* masm);
221   void GenerateOddballStub(MacroAssembler* masm);
222   void GenerateStringStub(MacroAssembler* masm);
223   void GenerateBothStringStub(MacroAssembler* masm);
224   void GenerateGenericStub(MacroAssembler* masm);
225   void GenerateAddStrings(MacroAssembler* masm);
226 
227   void GenerateHeapResultAllocation(MacroAssembler* masm, Label* alloc_failure);
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 GenerateCopyCharactersREP adds too much
252   // overhead. Copying of overlapping regions is not supported.
253   static void GenerateCopyCharacters(MacroAssembler* masm,
254                                      Register dest,
255                                      Register src,
256                                      Register count,
257                                      Register scratch,
258                                      bool ascii);
259 
260   // Generate code for copying characters using the rep movs instruction.
261   // Copies ecx characters from esi to edi. Copying of overlapping regions is
262   // not supported.
263   static void GenerateCopyCharactersREP(MacroAssembler* masm,
264                                         Register dest,     // Must be edi.
265                                         Register src,      // Must be esi.
266                                         Register count,    // Must be ecx.
267                                         Register scratch,  // Neither of above.
268                                         bool ascii);
269 
270   // Probe the symbol table for a two character string. If the string
271   // requires non-standard hashing a jump to the label not_probed is
272   // performed and registers c1 and c2 are preserved. In all other
273   // cases they are clobbered. If the string is not found by probing a
274   // jump to the label not_found is performed. This jump does not
275   // guarantee that the string is not in the symbol table. If the
276   // string is found the code falls through with the string in
277   // register eax.
278   static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
279                                                    Register c1,
280                                                    Register c2,
281                                                    Register scratch1,
282                                                    Register scratch2,
283                                                    Register scratch3,
284                                                    Label* not_probed,
285                                                    Label* not_found);
286 
287   // Generate string hash.
288   static void GenerateHashInit(MacroAssembler* masm,
289                                Register hash,
290                                Register character,
291                                Register scratch);
292   static void GenerateHashAddCharacter(MacroAssembler* masm,
293                                        Register hash,
294                                        Register character,
295                                        Register scratch);
296   static void GenerateHashGetHash(MacroAssembler* masm,
297                                   Register hash,
298                                   Register scratch);
299 
300  private:
301   DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
302 };
303 
304 
305 // Flag that indicates how to generate code for the stub StringAddStub.
306 enum StringAddFlags {
307   NO_STRING_ADD_FLAGS = 0,
308   // Omit left string check in stub (left is definitely a string).
309   NO_STRING_CHECK_LEFT_IN_STUB = 1 << 0,
310   // Omit right string check in stub (right is definitely a string).
311   NO_STRING_CHECK_RIGHT_IN_STUB = 1 << 1,
312   // Omit both string checks in stub.
313   NO_STRING_CHECK_IN_STUB =
314       NO_STRING_CHECK_LEFT_IN_STUB | NO_STRING_CHECK_RIGHT_IN_STUB
315 };
316 
317 
318 class StringAddStub: public CodeStub {
319  public:
StringAddStub(StringAddFlags flags)320   explicit StringAddStub(StringAddFlags flags) : flags_(flags) {}
321 
322  private:
MajorKey()323   Major MajorKey() { return StringAdd; }
MinorKey()324   int MinorKey() { return flags_; }
325 
326   void Generate(MacroAssembler* masm);
327 
328   void GenerateConvertArgument(MacroAssembler* masm,
329                                int stack_offset,
330                                Register arg,
331                                Register scratch1,
332                                Register scratch2,
333                                Register scratch3,
334                                Label* slow);
335 
336   const StringAddFlags flags_;
337 };
338 
339 
340 class SubStringStub: public CodeStub {
341  public:
SubStringStub()342   SubStringStub() {}
343 
344  private:
MajorKey()345   Major MajorKey() { return SubString; }
MinorKey()346   int MinorKey() { return 0; }
347 
348   void Generate(MacroAssembler* masm);
349 };
350 
351 
352 class StringCompareStub: public CodeStub {
353  public:
StringCompareStub()354   StringCompareStub() { }
355 
356   // Compares two flat ASCII strings and returns result in eax.
357   static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
358                                               Register left,
359                                               Register right,
360                                               Register scratch1,
361                                               Register scratch2,
362                                               Register scratch3);
363 
364   // Compares two flat ASCII strings for equality and returns result
365   // in eax.
366   static void GenerateFlatAsciiStringEquals(MacroAssembler* masm,
367                                             Register left,
368                                             Register right,
369                                             Register scratch1,
370                                             Register scratch2);
371 
372  private:
MajorKey()373   virtual Major MajorKey() { return StringCompare; }
MinorKey()374   virtual int MinorKey() { return 0; }
375   virtual void Generate(MacroAssembler* masm);
376 
377   static void GenerateAsciiCharsCompareLoop(
378       MacroAssembler* masm,
379       Register left,
380       Register right,
381       Register length,
382       Register scratch,
383       Label* chars_not_equal,
384       Label::Distance chars_not_equal_near = Label::kFar);
385 };
386 
387 
388 class NumberToStringStub: public CodeStub {
389  public:
NumberToStringStub()390   NumberToStringStub() { }
391 
392   // Generate code to do a lookup in the number string cache. If the number in
393   // the register object is found in the cache the generated code falls through
394   // with the result in the result register. The object and the result register
395   // can be the same. If the number is not found in the cache the code jumps to
396   // the label not_found with only the content of register object unchanged.
397   static void GenerateLookupNumberStringCache(MacroAssembler* masm,
398                                               Register object,
399                                               Register result,
400                                               Register scratch1,
401                                               Register scratch2,
402                                               bool object_is_smi,
403                                               Label* not_found);
404 
405  private:
MajorKey()406   Major MajorKey() { return NumberToString; }
MinorKey()407   int MinorKey() { return 0; }
408 
409   void Generate(MacroAssembler* masm);
410 };
411 
412 
413 class StringDictionaryLookupStub: public CodeStub {
414  public:
415   enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
416 
StringDictionaryLookupStub(Register dictionary,Register result,Register index,LookupMode mode)417   StringDictionaryLookupStub(Register dictionary,
418                              Register result,
419                              Register index,
420                              LookupMode mode)
421       : dictionary_(dictionary), result_(result), index_(index), mode_(mode) { }
422 
423   void Generate(MacroAssembler* masm);
424 
425   static void GenerateNegativeLookup(MacroAssembler* masm,
426                                      Label* miss,
427                                      Label* done,
428                                      Register properties,
429                                      Handle<String> name,
430                                      Register r0);
431 
432   static void GeneratePositiveLookup(MacroAssembler* masm,
433                                      Label* miss,
434                                      Label* done,
435                                      Register elements,
436                                      Register name,
437                                      Register r0,
438                                      Register r1);
439 
SometimesSetsUpAFrame()440   virtual bool SometimesSetsUpAFrame() { return false; }
441 
442  private:
443   static const int kInlinedProbes = 4;
444   static const int kTotalProbes = 20;
445 
446   static const int kCapacityOffset =
447       StringDictionary::kHeaderSize +
448       StringDictionary::kCapacityIndex * kPointerSize;
449 
450   static const int kElementsStartOffset =
451       StringDictionary::kHeaderSize +
452       StringDictionary::kElementsStartIndex * kPointerSize;
453 
MajorKey()454   Major MajorKey() { return StringDictionaryLookup; }
455 
MinorKey()456   int MinorKey() {
457     return DictionaryBits::encode(dictionary_.code()) |
458         ResultBits::encode(result_.code()) |
459         IndexBits::encode(index_.code()) |
460         LookupModeBits::encode(mode_);
461   }
462 
463   class DictionaryBits: public BitField<int, 0, 3> {};
464   class ResultBits: public BitField<int, 3, 3> {};
465   class IndexBits: public BitField<int, 6, 3> {};
466   class LookupModeBits: public BitField<LookupMode, 9, 1> {};
467 
468   Register dictionary_;
469   Register result_;
470   Register index_;
471   LookupMode mode_;
472 };
473 
474 
475 class RecordWriteStub: public CodeStub {
476  public:
RecordWriteStub(Register object,Register value,Register address,RememberedSetAction remembered_set_action,SaveFPRegsMode fp_mode)477   RecordWriteStub(Register object,
478                   Register value,
479                   Register address,
480                   RememberedSetAction remembered_set_action,
481                   SaveFPRegsMode fp_mode)
482       : object_(object),
483         value_(value),
484         address_(address),
485         remembered_set_action_(remembered_set_action),
486         save_fp_regs_mode_(fp_mode),
487         regs_(object,   // An input reg.
488               address,  // An input reg.
489               value) {  // One scratch reg.
490   }
491 
492   enum Mode {
493     STORE_BUFFER_ONLY,
494     INCREMENTAL,
495     INCREMENTAL_COMPACTION
496   };
497 
498   virtual bool IsPregenerated();
499   static void GenerateFixedRegStubsAheadOfTime();
SometimesSetsUpAFrame()500   virtual bool SometimesSetsUpAFrame() { return false; }
501 
502   static const byte kTwoByteNopInstruction = 0x3c;  // Cmpb al, #imm8.
503   static const byte kTwoByteJumpInstruction = 0xeb;  // Jmp #imm8.
504 
505   static const byte kFiveByteNopInstruction = 0x3d;  // Cmpl eax, #imm32.
506   static const byte kFiveByteJumpInstruction = 0xe9;  // Jmp #imm32.
507 
GetMode(Code * stub)508   static Mode GetMode(Code* stub) {
509     byte first_instruction = stub->instruction_start()[0];
510     byte second_instruction = stub->instruction_start()[2];
511 
512     if (first_instruction == kTwoByteJumpInstruction) {
513       return INCREMENTAL;
514     }
515 
516     ASSERT(first_instruction == kTwoByteNopInstruction);
517 
518     if (second_instruction == kFiveByteJumpInstruction) {
519       return INCREMENTAL_COMPACTION;
520     }
521 
522     ASSERT(second_instruction == kFiveByteNopInstruction);
523 
524     return STORE_BUFFER_ONLY;
525   }
526 
Patch(Code * stub,Mode mode)527   static void Patch(Code* stub, Mode mode) {
528     switch (mode) {
529       case STORE_BUFFER_ONLY:
530         ASSERT(GetMode(stub) == INCREMENTAL ||
531                GetMode(stub) == INCREMENTAL_COMPACTION);
532         stub->instruction_start()[0] = kTwoByteNopInstruction;
533         stub->instruction_start()[2] = kFiveByteNopInstruction;
534         break;
535       case INCREMENTAL:
536         ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
537         stub->instruction_start()[0] = kTwoByteJumpInstruction;
538         break;
539       case INCREMENTAL_COMPACTION:
540         ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
541         stub->instruction_start()[0] = kTwoByteNopInstruction;
542         stub->instruction_start()[2] = kFiveByteJumpInstruction;
543         break;
544     }
545     ASSERT(GetMode(stub) == mode);
546     CPU::FlushICache(stub->instruction_start(), 7);
547   }
548 
549  private:
550   // This is a helper class for freeing up 3 scratch registers, where the third
551   // is always ecx (needed for shift operations).  The input is two registers
552   // that must be preserved and one scratch register provided by the caller.
553   class RegisterAllocation {
554    public:
RegisterAllocation(Register object,Register address,Register scratch0)555     RegisterAllocation(Register object,
556                        Register address,
557                        Register scratch0)
558         : object_orig_(object),
559           address_orig_(address),
560           scratch0_orig_(scratch0),
561           object_(object),
562           address_(address),
563           scratch0_(scratch0) {
564       ASSERT(!AreAliased(scratch0, object, address, no_reg));
565       scratch1_ = GetRegThatIsNotEcxOr(object_, address_, scratch0_);
566       if (scratch0.is(ecx)) {
567         scratch0_ = GetRegThatIsNotEcxOr(object_, address_, scratch1_);
568       }
569       if (object.is(ecx)) {
570         object_ = GetRegThatIsNotEcxOr(address_, scratch0_, scratch1_);
571       }
572       if (address.is(ecx)) {
573         address_ = GetRegThatIsNotEcxOr(object_, scratch0_, scratch1_);
574       }
575       ASSERT(!AreAliased(scratch0_, object_, address_, ecx));
576     }
577 
Save(MacroAssembler * masm)578     void Save(MacroAssembler* masm) {
579       ASSERT(!address_orig_.is(object_));
580       ASSERT(object_.is(object_orig_) || address_.is(address_orig_));
581       ASSERT(!AreAliased(object_, address_, scratch1_, scratch0_));
582       ASSERT(!AreAliased(object_orig_, address_, scratch1_, scratch0_));
583       ASSERT(!AreAliased(object_, address_orig_, scratch1_, scratch0_));
584       // We don't have to save scratch0_orig_ because it was given to us as
585       // a scratch register.  But if we had to switch to a different reg then
586       // we should save the new scratch0_.
587       if (!scratch0_.is(scratch0_orig_)) masm->push(scratch0_);
588       if (!ecx.is(scratch0_orig_) &&
589           !ecx.is(object_orig_) &&
590           !ecx.is(address_orig_)) {
591         masm->push(ecx);
592       }
593       masm->push(scratch1_);
594       if (!address_.is(address_orig_)) {
595         masm->push(address_);
596         masm->mov(address_, address_orig_);
597       }
598       if (!object_.is(object_orig_)) {
599         masm->push(object_);
600         masm->mov(object_, object_orig_);
601       }
602     }
603 
Restore(MacroAssembler * masm)604     void Restore(MacroAssembler* masm) {
605       // These will have been preserved the entire time, so we just need to move
606       // them back.  Only in one case is the orig_ reg different from the plain
607       // one, since only one of them can alias with ecx.
608       if (!object_.is(object_orig_)) {
609         masm->mov(object_orig_, object_);
610         masm->pop(object_);
611       }
612       if (!address_.is(address_orig_)) {
613         masm->mov(address_orig_, address_);
614         masm->pop(address_);
615       }
616       masm->pop(scratch1_);
617       if (!ecx.is(scratch0_orig_) &&
618           !ecx.is(object_orig_) &&
619           !ecx.is(address_orig_)) {
620         masm->pop(ecx);
621       }
622       if (!scratch0_.is(scratch0_orig_)) masm->pop(scratch0_);
623     }
624 
625     // If we have to call into C then we need to save and restore all caller-
626     // saved registers that were not already preserved.  The caller saved
627     // registers are eax, ecx and edx.  The three scratch registers (incl. ecx)
628     // will be restored by other means so we don't bother pushing them here.
SaveCallerSaveRegisters(MacroAssembler * masm,SaveFPRegsMode mode)629     void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
630       if (!scratch0_.is(eax) && !scratch1_.is(eax)) masm->push(eax);
631       if (!scratch0_.is(edx) && !scratch1_.is(edx)) masm->push(edx);
632       if (mode == kSaveFPRegs) {
633         CpuFeatures::Scope scope(SSE2);
634         masm->sub(esp,
635                   Immediate(kDoubleSize * (XMMRegister::kNumRegisters - 1)));
636         // Save all XMM registers except XMM0.
637         for (int i = XMMRegister::kNumRegisters - 1; i > 0; i--) {
638           XMMRegister reg = XMMRegister::from_code(i);
639           masm->movdbl(Operand(esp, (i - 1) * kDoubleSize), reg);
640         }
641       }
642     }
643 
RestoreCallerSaveRegisters(MacroAssembler * masm,SaveFPRegsMode mode)644     inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
645                                            SaveFPRegsMode mode) {
646       if (mode == kSaveFPRegs) {
647         CpuFeatures::Scope scope(SSE2);
648         // Restore all XMM registers except XMM0.
649         for (int i = XMMRegister::kNumRegisters - 1; i > 0; i--) {
650           XMMRegister reg = XMMRegister::from_code(i);
651           masm->movdbl(reg, Operand(esp, (i - 1) * kDoubleSize));
652         }
653         masm->add(esp,
654                   Immediate(kDoubleSize * (XMMRegister::kNumRegisters - 1)));
655       }
656       if (!scratch0_.is(edx) && !scratch1_.is(edx)) masm->pop(edx);
657       if (!scratch0_.is(eax) && !scratch1_.is(eax)) masm->pop(eax);
658     }
659 
object()660     inline Register object() { return object_; }
address()661     inline Register address() { return address_; }
scratch0()662     inline Register scratch0() { return scratch0_; }
scratch1()663     inline Register scratch1() { return scratch1_; }
664 
665    private:
666     Register object_orig_;
667     Register address_orig_;
668     Register scratch0_orig_;
669     Register object_;
670     Register address_;
671     Register scratch0_;
672     Register scratch1_;
673     // Third scratch register is always ecx.
674 
GetRegThatIsNotEcxOr(Register r1,Register r2,Register r3)675     Register GetRegThatIsNotEcxOr(Register r1,
676                                   Register r2,
677                                   Register r3) {
678       for (int i = 0; i < Register::kNumAllocatableRegisters; i++) {
679         Register candidate = Register::FromAllocationIndex(i);
680         if (candidate.is(ecx)) continue;
681         if (candidate.is(r1)) continue;
682         if (candidate.is(r2)) continue;
683         if (candidate.is(r3)) continue;
684         return candidate;
685       }
686       UNREACHABLE();
687       return no_reg;
688     }
689     friend class RecordWriteStub;
690   };
691 
692   enum OnNoNeedToInformIncrementalMarker {
693     kReturnOnNoNeedToInformIncrementalMarker,
694     kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
695   }
696 ;
697   void Generate(MacroAssembler* masm);
698   void GenerateIncremental(MacroAssembler* masm, Mode mode);
699   void CheckNeedsToInformIncrementalMarker(
700       MacroAssembler* masm,
701       OnNoNeedToInformIncrementalMarker on_no_need,
702       Mode mode);
703   void InformIncrementalMarker(MacroAssembler* masm, Mode mode);
704 
MajorKey()705   Major MajorKey() { return RecordWrite; }
706 
MinorKey()707   int MinorKey() {
708     return ObjectBits::encode(object_.code()) |
709         ValueBits::encode(value_.code()) |
710         AddressBits::encode(address_.code()) |
711         RememberedSetActionBits::encode(remembered_set_action_) |
712         SaveFPRegsModeBits::encode(save_fp_regs_mode_);
713   }
714 
Activate(Code * code)715   void Activate(Code* code) {
716     code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
717   }
718 
719   class ObjectBits: public BitField<int, 0, 3> {};
720   class ValueBits: public BitField<int, 3, 3> {};
721   class AddressBits: public BitField<int, 6, 3> {};
722   class RememberedSetActionBits: public BitField<RememberedSetAction, 9, 1> {};
723   class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 10, 1> {};
724 
725   Register object_;
726   Register value_;
727   Register address_;
728   RememberedSetAction remembered_set_action_;
729   SaveFPRegsMode save_fp_regs_mode_;
730   RegisterAllocation regs_;
731 };
732 
733 
734 } }  // namespace v8::internal
735 
736 #endif  // V8_IA32_CODE_STUBS_IA32_H_
737