Line data Source code
1 : // Copyright 2011 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #ifndef V8_X64_CODE_STUBS_X64_H_
6 : #define V8_X64_CODE_STUBS_X64_H_
7 :
8 : namespace v8 {
9 : namespace internal {
10 :
11 :
12 0 : class NameDictionaryLookupStub: public PlatformCodeStub {
13 : public:
14 : NameDictionaryLookupStub(Isolate* isolate, Register dictionary,
15 : Register result, Register index)
16 829 : : PlatformCodeStub(isolate) {
17 829 : minor_key_ = DictionaryBits::encode(dictionary.code()) |
18 829 : ResultBits::encode(result.code()) |
19 829 : IndexBits::encode(index.code());
20 : }
21 :
22 : static void GenerateNegativeLookup(MacroAssembler* masm,
23 : Label* miss,
24 : Label* done,
25 : Register properties,
26 : Handle<Name> name,
27 : Register r0);
28 :
29 0 : bool SometimesSetsUpAFrame() override { return false; }
30 :
31 : private:
32 : static const int kInlinedProbes = 4;
33 : static const int kTotalProbes = 20;
34 :
35 : static const int kCapacityOffset =
36 : NameDictionary::kHeaderSize +
37 : NameDictionary::kCapacityIndex * kPointerSize;
38 :
39 : static const int kElementsStartOffset =
40 : NameDictionary::kHeaderSize +
41 : NameDictionary::kElementsStartIndex * kPointerSize;
42 :
43 : Register dictionary() const {
44 : return Register::from_code(DictionaryBits::decode(minor_key_));
45 : }
46 :
47 : Register result() const {
48 : return Register::from_code(ResultBits::decode(minor_key_));
49 : }
50 :
51 : Register index() const {
52 : return Register::from_code(IndexBits::decode(minor_key_));
53 : }
54 :
55 : class DictionaryBits: public BitField<int, 0, 4> {};
56 : class ResultBits: public BitField<int, 4, 4> {};
57 : class IndexBits: public BitField<int, 8, 4> {};
58 :
59 0 : DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
60 940 : DEFINE_PLATFORM_CODE_STUB(NameDictionaryLookup, PlatformCodeStub);
61 : };
62 :
63 :
64 6 : class RecordWriteStub: public PlatformCodeStub {
65 : public:
66 : RecordWriteStub(Isolate* isolate, Register object, Register value,
67 : Register address, RememberedSetAction remembered_set_action,
68 : SaveFPRegsMode fp_mode)
69 : : PlatformCodeStub(isolate),
70 : regs_(object, // An input reg.
71 : address, // An input reg.
72 : value) { // One scratch reg.
73 : minor_key_ = ObjectBits::encode(object.code()) |
74 : ValueBits::encode(value.code()) |
75 : AddressBits::encode(address.code()) |
76 : RememberedSetActionBits::encode(remembered_set_action) |
77 : SaveFPRegsModeBits::encode(fp_mode);
78 : }
79 :
80 6 : RecordWriteStub(uint32_t key, Isolate* isolate)
81 12 : : PlatformCodeStub(key, isolate), regs_(object(), address(), value()) {}
82 :
83 : enum Mode {
84 : STORE_BUFFER_ONLY,
85 : INCREMENTAL,
86 : INCREMENTAL_COMPACTION
87 : };
88 :
89 0 : bool SometimesSetsUpAFrame() override { return false; }
90 :
91 : static const byte kTwoByteNopInstruction = 0x3c; // Cmpb al, #imm8.
92 : static const byte kTwoByteJumpInstruction = 0xeb; // Jmp #imm8.
93 :
94 : static Mode GetMode(Code* stub);
95 :
96 : static void Patch(Code* stub, Mode mode);
97 :
98 0 : DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
99 :
100 : private:
101 : // This is a helper class for freeing up 3 scratch registers, where the third
102 : // is always rcx (needed for shift operations). The input is two registers
103 : // that must be preserved and one scratch register provided by the caller.
104 : class RegisterAllocation {
105 : public:
106 6 : RegisterAllocation(Register object, Register address, Register scratch0)
107 : : object_orig_(object),
108 : address_orig_(address),
109 : scratch0_orig_(scratch0),
110 : object_(object),
111 : address_(address),
112 : scratch0_(scratch0),
113 6 : scratch1_(no_reg) {
114 : DCHECK(!AreAliased(scratch0, object, address, no_reg));
115 6 : scratch1_ = GetRegThatIsNotRcxOr(object_, address_, scratch0_);
116 6 : if (scratch0 == rcx) {
117 0 : scratch0_ = GetRegThatIsNotRcxOr(object_, address_, scratch1_);
118 : }
119 6 : if (object == rcx) {
120 0 : object_ = GetRegThatIsNotRcxOr(address_, scratch0_, scratch1_);
121 : }
122 6 : if (address == rcx) {
123 0 : address_ = GetRegThatIsNotRcxOr(object_, scratch0_, scratch1_);
124 : }
125 : DCHECK(!AreAliased(scratch0_, object_, address_, rcx));
126 6 : }
127 :
128 0 : void Save(MacroAssembler* masm) {
129 : DCHECK(address_orig_ != object_);
130 : DCHECK(object_ == object_orig_ || address_ == address_orig_);
131 : DCHECK(!AreAliased(object_, address_, scratch1_, scratch0_));
132 : DCHECK(!AreAliased(object_orig_, address_, scratch1_, scratch0_));
133 : DCHECK(!AreAliased(object_, address_orig_, scratch1_, scratch0_));
134 : // We don't have to save scratch0_orig_ because it was given to us as
135 : // a scratch register. But if we had to switch to a different reg then
136 : // we should save the new scratch0_.
137 0 : if (scratch0_ != scratch0_orig_) masm->Push(scratch0_);
138 0 : if (rcx != scratch0_orig_ && rcx != object_orig_ &&
139 : rcx != address_orig_) {
140 0 : masm->Push(rcx);
141 : }
142 0 : masm->Push(scratch1_);
143 0 : if (address_ != address_orig_) {
144 0 : masm->Push(address_);
145 0 : masm->movp(address_, address_orig_);
146 : }
147 0 : if (object_ != object_orig_) {
148 0 : masm->Push(object_);
149 0 : masm->movp(object_, object_orig_);
150 : }
151 0 : }
152 :
153 0 : void Restore(MacroAssembler* masm) {
154 : // These will have been preserved the entire time, so we just need to move
155 : // them back. Only in one case is the orig_ reg different from the plain
156 : // one, since only one of them can alias with rcx.
157 0 : if (object_ != object_orig_) {
158 0 : masm->movp(object_orig_, object_);
159 0 : masm->Pop(object_);
160 : }
161 0 : if (address_ != address_orig_) {
162 0 : masm->movp(address_orig_, address_);
163 0 : masm->Pop(address_);
164 : }
165 0 : masm->Pop(scratch1_);
166 0 : if (rcx != scratch0_orig_ && rcx != object_orig_ &&
167 : rcx != address_orig_) {
168 0 : masm->Pop(rcx);
169 : }
170 0 : if (scratch0_ != scratch0_orig_) masm->Pop(scratch0_);
171 0 : }
172 :
173 : // If we have to call into C then we need to save and restore all caller-
174 : // saved registers that were not already preserved.
175 :
176 : // The three scratch registers (incl. rcx) will be restored by other means
177 : // so we don't bother pushing them here. Rbx, rbp and r12-15 are callee
178 : // save and don't need to be preserved.
179 : void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
180 0 : masm->PushCallerSaved(mode, scratch0_, scratch1_, rcx);
181 : }
182 :
183 : inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
184 : SaveFPRegsMode mode) {
185 0 : masm->PopCallerSaved(mode, scratch0_, scratch1_, rcx);
186 : }
187 :
188 : inline Register object() { return object_; }
189 : inline Register address() { return address_; }
190 : inline Register scratch0() { return scratch0_; }
191 : inline Register scratch1() { return scratch1_; }
192 :
193 : private:
194 : Register object_orig_;
195 : Register address_orig_;
196 : Register scratch0_orig_;
197 : Register object_;
198 : Register address_;
199 : Register scratch0_;
200 : Register scratch1_;
201 : // Third scratch register is always rcx.
202 :
203 6 : Register GetRegThatIsNotRcxOr(Register r1,
204 : Register r2,
205 : Register r3) {
206 12 : for (int i = 0; i < Register::kNumRegisters; i++) {
207 36 : if (RegisterConfiguration::Default()->IsAllocatableGeneralCode(i)) {
208 : Register candidate = Register::from_code(i);
209 18 : if (candidate != rcx && candidate != r1 && candidate != r2 &&
210 : candidate != r3) {
211 6 : return candidate;
212 : }
213 : }
214 : }
215 0 : UNREACHABLE();
216 : }
217 : friend class RecordWriteStub;
218 : };
219 :
220 : enum OnNoNeedToInformIncrementalMarker {
221 : kReturnOnNoNeedToInformIncrementalMarker,
222 : kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
223 : };
224 :
225 6 : Major MajorKey() const final { return RecordWrite; }
226 :
227 : void Generate(MacroAssembler* masm) override;
228 : void GenerateIncremental(MacroAssembler* masm, Label* second_instr);
229 : void CheckNeedsToInformIncrementalMarker(
230 : MacroAssembler* masm, OnNoNeedToInformIncrementalMarker on_no_need,
231 : Label* second_instr);
232 : void InformIncrementalMarker(MacroAssembler* masm);
233 :
234 : void Activate(Code* code) override;
235 :
236 : Register object() const {
237 : return Register::from_code(ObjectBits::decode(minor_key_));
238 : }
239 :
240 : Register value() const {
241 : return Register::from_code(ValueBits::decode(minor_key_));
242 : }
243 :
244 : Register address() const {
245 : return Register::from_code(AddressBits::decode(minor_key_));
246 : }
247 :
248 : RememberedSetAction remembered_set_action() const {
249 : return RememberedSetActionBits::decode(minor_key_);
250 : }
251 :
252 : SaveFPRegsMode save_fp_regs_mode() const {
253 : return SaveFPRegsModeBits::decode(minor_key_);
254 : }
255 :
256 : class ObjectBits: public BitField<int, 0, 4> {};
257 : class ValueBits: public BitField<int, 4, 4> {};
258 : class AddressBits: public BitField<int, 8, 4> {};
259 : class RememberedSetActionBits: public BitField<RememberedSetAction, 12, 1> {};
260 : class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 13, 1> {};
261 :
262 : Label slow_;
263 : RegisterAllocation regs_;
264 :
265 : DISALLOW_COPY_AND_ASSIGN(RecordWriteStub);
266 : };
267 :
268 :
269 : } // namespace internal
270 : } // namespace v8
271 :
272 : #endif // V8_X64_CODE_STUBS_X64_H_
|