1864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org// Copyright 2011 the V8 project authors. All rights reserved.
2864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org// Use of this source code is governed by a BSD-style license that can be
3864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org// found in the LICENSE file.
4864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
5864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org#ifndef V8_X87_CODE_STUBS_X87_H_
6864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org#define V8_X87_CODE_STUBS_X87_H_
7864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
8864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.orgnamespace v8 {
9864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.orgnamespace internal {
10864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
11864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
12864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.orgvoid ArrayNativeCode(MacroAssembler* masm,
13864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org                     bool construct_call,
14864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org                     Label* call_generic_code);
15864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
16864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
17864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.orgclass StringHelper : public AllStatic {
18864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org public:
19864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  // Generate code for copying characters using the rep movs instruction.
20864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  // Copies ecx characters from esi to edi. Copying of overlapping regions is
21864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  // not supported.
228ddb15e9094939a28890ee8bbc7f7fa246ecea49machenbach@chromium.org  static void GenerateCopyCharacters(MacroAssembler* masm,
238ddb15e9094939a28890ee8bbc7f7fa246ecea49machenbach@chromium.org                                     Register dest,
248ddb15e9094939a28890ee8bbc7f7fa246ecea49machenbach@chromium.org                                     Register src,
258ddb15e9094939a28890ee8bbc7f7fa246ecea49machenbach@chromium.org                                     Register count,
268ddb15e9094939a28890ee8bbc7f7fa246ecea49machenbach@chromium.org                                     Register scratch,
278ddb15e9094939a28890ee8bbc7f7fa246ecea49machenbach@chromium.org                                     String::Encoding encoding);
28864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
29b376fed08cb9d90a3f67f655adf63c4b35feb106machenbach@chromium.org  // Compares two flat one byte strings and returns result in eax.
30b376fed08cb9d90a3f67f655adf63c4b35feb106machenbach@chromium.org  static void GenerateCompareFlatOneByteStrings(MacroAssembler* masm,
31b376fed08cb9d90a3f67f655adf63c4b35feb106machenbach@chromium.org                                                Register left, Register right,
32b376fed08cb9d90a3f67f655adf63c4b35feb106machenbach@chromium.org                                                Register scratch1,
33b376fed08cb9d90a3f67f655adf63c4b35feb106machenbach@chromium.org                                                Register scratch2,
34b376fed08cb9d90a3f67f655adf63c4b35feb106machenbach@chromium.org                                                Register scratch3);
35b376fed08cb9d90a3f67f655adf63c4b35feb106machenbach@chromium.org
36b376fed08cb9d90a3f67f655adf63c4b35feb106machenbach@chromium.org  // Compares two flat one byte strings for equality and returns result in eax.
37b376fed08cb9d90a3f67f655adf63c4b35feb106machenbach@chromium.org  static void GenerateFlatOneByteStringEquals(MacroAssembler* masm,
389aaa825cf89e1bcfece269a453300ebf4a26d64dmachenbach@chromium.org                                              Register left, Register right,
39864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org                                              Register scratch1,
40b376fed08cb9d90a3f67f655adf63c4b35feb106machenbach@chromium.org                                              Register scratch2);
41864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
42864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org private:
43b376fed08cb9d90a3f67f655adf63c4b35feb106machenbach@chromium.org  static void GenerateOneByteCharsCompareLoop(
44b376fed08cb9d90a3f67f655adf63c4b35feb106machenbach@chromium.org      MacroAssembler* masm, Register left, Register right, Register length,
45b376fed08cb9d90a3f67f655adf63c4b35feb106machenbach@chromium.org      Register scratch, Label* chars_not_equal,
46864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      Label::Distance chars_not_equal_near = Label::kFar);
479aaa825cf89e1bcfece269a453300ebf4a26d64dmachenbach@chromium.org
489aaa825cf89e1bcfece269a453300ebf4a26d64dmachenbach@chromium.org  DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
49864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org};
50864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
51864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
52864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.orgclass NameDictionaryLookupStub: public PlatformCodeStub {
53864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org public:
54864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
55864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
5642ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org  NameDictionaryLookupStub(Isolate* isolate, Register dictionary,
5742ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org                           Register result, Register index, LookupMode mode)
5842ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org      : PlatformCodeStub(isolate) {
5942ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org    minor_key_ = DictionaryBits::encode(dictionary.code()) |
6042ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org                 ResultBits::encode(result.code()) |
6142ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org                 IndexBits::encode(index.code()) | LookupModeBits::encode(mode);
6242ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org  }
63864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
64864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  static void GenerateNegativeLookup(MacroAssembler* masm,
65864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org                                     Label* miss,
66864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org                                     Label* done,
67864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org                                     Register properties,
68864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org                                     Handle<Name> name,
69864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org                                     Register r0);
70864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
71864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  static void GeneratePositiveLookup(MacroAssembler* masm,
72864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org                                     Label* miss,
73864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org                                     Label* done,
74864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org                                     Register elements,
75864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org                                     Register name,
76864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org                                     Register r0,
77864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org                                     Register r1);
78864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
79864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  virtual bool SometimesSetsUpAFrame() { return false; }
80864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
81864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org private:
82864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  static const int kInlinedProbes = 4;
83864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  static const int kTotalProbes = 20;
84864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
85864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  static const int kCapacityOffset =
86864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      NameDictionary::kHeaderSize +
87864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      NameDictionary::kCapacityIndex * kPointerSize;
88864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
89864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  static const int kElementsStartOffset =
90864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      NameDictionary::kHeaderSize +
91864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      NameDictionary::kElementsStartIndex * kPointerSize;
92864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
9342ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org  Register dictionary() const {
9442ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org    return Register::from_code(DictionaryBits::decode(minor_key_));
9542ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org  }
9642ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org
9742ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org  Register result() const {
9842ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org    return Register::from_code(ResultBits::decode(minor_key_));
9942ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org  }
100864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
10142ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org  Register index() const {
10242ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org    return Register::from_code(IndexBits::decode(minor_key_));
103864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  }
104864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
10542ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org  LookupMode mode() const { return LookupModeBits::decode(minor_key_); }
10642ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org
107864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  class DictionaryBits: public BitField<int, 0, 3> {};
108864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  class ResultBits: public BitField<int, 3, 3> {};
109864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  class IndexBits: public BitField<int, 6, 3> {};
110864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  class LookupModeBits: public BitField<LookupMode, 9, 1> {};
111864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
112b376fed08cb9d90a3f67f655adf63c4b35feb106machenbach@chromium.org  DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
1132c81ceb7f1e1ccf5f304be0646f4c1375941a7f2machenbach@chromium.org  DEFINE_PLATFORM_CODE_STUB(NameDictionaryLookup, PlatformCodeStub);
114864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org};
115864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
116864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
117864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.orgclass RecordWriteStub: public PlatformCodeStub {
118864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org public:
11906b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org  RecordWriteStub(Isolate* isolate, Register object, Register value,
12006b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org                  Register address, RememberedSetAction remembered_set_action,
12106b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org                  SaveFPRegsMode fp_mode)
122864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      : PlatformCodeStub(isolate),
123864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org        regs_(object,   // An input reg.
124864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org              address,  // An input reg.
125864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org              value) {  // One scratch reg.
12642ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org    minor_key_ = ObjectBits::encode(object.code()) |
12742ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org                 ValueBits::encode(value.code()) |
12842ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org                 AddressBits::encode(address.code()) |
12906b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org                 RememberedSetActionBits::encode(remembered_set_action) |
13006b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org                 SaveFPRegsModeBits::encode(fp_mode);
131864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  }
132864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
1332c81ceb7f1e1ccf5f304be0646f4c1375941a7f2machenbach@chromium.org  RecordWriteStub(uint32_t key, Isolate* isolate)
1342c81ceb7f1e1ccf5f304be0646f4c1375941a7f2machenbach@chromium.org      : PlatformCodeStub(key, isolate), regs_(object(), address(), value()) {}
1352c81ceb7f1e1ccf5f304be0646f4c1375941a7f2machenbach@chromium.org
136864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  enum Mode {
137864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    STORE_BUFFER_ONLY,
138864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    INCREMENTAL,
139864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    INCREMENTAL_COMPACTION
140864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  };
141864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
142864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  virtual bool SometimesSetsUpAFrame() { return false; }
143864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
144864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  static const byte kTwoByteNopInstruction = 0x3c;  // Cmpb al, #imm8.
145864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  static const byte kTwoByteJumpInstruction = 0xeb;  // Jmp #imm8.
146864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
147864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  static const byte kFiveByteNopInstruction = 0x3d;  // Cmpl eax, #imm32.
148864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  static const byte kFiveByteJumpInstruction = 0xe9;  // Jmp #imm32.
149864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
150864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  static Mode GetMode(Code* stub) {
151864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    byte first_instruction = stub->instruction_start()[0];
152864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    byte second_instruction = stub->instruction_start()[2];
153864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
154864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    if (first_instruction == kTwoByteJumpInstruction) {
155864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      return INCREMENTAL;
156864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    }
157864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
158e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org    DCHECK(first_instruction == kTwoByteNopInstruction);
159864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
160864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    if (second_instruction == kFiveByteJumpInstruction) {
161864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      return INCREMENTAL_COMPACTION;
162864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    }
163864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
164e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org    DCHECK(second_instruction == kFiveByteNopInstruction);
165864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
166864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    return STORE_BUFFER_ONLY;
167864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  }
168864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
169864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  static void Patch(Code* stub, Mode mode) {
170864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    switch (mode) {
171864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      case STORE_BUFFER_ONLY:
172e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org        DCHECK(GetMode(stub) == INCREMENTAL ||
173864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org               GetMode(stub) == INCREMENTAL_COMPACTION);
174864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org        stub->instruction_start()[0] = kTwoByteNopInstruction;
175864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org        stub->instruction_start()[2] = kFiveByteNopInstruction;
176864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org        break;
177864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      case INCREMENTAL:
178e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org        DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
179864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org        stub->instruction_start()[0] = kTwoByteJumpInstruction;
180864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org        break;
181864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      case INCREMENTAL_COMPACTION:
182e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org        DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
183864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org        stub->instruction_start()[0] = kTwoByteNopInstruction;
184864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org        stub->instruction_start()[2] = kFiveByteJumpInstruction;
185864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org        break;
186864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    }
187e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org    DCHECK(GetMode(stub) == mode);
1885de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org    CpuFeatures::FlushICache(stub->instruction_start(), 7);
189864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  }
190864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
191b376fed08cb9d90a3f67f655adf63c4b35feb106machenbach@chromium.org  DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
192b376fed08cb9d90a3f67f655adf63c4b35feb106machenbach@chromium.org
193864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org private:
194864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  // This is a helper class for freeing up 3 scratch registers, where the third
195864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  // is always ecx (needed for shift operations).  The input is two registers
196864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  // that must be preserved and one scratch register provided by the caller.
197864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  class RegisterAllocation {
198864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org   public:
199864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    RegisterAllocation(Register object,
200864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org                       Register address,
201864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org                       Register scratch0)
202864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org        : object_orig_(object),
203864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org          address_orig_(address),
204864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org          scratch0_orig_(scratch0),
205864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org          object_(object),
206864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org          address_(address),
207864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org          scratch0_(scratch0) {
208e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org      DCHECK(!AreAliased(scratch0, object, address, no_reg));
209864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      scratch1_ = GetRegThatIsNotEcxOr(object_, address_, scratch0_);
210864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      if (scratch0.is(ecx)) {
211864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org        scratch0_ = GetRegThatIsNotEcxOr(object_, address_, scratch1_);
212864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      }
213864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      if (object.is(ecx)) {
214864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org        object_ = GetRegThatIsNotEcxOr(address_, scratch0_, scratch1_);
215864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      }
216864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      if (address.is(ecx)) {
217864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org        address_ = GetRegThatIsNotEcxOr(object_, scratch0_, scratch1_);
218864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      }
219e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org      DCHECK(!AreAliased(scratch0_, object_, address_, ecx));
220864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    }
221864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
222864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    void Save(MacroAssembler* masm) {
223e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org      DCHECK(!address_orig_.is(object_));
224e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org      DCHECK(object_.is(object_orig_) || address_.is(address_orig_));
225e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org      DCHECK(!AreAliased(object_, address_, scratch1_, scratch0_));
226e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org      DCHECK(!AreAliased(object_orig_, address_, scratch1_, scratch0_));
227e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org      DCHECK(!AreAliased(object_, address_orig_, scratch1_, scratch0_));
228864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      // We don't have to save scratch0_orig_ because it was given to us as
229864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      // a scratch register.  But if we had to switch to a different reg then
230864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      // we should save the new scratch0_.
231864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      if (!scratch0_.is(scratch0_orig_)) masm->push(scratch0_);
232864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      if (!ecx.is(scratch0_orig_) &&
233864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org          !ecx.is(object_orig_) &&
234864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org          !ecx.is(address_orig_)) {
235864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org        masm->push(ecx);
236864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      }
237864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      masm->push(scratch1_);
238864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      if (!address_.is(address_orig_)) {
239864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org        masm->push(address_);
240864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org        masm->mov(address_, address_orig_);
241864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      }
242864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      if (!object_.is(object_orig_)) {
243864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org        masm->push(object_);
244864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org        masm->mov(object_, object_orig_);
245864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      }
246864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    }
247864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
248864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    void Restore(MacroAssembler* masm) {
249864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      // These will have been preserved the entire time, so we just need to move
250864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      // them back.  Only in one case is the orig_ reg different from the plain
251864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      // one, since only one of them can alias with ecx.
252864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      if (!object_.is(object_orig_)) {
253864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org        masm->mov(object_orig_, object_);
254864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org        masm->pop(object_);
255864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      }
256864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      if (!address_.is(address_orig_)) {
257864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org        masm->mov(address_orig_, address_);
258864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org        masm->pop(address_);
259864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      }
260864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      masm->pop(scratch1_);
261864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      if (!ecx.is(scratch0_orig_) &&
262864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org          !ecx.is(object_orig_) &&
263864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org          !ecx.is(address_orig_)) {
264864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org        masm->pop(ecx);
265864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      }
266864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      if (!scratch0_.is(scratch0_orig_)) masm->pop(scratch0_);
267864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    }
268864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
269864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    // If we have to call into C then we need to save and restore all caller-
270864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    // saved registers that were not already preserved.  The caller saved
271864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    // registers are eax, ecx and edx.  The three scratch registers (incl. ecx)
272864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    // will be restored by other means so we don't bother pushing them here.
27306b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org    void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
274864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      if (!scratch0_.is(eax) && !scratch1_.is(eax)) masm->push(eax);
275864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      if (!scratch0_.is(edx) && !scratch1_.is(edx)) masm->push(edx);
27606b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org      if (mode == kSaveFPRegs) {
27706b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org        // Save FPU state in m108byte.
27806b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org        masm->sub(esp, Immediate(108));
27906b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org        masm->fnsave(Operand(esp, 0));
28006b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org      }
281864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    }
282864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
28306b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org    inline void RestoreCallerSaveRegisters(MacroAssembler* masm,
28406b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org                                           SaveFPRegsMode mode) {
28506b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org      if (mode == kSaveFPRegs) {
28606b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org        // Restore FPU state in m108byte.
28706b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org        masm->frstor(Operand(esp, 0));
28806b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org        masm->add(esp, Immediate(108));
28906b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org      }
290864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      if (!scratch0_.is(edx) && !scratch1_.is(edx)) masm->pop(edx);
291864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      if (!scratch0_.is(eax) && !scratch1_.is(eax)) masm->pop(eax);
292864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    }
293864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
294864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    inline Register object() { return object_; }
295864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    inline Register address() { return address_; }
296864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    inline Register scratch0() { return scratch0_; }
297864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    inline Register scratch1() { return scratch1_; }
298864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
299864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org   private:
300864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    Register object_orig_;
301864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    Register address_orig_;
302864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    Register scratch0_orig_;
303864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    Register object_;
304864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    Register address_;
305864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    Register scratch0_;
306864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    Register scratch1_;
307864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    // Third scratch register is always ecx.
308864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
309864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    Register GetRegThatIsNotEcxOr(Register r1,
310864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org                                  Register r2,
311864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org                                  Register r3) {
312864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      for (int i = 0; i < Register::NumAllocatableRegisters(); i++) {
313864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org        Register candidate = Register::FromAllocationIndex(i);
314864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org        if (candidate.is(ecx)) continue;
315864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org        if (candidate.is(r1)) continue;
316864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org        if (candidate.is(r2)) continue;
317864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org        if (candidate.is(r3)) continue;
318864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org        return candidate;
319864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      }
320864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      UNREACHABLE();
321864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      return no_reg;
322864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    }
323864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    friend class RecordWriteStub;
324864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  };
325864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
326864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  enum OnNoNeedToInformIncrementalMarker {
327864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    kReturnOnNoNeedToInformIncrementalMarker,
328864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org    kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
32942ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org  };
33042ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org
3312c81ceb7f1e1ccf5f304be0646f4c1375941a7f2machenbach@chromium.org  virtual inline Major MajorKey() const FINAL OVERRIDE { return RecordWrite; }
33242ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org
3332c81ceb7f1e1ccf5f304be0646f4c1375941a7f2machenbach@chromium.org  virtual void Generate(MacroAssembler* masm) OVERRIDE;
334864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  void GenerateIncremental(MacroAssembler* masm, Mode mode);
335864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  void CheckNeedsToInformIncrementalMarker(
336864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      MacroAssembler* masm,
337864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      OnNoNeedToInformIncrementalMarker on_no_need,
338864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org      Mode mode);
339864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  void InformIncrementalMarker(MacroAssembler* masm);
340864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
34142ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org  void Activate(Code* code) {
34242ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org    code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
34342ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org  }
344864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
34542ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org  Register object() const {
34642ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org    return Register::from_code(ObjectBits::decode(minor_key_));
347864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  }
348864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
34942ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org  Register value() const {
35042ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org    return Register::from_code(ValueBits::decode(minor_key_));
35142ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org  }
35242ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org
35342ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org  Register address() const {
35442ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org    return Register::from_code(AddressBits::decode(minor_key_));
35542ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org  }
35642ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org
35742ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org  RememberedSetAction remembered_set_action() const {
35842ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org    return RememberedSetActionBits::decode(minor_key_);
359864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  }
360864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
36106b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org  SaveFPRegsMode save_fp_regs_mode() const {
36206b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org    return SaveFPRegsModeBits::decode(minor_key_);
36306b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org  }
36406b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org
365864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  class ObjectBits: public BitField<int, 0, 3> {};
366864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  class ValueBits: public BitField<int, 3, 3> {};
367864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  class AddressBits: public BitField<int, 6, 3> {};
368864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  class RememberedSetActionBits: public BitField<RememberedSetAction, 9, 1> {};
36906b2696801712948b665372a38f96b1f10be6997machenbach@chromium.org  class SaveFPRegsModeBits : public BitField<SaveFPRegsMode, 10, 1> {};
370864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
371864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org  RegisterAllocation regs_;
37242ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org
37342ed2fc449e83fab2ccbf1b769a5e83715c9d783machenbach@chromium.org  DISALLOW_COPY_AND_ASSIGN(RecordWriteStub);
374864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org};
375864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
376864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
377864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org} }  // namespace v8::internal
378864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org
379864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org#endif  // V8_X87_CODE_STUBS_X87_H_
380