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 : void ArrayNativeCode(MacroAssembler* masm, Label* call_generic_code);
13 :
14 :
15 : class StringHelper : public AllStatic {
16 : public:
17 : // Compares two flat one-byte strings and returns result in rax.
18 : static void GenerateCompareFlatOneByteStrings(
19 : MacroAssembler* masm, Register left, Register right, Register scratch1,
20 : Register scratch2, Register scratch3, Register scratch4);
21 :
22 : // Compares two flat one-byte strings for equality and returns result in rax.
23 : static void GenerateFlatOneByteStringEquals(MacroAssembler* masm,
24 : Register left, Register right,
25 : Register scratch1,
26 : Register scratch2);
27 :
28 : private:
29 : static void GenerateOneByteCharsCompareLoop(
30 : MacroAssembler* masm, Register left, Register right, Register length,
31 : Register scratch, Label* chars_not_equal,
32 : Label::Distance near_jump = Label::kFar);
33 :
34 : DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
35 : };
36 :
37 :
38 0 : class NameDictionaryLookupStub: public PlatformCodeStub {
39 : public:
40 : enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
41 :
42 : NameDictionaryLookupStub(Isolate* isolate, Register dictionary,
43 : Register result, Register index, LookupMode mode)
44 1275 : : PlatformCodeStub(isolate) {
45 1275 : minor_key_ = DictionaryBits::encode(dictionary.code()) |
46 1275 : ResultBits::encode(result.code()) |
47 1275 : IndexBits::encode(index.code()) | LookupModeBits::encode(mode);
48 : }
49 :
50 : static void GenerateNegativeLookup(MacroAssembler* masm,
51 : Label* miss,
52 : Label* done,
53 : Register properties,
54 : Handle<Name> name,
55 : Register r0);
56 :
57 0 : bool SometimesSetsUpAFrame() override { return false; }
58 :
59 : private:
60 : static const int kInlinedProbes = 4;
61 : static const int kTotalProbes = 20;
62 :
63 : static const int kCapacityOffset =
64 : NameDictionary::kHeaderSize +
65 : NameDictionary::kCapacityIndex * kPointerSize;
66 :
67 : static const int kElementsStartOffset =
68 : NameDictionary::kHeaderSize +
69 : NameDictionary::kElementsStartIndex * kPointerSize;
70 :
71 : Register dictionary() const {
72 : return Register::from_code(DictionaryBits::decode(minor_key_));
73 : }
74 :
75 : Register result() const {
76 : return Register::from_code(ResultBits::decode(minor_key_));
77 : }
78 :
79 : Register index() const {
80 : return Register::from_code(IndexBits::decode(minor_key_));
81 : }
82 :
83 : LookupMode mode() const { return LookupModeBits::decode(minor_key_); }
84 :
85 : class DictionaryBits: public BitField<int, 0, 4> {};
86 : class ResultBits: public BitField<int, 4, 4> {};
87 : class IndexBits: public BitField<int, 8, 4> {};
88 : class LookupModeBits: public BitField<LookupMode, 12, 1> {};
89 :
90 0 : DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
91 1377 : DEFINE_PLATFORM_CODE_STUB(NameDictionaryLookup, PlatformCodeStub);
92 : };
93 :
94 :
95 0 : class RecordWriteStub: public PlatformCodeStub {
96 : public:
97 1077394 : RecordWriteStub(Isolate* isolate, Register object, Register value,
98 : Register address, RememberedSetAction remembered_set_action,
99 : SaveFPRegsMode fp_mode)
100 : : PlatformCodeStub(isolate),
101 : regs_(object, // An input reg.
102 : address, // An input reg.
103 2154788 : value) { // One scratch reg.
104 1077394 : minor_key_ = ObjectBits::encode(object.code()) |
105 1077394 : ValueBits::encode(value.code()) |
106 1077394 : AddressBits::encode(address.code()) |
107 1077394 : RememberedSetActionBits::encode(remembered_set_action) |
108 1077394 : SaveFPRegsModeBits::encode(fp_mode);
109 1077394 : }
110 :
111 0 : RecordWriteStub(uint32_t key, Isolate* isolate)
112 0 : : PlatformCodeStub(key, isolate), regs_(object(), address(), value()) {}
113 :
114 : enum Mode {
115 : STORE_BUFFER_ONLY,
116 : INCREMENTAL,
117 : INCREMENTAL_COMPACTION
118 : };
119 :
120 0 : bool SometimesSetsUpAFrame() override { return false; }
121 :
122 : static const byte kTwoByteNopInstruction = 0x3c; // Cmpb al, #imm8.
123 : static const byte kTwoByteJumpInstruction = 0xeb; // Jmp #imm8.
124 :
125 : static const byte kFiveByteNopInstruction = 0x3d; // Cmpl eax, #imm32.
126 : static const byte kFiveByteJumpInstruction = 0xe9; // Jmp #imm32.
127 :
128 : static Mode GetMode(Code* stub) {
129 : byte first_instruction = stub->instruction_start()[0];
130 : byte second_instruction = stub->instruction_start()[2];
131 :
132 : if (first_instruction == kTwoByteJumpInstruction) {
133 : return INCREMENTAL;
134 : }
135 :
136 : DCHECK(first_instruction == kTwoByteNopInstruction);
137 :
138 : if (second_instruction == kFiveByteJumpInstruction) {
139 : return INCREMENTAL_COMPACTION;
140 : }
141 :
142 : DCHECK(second_instruction == kFiveByteNopInstruction);
143 :
144 : return STORE_BUFFER_ONLY;
145 : }
146 :
147 286452 : static void Patch(Code* stub, Mode mode) {
148 286452 : switch (mode) {
149 : case STORE_BUFFER_ONLY:
150 : DCHECK(GetMode(stub) == INCREMENTAL ||
151 : GetMode(stub) == INCREMENTAL_COMPACTION);
152 141612 : stub->instruction_start()[0] = kTwoByteNopInstruction;
153 141612 : stub->instruction_start()[2] = kFiveByteNopInstruction;
154 141612 : break;
155 : case INCREMENTAL:
156 : DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
157 132591 : stub->instruction_start()[0] = kTwoByteJumpInstruction;
158 132591 : break;
159 : case INCREMENTAL_COMPACTION:
160 : DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
161 12249 : stub->instruction_start()[0] = kTwoByteNopInstruction;
162 12249 : stub->instruction_start()[2] = kFiveByteJumpInstruction;
163 12249 : break;
164 : }
165 : DCHECK(GetMode(stub) == mode);
166 572904 : Assembler::FlushICache(stub->GetIsolate(), stub->instruction_start(), 7);
167 286452 : }
168 :
169 0 : DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
170 :
171 : private:
172 : // This is a helper class for freeing up 3 scratch registers, where the third
173 : // is always rcx (needed for shift operations). The input is two registers
174 : // that must be preserved and one scratch register provided by the caller.
175 : class RegisterAllocation {
176 : public:
177 1077394 : RegisterAllocation(Register object,
178 : Register address,
179 : Register scratch0)
180 : : object_orig_(object),
181 : address_orig_(address),
182 : scratch0_orig_(scratch0),
183 : object_(object),
184 : address_(address),
185 1077394 : scratch0_(scratch0) {
186 : DCHECK(!AreAliased(scratch0, object, address, no_reg));
187 1077394 : scratch1_ = GetRegThatIsNotRcxOr(object_, address_, scratch0_);
188 1077394 : if (scratch0.is(rcx)) {
189 112961 : scratch0_ = GetRegThatIsNotRcxOr(object_, address_, scratch1_);
190 : }
191 1077394 : if (object.is(rcx)) {
192 550826 : object_ = GetRegThatIsNotRcxOr(address_, scratch0_, scratch1_);
193 : }
194 1077394 : if (address.is(rcx)) {
195 246178 : address_ = GetRegThatIsNotRcxOr(object_, scratch0_, scratch1_);
196 : }
197 : DCHECK(!AreAliased(scratch0_, object_, address_, rcx));
198 1077394 : }
199 :
200 45606 : void Save(MacroAssembler* masm) {
201 : DCHECK(!address_orig_.is(object_));
202 : DCHECK(object_.is(object_orig_) || address_.is(address_orig_));
203 : DCHECK(!AreAliased(object_, address_, scratch1_, scratch0_));
204 : DCHECK(!AreAliased(object_orig_, address_, scratch1_, scratch0_));
205 : DCHECK(!AreAliased(object_, address_orig_, scratch1_, scratch0_));
206 : // We don't have to save scratch0_orig_ because it was given to us as
207 : // a scratch register. But if we had to switch to a different reg then
208 : // we should save the new scratch0_.
209 45606 : if (!scratch0_.is(scratch0_orig_)) masm->Push(scratch0_);
210 88812 : if (!rcx.is(scratch0_orig_) &&
211 76448 : !rcx.is(object_orig_) &&
212 : !rcx.is(address_orig_)) {
213 23136 : masm->Push(rcx);
214 : }
215 45606 : masm->Push(scratch1_);
216 45606 : if (!address_.is(address_orig_)) {
217 7706 : masm->Push(address_);
218 7706 : masm->movp(address_, address_orig_);
219 : }
220 45606 : if (!object_.is(object_orig_)) {
221 12364 : masm->Push(object_);
222 12364 : masm->movp(object_, object_orig_);
223 : }
224 45606 : }
225 :
226 250860 : void Restore(MacroAssembler* masm) {
227 : // These will have been preserved the entire time, so we just need to move
228 : // them back. Only in one case is the orig_ reg different from the plain
229 : // one, since only one of them can alias with rcx.
230 250860 : if (!object_.is(object_orig_)) {
231 71808 : masm->movp(object_orig_, object_);
232 71808 : masm->Pop(object_);
233 : }
234 250860 : if (!address_.is(address_orig_)) {
235 44574 : masm->movp(address_orig_, address_);
236 44574 : masm->Pop(address_);
237 : }
238 250860 : masm->Pop(scratch1_);
239 488526 : if (!rcx.is(scratch0_orig_) &&
240 416718 : !rcx.is(object_orig_) &&
241 : !rcx.is(address_orig_)) {
242 121284 : masm->Pop(rcx);
243 : }
244 250860 : if (!scratch0_.is(scratch0_orig_)) masm->Pop(scratch0_);
245 250860 : }
246 :
247 : // If we have to call into C then we need to save and restore all caller-
248 : // saved registers that were not already preserved.
249 :
250 : // The three scratch registers (incl. rcx) will be restored by other means
251 : // so we don't bother pushing them here. Rbx, rbp and r12-15 are callee
252 : // save and don't need to be preserved.
253 : void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
254 83620 : masm->PushCallerSaved(mode, scratch0_, scratch1_, rcx);
255 : }
256 :
257 : inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
258 : SaveFPRegsMode mode) {
259 83620 : masm->PopCallerSaved(mode, scratch0_, scratch1_, rcx);
260 : }
261 :
262 : inline Register object() { return object_; }
263 : inline Register address() { return address_; }
264 : inline Register scratch0() { return scratch0_; }
265 : inline Register scratch1() { return scratch1_; }
266 :
267 : private:
268 : Register object_orig_;
269 : Register address_orig_;
270 : Register scratch0_orig_;
271 : Register object_;
272 : Register address_;
273 : Register scratch0_;
274 : Register scratch1_;
275 : // Third scratch register is always rcx.
276 :
277 1987359 : Register GetRegThatIsNotRcxOr(Register r1,
278 : Register r2,
279 : Register r3) {
280 5627639 : for (int i = 0; i < Register::kNumRegisters; i++) {
281 15229996 : if (RegisterConfiguration::Crankshaft()->IsAllocatableGeneralCode(i)) {
282 : Register candidate = Register::from_code(i);
283 6259886 : if (candidate.is(rcx)) continue;
284 4978951 : if (candidate.is(r1)) continue;
285 4135604 : if (candidate.is(r2)) continue;
286 3169817 : if (candidate.is(r3)) continue;
287 1987359 : return candidate;
288 : }
289 : }
290 0 : UNREACHABLE();
291 : return no_reg;
292 : }
293 : friend class RecordWriteStub;
294 : };
295 :
296 : enum OnNoNeedToInformIncrementalMarker {
297 : kReturnOnNoNeedToInformIncrementalMarker,
298 : kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
299 : };
300 :
301 1145810 : Major MajorKey() const final { return RecordWrite; }
302 :
303 : void Generate(MacroAssembler* masm) override;
304 : void GenerateIncremental(MacroAssembler* masm, Mode mode);
305 : void CheckNeedsToInformIncrementalMarker(
306 : MacroAssembler* masm,
307 : OnNoNeedToInformIncrementalMarker on_no_need,
308 : Mode mode);
309 : void InformIncrementalMarker(MacroAssembler* masm);
310 :
311 : void Activate(Code* code) override;
312 :
313 : Register object() const {
314 : return Register::from_code(ObjectBits::decode(minor_key_));
315 : }
316 :
317 : Register value() const {
318 : return Register::from_code(ValueBits::decode(minor_key_));
319 : }
320 :
321 : Register address() const {
322 : return Register::from_code(AddressBits::decode(minor_key_));
323 : }
324 :
325 : RememberedSetAction remembered_set_action() const {
326 : return RememberedSetActionBits::decode(minor_key_);
327 : }
328 :
329 : SaveFPRegsMode save_fp_regs_mode() const {
330 : return SaveFPRegsModeBits::decode(minor_key_);
331 : }
332 :
333 : class ObjectBits: public BitField<int, 0, 4> {};
334 : class ValueBits: public BitField<int, 4, 4> {};
335 : class AddressBits: public BitField<int, 8, 4> {};
336 : class RememberedSetActionBits: public BitField<RememberedSetAction, 12, 1> {};
337 : class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 13, 1> {};
338 :
339 : Label slow_;
340 : RegisterAllocation regs_;
341 :
342 : DISALLOW_COPY_AND_ASSIGN(RecordWriteStub);
343 : };
344 :
345 :
346 : } // namespace internal
347 : } // namespace v8
348 :
349 : #endif // V8_X64_CODE_STUBS_X64_H_
|