blob: 07563cd02a0251ee9a01cb08f14c587ccd5a466c [file] [log] [blame]
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001// Copyright 2011 the V8 project authors. All rights reserved.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002// 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
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +000031#include "macro-assembler.h"
32#include "code-stubs.h"
ricow@chromium.org65fae842010-08-25 15:26:24 +000033#include "ic-inl.h"
34
35namespace v8 {
36namespace internal {
37
38
39// Compute a transcendental math function natively, or call the
40// TranscendentalCache runtime function.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000041class TranscendentalCacheStub: public PlatformCodeStub {
ricow@chromium.org65fae842010-08-25 15:26:24 +000042 public:
whesse@chromium.org023421e2010-12-21 12:19:12 +000043 enum ArgumentType {
44 TAGGED = 0,
45 UNTAGGED = 1 << TranscendentalCache::kTranscendentalTypeBits
46 };
47
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000048 TranscendentalCacheStub(TranscendentalCache::Type type,
49 ArgumentType argument_type)
whesse@chromium.org023421e2010-12-21 12:19:12 +000050 : type_(type), argument_type_(argument_type) {}
ricow@chromium.org65fae842010-08-25 15:26:24 +000051 void Generate(MacroAssembler* masm);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +000052 static void GenerateOperation(MacroAssembler* masm,
53 TranscendentalCache::Type type);
ricow@chromium.org65fae842010-08-25 15:26:24 +000054 private:
55 TranscendentalCache::Type type_;
whesse@chromium.org023421e2010-12-21 12:19:12 +000056 ArgumentType argument_type_;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000057
ricow@chromium.org65fae842010-08-25 15:26:24 +000058 Major MajorKey() { return TranscendentalCache; }
whesse@chromium.org023421e2010-12-21 12:19:12 +000059 int MinorKey() { return type_ | argument_type_; }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000060 Runtime::FunctionId RuntimeFunction();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000061};
62
63
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000064class StoreBufferOverflowStub: public PlatformCodeStub {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000065 public:
66 explicit StoreBufferOverflowStub(SaveFPRegsMode save_fp)
ulan@chromium.org750145a2013-03-07 15:14:13 +000067 : save_doubles_(save_fp) {
68 ASSERT(CpuFeatures::IsSafeForSnapshot(SSE2) || save_fp == kDontSaveFPRegs);
69 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000070
71 void Generate(MacroAssembler* masm);
72
73 virtual bool IsPregenerated() { return true; }
hpayer@chromium.org8432c912013-02-28 15:55:26 +000074 static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000075 virtual bool SometimesSetsUpAFrame() { return false; }
76
77 private:
78 SaveFPRegsMode save_doubles_;
79
80 Major MajorKey() { return StoreBufferOverflow; }
81 int MinorKey() { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; }
82};
83
84
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000085class UnaryOpStub: public PlatformCodeStub {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000086 public:
ricow@chromium.org4f693d62011-07-04 14:01:31 +000087 UnaryOpStub(Token::Value op,
88 UnaryOverwriteMode mode,
89 UnaryOpIC::TypeInfo operand_type = UnaryOpIC::UNINITIALIZED)
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000090 : op_(op),
91 mode_(mode),
whesse@chromium.org030d38e2011-07-13 13:23:34 +000092 operand_type_(operand_type) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000093 }
94
95 private:
96 Token::Value op_;
97 UnaryOverwriteMode mode_;
98
99 // Operand type information determined at runtime.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000100 UnaryOpIC::TypeInfo operand_type_;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000101
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000102 virtual void PrintName(StringStream* stream);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000103
104 class ModeBits: public BitField<UnaryOverwriteMode, 0, 1> {};
105 class OpBits: public BitField<Token::Value, 1, 7> {};
danno@chromium.org40cb8782011-05-25 07:58:50 +0000106 class OperandTypeInfoBits: public BitField<UnaryOpIC::TypeInfo, 8, 3> {};
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000107
danno@chromium.org40cb8782011-05-25 07:58:50 +0000108 Major MajorKey() { return UnaryOp; }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000109 int MinorKey() {
110 return ModeBits::encode(mode_)
111 | OpBits::encode(op_)
112 | OperandTypeInfoBits::encode(operand_type_);
113 }
114
115 // Note: A lot of the helper functions below will vanish when we use virtual
116 // function instead of switch more often.
117 void Generate(MacroAssembler* masm);
118
119 void GenerateTypeTransition(MacroAssembler* masm);
120
121 void GenerateSmiStub(MacroAssembler* masm);
122 void GenerateSmiStubSub(MacroAssembler* masm);
123 void GenerateSmiStubBitNot(MacroAssembler* masm);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000124 void GenerateSmiCodeSub(MacroAssembler* masm,
125 Label* non_smi,
126 Label* undo,
127 Label* slow,
128 Label::Distance non_smi_near = Label::kFar,
129 Label::Distance undo_near = Label::kFar,
130 Label::Distance slow_near = Label::kFar);
131 void GenerateSmiCodeBitNot(MacroAssembler* masm,
132 Label* non_smi,
133 Label::Distance non_smi_near = Label::kFar);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000134 void GenerateSmiCodeUndo(MacroAssembler* masm);
135
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000136 void GenerateNumberStub(MacroAssembler* masm);
137 void GenerateNumberStubSub(MacroAssembler* masm);
138 void GenerateNumberStubBitNot(MacroAssembler* masm);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000139 void GenerateHeapNumberCodeSub(MacroAssembler* masm, Label* slow);
140 void GenerateHeapNumberCodeBitNot(MacroAssembler* masm, Label* slow);
141
142 void GenerateGenericStub(MacroAssembler* masm);
143 void GenerateGenericStubSub(MacroAssembler* masm);
144 void GenerateGenericStubBitNot(MacroAssembler* masm);
145 void GenerateGenericCodeFallback(MacroAssembler* masm);
146
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +0000147 virtual Code::Kind GetCodeKind() const { return Code::UNARY_OP_IC; }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000148
149 virtual InlineCacheState GetICState() {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000150 return UnaryOpIC::ToState(operand_type_);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000151 }
152
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +0000153 virtual void FinishCode(Handle<Code> code) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000154 code->set_unary_op_type(operand_type_);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000155 }
156};
157
158
ricow@chromium.org65fae842010-08-25 15:26:24 +0000159class StringHelper : public AllStatic {
160 public:
161 // Generate code for copying characters using a simple loop. This should only
162 // be used in places where the number of characters is small and the
163 // additional setup and checking in GenerateCopyCharactersREP adds too much
164 // overhead. Copying of overlapping regions is not supported.
165 static void GenerateCopyCharacters(MacroAssembler* masm,
166 Register dest,
167 Register src,
168 Register count,
169 Register scratch,
170 bool ascii);
171
172 // Generate code for copying characters using the rep movs instruction.
173 // Copies ecx characters from esi to edi. Copying of overlapping regions is
174 // not supported.
175 static void GenerateCopyCharactersREP(MacroAssembler* masm,
176 Register dest, // Must be edi.
177 Register src, // Must be esi.
178 Register count, // Must be ecx.
179 Register scratch, // Neither of above.
180 bool ascii);
181
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000182 // Probe the string table for a two character string. If the string
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000183 // requires non-standard hashing a jump to the label not_probed is
184 // performed and registers c1 and c2 are preserved. In all other
185 // cases they are clobbered. If the string is not found by probing a
186 // jump to the label not_found is performed. This jump does not
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000187 // guarantee that the string is not in the string table. If the
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000188 // string is found the code falls through with the string in
189 // register eax.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000190 static void GenerateTwoCharacterStringTableProbe(MacroAssembler* masm,
ricow@chromium.org65fae842010-08-25 15:26:24 +0000191 Register c1,
192 Register c2,
193 Register scratch1,
194 Register scratch2,
195 Register scratch3,
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000196 Label* not_probed,
ricow@chromium.org65fae842010-08-25 15:26:24 +0000197 Label* not_found);
198
199 // Generate string hash.
200 static void GenerateHashInit(MacroAssembler* masm,
201 Register hash,
202 Register character,
203 Register scratch);
204 static void GenerateHashAddCharacter(MacroAssembler* masm,
205 Register hash,
206 Register character,
207 Register scratch);
208 static void GenerateHashGetHash(MacroAssembler* masm,
209 Register hash,
210 Register scratch);
211
212 private:
213 DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
214};
215
216
217// Flag that indicates how to generate code for the stub StringAddStub.
218enum StringAddFlags {
219 NO_STRING_ADD_FLAGS = 0,
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000220 // Omit left string check in stub (left is definitely a string).
221 NO_STRING_CHECK_LEFT_IN_STUB = 1 << 0,
222 // Omit right string check in stub (right is definitely a string).
223 NO_STRING_CHECK_RIGHT_IN_STUB = 1 << 1,
224 // Omit both string checks in stub.
225 NO_STRING_CHECK_IN_STUB =
226 NO_STRING_CHECK_LEFT_IN_STUB | NO_STRING_CHECK_RIGHT_IN_STUB
ricow@chromium.org65fae842010-08-25 15:26:24 +0000227};
228
229
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000230class StringAddStub: public PlatformCodeStub {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000231 public:
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000232 explicit StringAddStub(StringAddFlags flags) : flags_(flags) {}
ricow@chromium.org65fae842010-08-25 15:26:24 +0000233
234 private:
235 Major MajorKey() { return StringAdd; }
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000236 int MinorKey() { return flags_; }
ricow@chromium.org65fae842010-08-25 15:26:24 +0000237
238 void Generate(MacroAssembler* masm);
239
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000240 void GenerateConvertArgument(MacroAssembler* masm,
241 int stack_offset,
242 Register arg,
243 Register scratch1,
244 Register scratch2,
245 Register scratch3,
246 Label* slow);
247
248 const StringAddFlags flags_;
ricow@chromium.org65fae842010-08-25 15:26:24 +0000249};
250
251
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000252class SubStringStub: public PlatformCodeStub {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000253 public:
254 SubStringStub() {}
255
256 private:
257 Major MajorKey() { return SubString; }
258 int MinorKey() { return 0; }
259
260 void Generate(MacroAssembler* masm);
261};
262
263
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000264class StringCompareStub: public PlatformCodeStub {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000265 public:
lrn@chromium.org1c092762011-05-09 09:42:16 +0000266 StringCompareStub() { }
ricow@chromium.org65fae842010-08-25 15:26:24 +0000267
lrn@chromium.org1c092762011-05-09 09:42:16 +0000268 // Compares two flat ASCII strings and returns result in eax.
ricow@chromium.org65fae842010-08-25 15:26:24 +0000269 static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
270 Register left,
271 Register right,
272 Register scratch1,
273 Register scratch2,
274 Register scratch3);
275
lrn@chromium.org1c092762011-05-09 09:42:16 +0000276 // Compares two flat ASCII strings for equality and returns result
277 // in eax.
278 static void GenerateFlatAsciiStringEquals(MacroAssembler* masm,
279 Register left,
280 Register right,
281 Register scratch1,
282 Register scratch2);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000283
lrn@chromium.org1c092762011-05-09 09:42:16 +0000284 private:
285 virtual Major MajorKey() { return StringCompare; }
286 virtual int MinorKey() { return 0; }
287 virtual void Generate(MacroAssembler* masm);
288
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000289 static void GenerateAsciiCharsCompareLoop(
290 MacroAssembler* masm,
291 Register left,
292 Register right,
293 Register length,
294 Register scratch,
295 Label* chars_not_equal,
296 Label::Distance chars_not_equal_near = Label::kFar);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000297};
298
299
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000300class NumberToStringStub: public PlatformCodeStub {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000301 public:
302 NumberToStringStub() { }
303
304 // Generate code to do a lookup in the number string cache. If the number in
305 // the register object is found in the cache the generated code falls through
306 // with the result in the result register. The object and the result register
307 // can be the same. If the number is not found in the cache the code jumps to
308 // the label not_found with only the content of register object unchanged.
309 static void GenerateLookupNumberStringCache(MacroAssembler* masm,
310 Register object,
311 Register result,
312 Register scratch1,
313 Register scratch2,
314 bool object_is_smi,
315 Label* not_found);
316
317 private:
318 Major MajorKey() { return NumberToString; }
319 int MinorKey() { return 0; }
320
321 void Generate(MacroAssembler* masm);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000322};
323
lrn@chromium.org1c092762011-05-09 09:42:16 +0000324
ulan@chromium.org750145a2013-03-07 15:14:13 +0000325class NameDictionaryLookupStub: public PlatformCodeStub {
lrn@chromium.org1c092762011-05-09 09:42:16 +0000326 public:
327 enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
328
ulan@chromium.org750145a2013-03-07 15:14:13 +0000329 NameDictionaryLookupStub(Register dictionary,
330 Register result,
331 Register index,
332 LookupMode mode)
lrn@chromium.org1c092762011-05-09 09:42:16 +0000333 : dictionary_(dictionary), result_(result), index_(index), mode_(mode) { }
334
335 void Generate(MacroAssembler* masm);
336
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000337 static void GenerateNegativeLookup(MacroAssembler* masm,
338 Label* miss,
339 Label* done,
340 Register properties,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000341 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000342 Register r0);
343
lrn@chromium.org1c092762011-05-09 09:42:16 +0000344 static void GeneratePositiveLookup(MacroAssembler* masm,
345 Label* miss,
346 Label* done,
347 Register elements,
348 Register name,
349 Register r0,
350 Register r1);
351
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000352 virtual bool SometimesSetsUpAFrame() { return false; }
353
lrn@chromium.org1c092762011-05-09 09:42:16 +0000354 private:
355 static const int kInlinedProbes = 4;
356 static const int kTotalProbes = 20;
357
358 static const int kCapacityOffset =
ulan@chromium.org750145a2013-03-07 15:14:13 +0000359 NameDictionary::kHeaderSize +
360 NameDictionary::kCapacityIndex * kPointerSize;
lrn@chromium.org1c092762011-05-09 09:42:16 +0000361
362 static const int kElementsStartOffset =
ulan@chromium.org750145a2013-03-07 15:14:13 +0000363 NameDictionary::kHeaderSize +
364 NameDictionary::kElementsStartIndex * kPointerSize;
lrn@chromium.org1c092762011-05-09 09:42:16 +0000365
ulan@chromium.org750145a2013-03-07 15:14:13 +0000366 Major MajorKey() { return NameDictionaryLookup; }
lrn@chromium.org1c092762011-05-09 09:42:16 +0000367
368 int MinorKey() {
369 return DictionaryBits::encode(dictionary_.code()) |
370 ResultBits::encode(result_.code()) |
371 IndexBits::encode(index_.code()) |
372 LookupModeBits::encode(mode_);
373 }
374
375 class DictionaryBits: public BitField<int, 0, 3> {};
376 class ResultBits: public BitField<int, 3, 3> {};
377 class IndexBits: public BitField<int, 6, 3> {};
378 class LookupModeBits: public BitField<LookupMode, 9, 1> {};
379
380 Register dictionary_;
381 Register result_;
382 Register index_;
383 LookupMode mode_;
384};
385
386
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000387class RecordWriteStub: public PlatformCodeStub {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000388 public:
389 RecordWriteStub(Register object,
390 Register value,
391 Register address,
392 RememberedSetAction remembered_set_action,
393 SaveFPRegsMode fp_mode)
394 : object_(object),
395 value_(value),
396 address_(address),
397 remembered_set_action_(remembered_set_action),
398 save_fp_regs_mode_(fp_mode),
399 regs_(object, // An input reg.
400 address, // An input reg.
401 value) { // One scratch reg.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000402 ASSERT(CpuFeatures::IsSafeForSnapshot(SSE2) || fp_mode == kDontSaveFPRegs);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000403 }
404
405 enum Mode {
406 STORE_BUFFER_ONLY,
407 INCREMENTAL,
408 INCREMENTAL_COMPACTION
409 };
410
411 virtual bool IsPregenerated();
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000412 static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000413 virtual bool SometimesSetsUpAFrame() { return false; }
414
415 static const byte kTwoByteNopInstruction = 0x3c; // Cmpb al, #imm8.
416 static const byte kTwoByteJumpInstruction = 0xeb; // Jmp #imm8.
417
418 static const byte kFiveByteNopInstruction = 0x3d; // Cmpl eax, #imm32.
419 static const byte kFiveByteJumpInstruction = 0xe9; // Jmp #imm32.
420
421 static Mode GetMode(Code* stub) {
422 byte first_instruction = stub->instruction_start()[0];
423 byte second_instruction = stub->instruction_start()[2];
424
425 if (first_instruction == kTwoByteJumpInstruction) {
426 return INCREMENTAL;
427 }
428
429 ASSERT(first_instruction == kTwoByteNopInstruction);
430
431 if (second_instruction == kFiveByteJumpInstruction) {
432 return INCREMENTAL_COMPACTION;
433 }
434
435 ASSERT(second_instruction == kFiveByteNopInstruction);
436
437 return STORE_BUFFER_ONLY;
438 }
439
440 static void Patch(Code* stub, Mode mode) {
441 switch (mode) {
442 case STORE_BUFFER_ONLY:
443 ASSERT(GetMode(stub) == INCREMENTAL ||
444 GetMode(stub) == INCREMENTAL_COMPACTION);
445 stub->instruction_start()[0] = kTwoByteNopInstruction;
446 stub->instruction_start()[2] = kFiveByteNopInstruction;
447 break;
448 case INCREMENTAL:
449 ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
450 stub->instruction_start()[0] = kTwoByteJumpInstruction;
451 break;
452 case INCREMENTAL_COMPACTION:
453 ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
454 stub->instruction_start()[0] = kTwoByteNopInstruction;
455 stub->instruction_start()[2] = kFiveByteJumpInstruction;
456 break;
457 }
458 ASSERT(GetMode(stub) == mode);
459 CPU::FlushICache(stub->instruction_start(), 7);
460 }
461
462 private:
463 // This is a helper class for freeing up 3 scratch registers, where the third
464 // is always ecx (needed for shift operations). The input is two registers
465 // that must be preserved and one scratch register provided by the caller.
466 class RegisterAllocation {
467 public:
468 RegisterAllocation(Register object,
469 Register address,
470 Register scratch0)
471 : object_orig_(object),
472 address_orig_(address),
473 scratch0_orig_(scratch0),
474 object_(object),
475 address_(address),
476 scratch0_(scratch0) {
477 ASSERT(!AreAliased(scratch0, object, address, no_reg));
478 scratch1_ = GetRegThatIsNotEcxOr(object_, address_, scratch0_);
479 if (scratch0.is(ecx)) {
480 scratch0_ = GetRegThatIsNotEcxOr(object_, address_, scratch1_);
481 }
482 if (object.is(ecx)) {
483 object_ = GetRegThatIsNotEcxOr(address_, scratch0_, scratch1_);
484 }
485 if (address.is(ecx)) {
486 address_ = GetRegThatIsNotEcxOr(object_, scratch0_, scratch1_);
487 }
488 ASSERT(!AreAliased(scratch0_, object_, address_, ecx));
489 }
490
491 void Save(MacroAssembler* masm) {
492 ASSERT(!address_orig_.is(object_));
493 ASSERT(object_.is(object_orig_) || address_.is(address_orig_));
494 ASSERT(!AreAliased(object_, address_, scratch1_, scratch0_));
495 ASSERT(!AreAliased(object_orig_, address_, scratch1_, scratch0_));
496 ASSERT(!AreAliased(object_, address_orig_, scratch1_, scratch0_));
497 // We don't have to save scratch0_orig_ because it was given to us as
498 // a scratch register. But if we had to switch to a different reg then
499 // we should save the new scratch0_.
500 if (!scratch0_.is(scratch0_orig_)) masm->push(scratch0_);
501 if (!ecx.is(scratch0_orig_) &&
502 !ecx.is(object_orig_) &&
503 !ecx.is(address_orig_)) {
504 masm->push(ecx);
505 }
506 masm->push(scratch1_);
507 if (!address_.is(address_orig_)) {
508 masm->push(address_);
509 masm->mov(address_, address_orig_);
510 }
511 if (!object_.is(object_orig_)) {
512 masm->push(object_);
513 masm->mov(object_, object_orig_);
514 }
515 }
516
517 void Restore(MacroAssembler* masm) {
518 // These will have been preserved the entire time, so we just need to move
519 // them back. Only in one case is the orig_ reg different from the plain
520 // one, since only one of them can alias with ecx.
521 if (!object_.is(object_orig_)) {
522 masm->mov(object_orig_, object_);
523 masm->pop(object_);
524 }
525 if (!address_.is(address_orig_)) {
526 masm->mov(address_orig_, address_);
527 masm->pop(address_);
528 }
529 masm->pop(scratch1_);
530 if (!ecx.is(scratch0_orig_) &&
531 !ecx.is(object_orig_) &&
532 !ecx.is(address_orig_)) {
533 masm->pop(ecx);
534 }
535 if (!scratch0_.is(scratch0_orig_)) masm->pop(scratch0_);
536 }
537
538 // If we have to call into C then we need to save and restore all caller-
539 // saved registers that were not already preserved. The caller saved
540 // registers are eax, ecx and edx. The three scratch registers (incl. ecx)
541 // will be restored by other means so we don't bother pushing them here.
542 void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
543 if (!scratch0_.is(eax) && !scratch1_.is(eax)) masm->push(eax);
544 if (!scratch0_.is(edx) && !scratch1_.is(edx)) masm->push(edx);
545 if (mode == kSaveFPRegs) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000546 CpuFeatureScope scope(masm, SSE2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000547 masm->sub(esp,
548 Immediate(kDoubleSize * (XMMRegister::kNumRegisters - 1)));
549 // Save all XMM registers except XMM0.
550 for (int i = XMMRegister::kNumRegisters - 1; i > 0; i--) {
551 XMMRegister reg = XMMRegister::from_code(i);
552 masm->movdbl(Operand(esp, (i - 1) * kDoubleSize), reg);
553 }
554 }
555 }
556
557 inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
558 SaveFPRegsMode mode) {
559 if (mode == kSaveFPRegs) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000560 CpuFeatureScope scope(masm, SSE2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000561 // Restore all XMM registers except XMM0.
562 for (int i = XMMRegister::kNumRegisters - 1; i > 0; i--) {
563 XMMRegister reg = XMMRegister::from_code(i);
564 masm->movdbl(reg, Operand(esp, (i - 1) * kDoubleSize));
565 }
566 masm->add(esp,
567 Immediate(kDoubleSize * (XMMRegister::kNumRegisters - 1)));
568 }
569 if (!scratch0_.is(edx) && !scratch1_.is(edx)) masm->pop(edx);
570 if (!scratch0_.is(eax) && !scratch1_.is(eax)) masm->pop(eax);
571 }
572
573 inline Register object() { return object_; }
574 inline Register address() { return address_; }
575 inline Register scratch0() { return scratch0_; }
576 inline Register scratch1() { return scratch1_; }
577
578 private:
579 Register object_orig_;
580 Register address_orig_;
581 Register scratch0_orig_;
582 Register object_;
583 Register address_;
584 Register scratch0_;
585 Register scratch1_;
586 // Third scratch register is always ecx.
587
588 Register GetRegThatIsNotEcxOr(Register r1,
589 Register r2,
590 Register r3) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000591 for (int i = 0; i < Register::NumAllocatableRegisters(); i++) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000592 Register candidate = Register::FromAllocationIndex(i);
593 if (candidate.is(ecx)) continue;
594 if (candidate.is(r1)) continue;
595 if (candidate.is(r2)) continue;
596 if (candidate.is(r3)) continue;
597 return candidate;
598 }
599 UNREACHABLE();
600 return no_reg;
601 }
602 friend class RecordWriteStub;
603 };
604
605 enum OnNoNeedToInformIncrementalMarker {
606 kReturnOnNoNeedToInformIncrementalMarker,
607 kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
608 }
609;
610 void Generate(MacroAssembler* masm);
611 void GenerateIncremental(MacroAssembler* masm, Mode mode);
612 void CheckNeedsToInformIncrementalMarker(
613 MacroAssembler* masm,
614 OnNoNeedToInformIncrementalMarker on_no_need,
615 Mode mode);
616 void InformIncrementalMarker(MacroAssembler* masm, Mode mode);
617
618 Major MajorKey() { return RecordWrite; }
619
620 int MinorKey() {
621 return ObjectBits::encode(object_.code()) |
622 ValueBits::encode(value_.code()) |
623 AddressBits::encode(address_.code()) |
624 RememberedSetActionBits::encode(remembered_set_action_) |
625 SaveFPRegsModeBits::encode(save_fp_regs_mode_);
626 }
627
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000628 void Activate(Code* code) {
629 code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
630 }
631
632 class ObjectBits: public BitField<int, 0, 3> {};
633 class ValueBits: public BitField<int, 3, 3> {};
634 class AddressBits: public BitField<int, 6, 3> {};
635 class RememberedSetActionBits: public BitField<RememberedSetAction, 9, 1> {};
636 class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 10, 1> {};
637
638 Register object_;
639 Register value_;
640 Register address_;
641 RememberedSetAction remembered_set_action_;
642 SaveFPRegsMode save_fp_regs_mode_;
643 RegisterAllocation regs_;
644};
645
646
ricow@chromium.org65fae842010-08-25 15:26:24 +0000647} } // namespace v8::internal
648
649#endif // V8_IA32_CODE_STUBS_IA32_H_