blob: 6a1a18f830a6c78f6b024b1e65b897a121835e7e [file] [log] [blame]
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001// Copyright 2011 the V8 project authors. All rights reserved.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002// 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_X64_CODE_STUBS_X64_H_
29#define V8_X64_CODE_STUBS_X64_H_
30
31#include "ic-inl.h"
32#include "type-info.h"
33
34namespace v8 {
35namespace internal {
36
37
38// Compute a transcendental math function natively, or call the
39// TranscendentalCache runtime function.
40class TranscendentalCacheStub: public CodeStub {
41 public:
Ben Murdoche0cee9b2011-05-25 10:26:03 +010042 enum ArgumentType {
43 TAGGED = 0,
44 UNTAGGED = 1 << TranscendentalCache::kTranscendentalTypeBits
45 };
46
47 explicit TranscendentalCacheStub(TranscendentalCache::Type type,
48 ArgumentType argument_type)
49 : type_(type), argument_type_(argument_type) {}
Kristian Monsen80d68ea2010-09-08 11:05:35 +010050 void Generate(MacroAssembler* masm);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010051 static void GenerateOperation(MacroAssembler* masm,
52 TranscendentalCache::Type type);
Kristian Monsen80d68ea2010-09-08 11:05:35 +010053 private:
54 TranscendentalCache::Type type_;
Ben Murdoche0cee9b2011-05-25 10:26:03 +010055 ArgumentType argument_type_;
56
Kristian Monsen80d68ea2010-09-08 11:05:35 +010057 Major MajorKey() { return TranscendentalCache; }
Ben Murdoche0cee9b2011-05-25 10:26:03 +010058 int MinorKey() { return type_ | argument_type_; }
Kristian Monsen80d68ea2010-09-08 11:05:35 +010059 Runtime::FunctionId RuntimeFunction();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010060};
61
62
63class StoreBufferOverflowStub: public CodeStub {
64 public:
65 explicit StoreBufferOverflowStub(SaveFPRegsMode save_fp)
66 : save_doubles_(save_fp) { }
67
68 void Generate(MacroAssembler* masm);
69
70 virtual bool IsPregenerated() { return true; }
71 static void GenerateFixedRegStubsAheadOfTime();
72 virtual bool SometimesSetsUpAFrame() { return false; }
73
74 private:
75 SaveFPRegsMode save_doubles_;
76
77 Major MajorKey() { return StoreBufferOverflow; }
78 int MinorKey() { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; }
79};
80
81
82// Flag that indicates how to generate code for the stub GenericBinaryOpStub.
83enum GenericBinaryFlags {
84 NO_GENERIC_BINARY_FLAGS = 0,
85 NO_SMI_CODE_IN_STUB = 1 << 0 // Omit smi code in stub.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000086};
87
88
Ben Murdoch257744e2011-11-30 15:57:28 +000089class UnaryOpStub: public CodeStub {
Ben Murdoch086aeea2011-05-13 15:57:08 +010090 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000091 UnaryOpStub(Token::Value op,
92 UnaryOverwriteMode mode,
93 UnaryOpIC::TypeInfo operand_type = UnaryOpIC::UNINITIALIZED)
Ben Murdoch086aeea2011-05-13 15:57:08 +010094 : op_(op),
95 mode_(mode),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000096 operand_type_(operand_type) {
Ben Murdoch257744e2011-11-30 15:57:28 +000097 }
98
99 private:
100 Token::Value op_;
101 UnaryOverwriteMode mode_;
102
103 // Operand type information determined at runtime.
104 UnaryOpIC::TypeInfo operand_type_;
105
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000106 virtual void PrintName(StringStream* stream);
Ben Murdoch257744e2011-11-30 15:57:28 +0000107
108 class ModeBits: public BitField<UnaryOverwriteMode, 0, 1> {};
109 class OpBits: public BitField<Token::Value, 1, 7> {};
110 class OperandTypeInfoBits: public BitField<UnaryOpIC::TypeInfo, 8, 3> {};
111
112 Major MajorKey() { return UnaryOp; }
113 int MinorKey() {
114 return ModeBits::encode(mode_)
115 | OpBits::encode(op_)
116 | OperandTypeInfoBits::encode(operand_type_);
117 }
118
119 // Note: A lot of the helper functions below will vanish when we use virtual
120 // function instead of switch more often.
121 void Generate(MacroAssembler* masm);
122
123 void GenerateTypeTransition(MacroAssembler* masm);
124
125 void GenerateSmiStub(MacroAssembler* masm);
126 void GenerateSmiStubSub(MacroAssembler* masm);
127 void GenerateSmiStubBitNot(MacroAssembler* masm);
128 void GenerateSmiCodeSub(MacroAssembler* masm,
129 Label* non_smi,
130 Label* slow,
131 Label::Distance non_smi_near = Label::kFar,
132 Label::Distance slow_near = Label::kFar);
133 void GenerateSmiCodeBitNot(MacroAssembler* masm,
134 Label* non_smi,
135 Label::Distance non_smi_near);
136
137 void GenerateHeapNumberStub(MacroAssembler* masm);
138 void GenerateHeapNumberStubSub(MacroAssembler* masm);
139 void GenerateHeapNumberStubBitNot(MacroAssembler* masm);
140 void GenerateHeapNumberCodeSub(MacroAssembler* masm, Label* slow);
141 void GenerateHeapNumberCodeBitNot(MacroAssembler* masm, Label* slow);
142
143 void GenerateGenericStub(MacroAssembler* masm);
144 void GenerateGenericStubSub(MacroAssembler* masm);
145 void GenerateGenericStubBitNot(MacroAssembler* masm);
146 void GenerateGenericCodeFallback(MacroAssembler* masm);
147
148 virtual int GetCodeKind() { return Code::UNARY_OP_IC; }
149
150 virtual InlineCacheState GetICState() {
151 return UnaryOpIC::ToState(operand_type_);
152 }
153
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100154 virtual void FinishCode(Handle<Code> code) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000155 code->set_unary_op_type(operand_type_);
156 }
157};
158
159
160class BinaryOpStub: public CodeStub {
161 public:
162 BinaryOpStub(Token::Value op, OverwriteMode mode)
163 : op_(op),
164 mode_(mode),
165 operands_type_(BinaryOpIC::UNINITIALIZED),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000166 result_type_(BinaryOpIC::UNINITIALIZED) {
Ben Murdoch086aeea2011-05-13 15:57:08 +0100167 ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
168 }
169
Ben Murdoch257744e2011-11-30 15:57:28 +0000170 BinaryOpStub(
Ben Murdoch086aeea2011-05-13 15:57:08 +0100171 int key,
Ben Murdoch257744e2011-11-30 15:57:28 +0000172 BinaryOpIC::TypeInfo operands_type,
173 BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED)
Ben Murdoch086aeea2011-05-13 15:57:08 +0100174 : op_(OpBits::decode(key)),
175 mode_(ModeBits::decode(key)),
176 operands_type_(operands_type),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000177 result_type_(result_type) { }
Ben Murdoch086aeea2011-05-13 15:57:08 +0100178
179 private:
180 enum SmiCodeGenerateHeapNumberResults {
181 ALLOW_HEAPNUMBER_RESULTS,
182 NO_HEAPNUMBER_RESULTS
183 };
184
185 Token::Value op_;
186 OverwriteMode mode_;
187
188 // Operand type information determined at runtime.
Ben Murdoch257744e2011-11-30 15:57:28 +0000189 BinaryOpIC::TypeInfo operands_type_;
190 BinaryOpIC::TypeInfo result_type_;
Ben Murdoch086aeea2011-05-13 15:57:08 +0100191
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000192 virtual void PrintName(StringStream* stream);
Ben Murdoch086aeea2011-05-13 15:57:08 +0100193
194 // Minor key encoding in 15 bits RRRTTTOOOOOOOMM.
195 class ModeBits: public BitField<OverwriteMode, 0, 2> {};
196 class OpBits: public BitField<Token::Value, 2, 7> {};
Ben Murdoch257744e2011-11-30 15:57:28 +0000197 class OperandTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 9, 3> {};
198 class ResultTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 12, 3> {};
Ben Murdoch086aeea2011-05-13 15:57:08 +0100199
Ben Murdoch257744e2011-11-30 15:57:28 +0000200 Major MajorKey() { return BinaryOp; }
Ben Murdoch086aeea2011-05-13 15:57:08 +0100201 int MinorKey() {
202 return OpBits::encode(op_)
203 | ModeBits::encode(mode_)
204 | OperandTypeInfoBits::encode(operands_type_)
205 | ResultTypeInfoBits::encode(result_type_);
206 }
207
208 void Generate(MacroAssembler* masm);
209 void GenerateGeneric(MacroAssembler* masm);
210 void GenerateSmiCode(MacroAssembler* masm,
211 Label* slow,
212 SmiCodeGenerateHeapNumberResults heapnumber_results);
Steve Block1e0659c2011-05-24 12:43:12 +0100213 void GenerateFloatingPointCode(MacroAssembler* masm,
214 Label* allocation_failure,
215 Label* non_numeric_failure);
216 void GenerateStringAddCode(MacroAssembler* masm);
217 void GenerateCallRuntimeCode(MacroAssembler* masm);
Ben Murdoch086aeea2011-05-13 15:57:08 +0100218 void GenerateLoadArguments(MacroAssembler* masm);
219 void GenerateReturn(MacroAssembler* masm);
220 void GenerateUninitializedStub(MacroAssembler* masm);
221 void GenerateSmiStub(MacroAssembler* masm);
222 void GenerateInt32Stub(MacroAssembler* masm);
223 void GenerateHeapNumberStub(MacroAssembler* masm);
Steve Block44f0eee2011-05-26 01:26:41 +0100224 void GenerateOddballStub(MacroAssembler* masm);
Ben Murdoch086aeea2011-05-13 15:57:08 +0100225 void GenerateStringStub(MacroAssembler* masm);
Ben Murdoch257744e2011-11-30 15:57:28 +0000226 void GenerateBothStringStub(MacroAssembler* masm);
Ben Murdoch086aeea2011-05-13 15:57:08 +0100227 void GenerateGenericStub(MacroAssembler* masm);
228
229 void GenerateHeapResultAllocation(MacroAssembler* masm, Label* alloc_failure);
230 void GenerateRegisterArgsPush(MacroAssembler* masm);
231 void GenerateTypeTransition(MacroAssembler* masm);
232 void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm);
233
Ben Murdoch257744e2011-11-30 15:57:28 +0000234 virtual int GetCodeKind() { return Code::BINARY_OP_IC; }
Ben Murdoch086aeea2011-05-13 15:57:08 +0100235
236 virtual InlineCacheState GetICState() {
Ben Murdoch257744e2011-11-30 15:57:28 +0000237 return BinaryOpIC::ToState(operands_type_);
Ben Murdoch086aeea2011-05-13 15:57:08 +0100238 }
239
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100240 virtual void FinishCode(Handle<Code> code) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000241 code->set_binary_op_type(operands_type_);
242 code->set_binary_op_result_type(result_type_);
Ben Murdoch086aeea2011-05-13 15:57:08 +0100243 }
244
245 friend class CodeGenerator;
246};
247
248
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100249class StringHelper : public AllStatic {
250 public:
251 // Generate code for copying characters using a simple loop. This should only
252 // be used in places where the number of characters is small and the
253 // additional setup and checking in GenerateCopyCharactersREP adds too much
254 // overhead. Copying of overlapping regions is not supported.
255 static void GenerateCopyCharacters(MacroAssembler* masm,
256 Register dest,
257 Register src,
258 Register count,
259 bool ascii);
260
261 // Generate code for copying characters using the rep movs instruction.
262 // Copies rcx characters from rsi to rdi. Copying of overlapping regions is
263 // not supported.
264 static void GenerateCopyCharactersREP(MacroAssembler* masm,
265 Register dest, // Must be rdi.
266 Register src, // Must be rsi.
267 Register count, // Must be rcx.
268 bool ascii);
269
270
271 // Probe the symbol table for a two character string. If the string is
272 // not found by probing a jump to the label not_found is performed. This jump
273 // does not guarantee that the string is not in the symbol table. If the
274 // string is found the code falls through with the string in register rax.
275 static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
276 Register c1,
277 Register c2,
278 Register scratch1,
279 Register scratch2,
280 Register scratch3,
281 Register scratch4,
282 Label* not_found);
283
284 // Generate string hash.
285 static void GenerateHashInit(MacroAssembler* masm,
286 Register hash,
287 Register character,
288 Register scratch);
289 static void GenerateHashAddCharacter(MacroAssembler* masm,
290 Register hash,
291 Register character,
292 Register scratch);
293 static void GenerateHashGetHash(MacroAssembler* masm,
294 Register hash,
295 Register scratch);
296
297 private:
298 DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
299};
300
301
302// Flag that indicates how to generate code for the stub StringAddStub.
303enum StringAddFlags {
304 NO_STRING_ADD_FLAGS = 0,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100305 // Omit left string check in stub (left is definitely a string).
306 NO_STRING_CHECK_LEFT_IN_STUB = 1 << 0,
307 // Omit right string check in stub (right is definitely a string).
308 NO_STRING_CHECK_RIGHT_IN_STUB = 1 << 1,
309 // Omit both string checks in stub.
310 NO_STRING_CHECK_IN_STUB =
311 NO_STRING_CHECK_LEFT_IN_STUB | NO_STRING_CHECK_RIGHT_IN_STUB
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100312};
313
314
315class StringAddStub: public CodeStub {
316 public:
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100317 explicit StringAddStub(StringAddFlags flags) : flags_(flags) {}
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100318
319 private:
320 Major MajorKey() { return StringAdd; }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100321 int MinorKey() { return flags_; }
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100322
323 void Generate(MacroAssembler* masm);
324
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100325 void GenerateConvertArgument(MacroAssembler* masm,
326 int stack_offset,
327 Register arg,
328 Register scratch1,
329 Register scratch2,
330 Register scratch3,
331 Label* slow);
332
333 const StringAddFlags flags_;
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100334};
335
336
337class SubStringStub: public CodeStub {
338 public:
339 SubStringStub() {}
340
341 private:
342 Major MajorKey() { return SubString; }
343 int MinorKey() { return 0; }
344
345 void Generate(MacroAssembler* masm);
346};
347
348
349class StringCompareStub: public CodeStub {
350 public:
Ben Murdoch257744e2011-11-30 15:57:28 +0000351 StringCompareStub() {}
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100352
Ben Murdoch257744e2011-11-30 15:57:28 +0000353 // Compares two flat ASCII strings and returns result in rax.
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100354 static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
355 Register left,
356 Register right,
357 Register scratch1,
358 Register scratch2,
359 Register scratch3,
360 Register scratch4);
361
Ben Murdoch257744e2011-11-30 15:57:28 +0000362 // Compares two flat ASCII strings for equality and returns result
363 // in rax.
364 static void GenerateFlatAsciiStringEquals(MacroAssembler* masm,
365 Register left,
366 Register right,
367 Register scratch1,
368 Register scratch2);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100369
Ben Murdoch257744e2011-11-30 15:57:28 +0000370 private:
371 virtual Major MajorKey() { return StringCompare; }
372 virtual int MinorKey() { return 0; }
373 virtual void Generate(MacroAssembler* masm);
374
375 static void GenerateAsciiCharsCompareLoop(
376 MacroAssembler* masm,
377 Register left,
378 Register right,
379 Register length,
380 Register scratch,
381 Label* chars_not_equal,
382 Label::Distance near_jump = Label::kFar);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100383};
384
385
386class NumberToStringStub: public CodeStub {
387 public:
388 NumberToStringStub() { }
389
390 // Generate code to do a lookup in the number string cache. If the number in
391 // the register object is found in the cache the generated code falls through
392 // with the result in the result register. The object and the result register
393 // can be the same. If the number is not found in the cache the code jumps to
394 // the label not_found with only the content of register object unchanged.
395 static void GenerateLookupNumberStringCache(MacroAssembler* masm,
396 Register object,
397 Register result,
398 Register scratch1,
399 Register scratch2,
400 bool object_is_smi,
401 Label* not_found);
402
403 private:
404 static void GenerateConvertHashCodeToIndex(MacroAssembler* masm,
405 Register hash,
406 Register mask);
407
408 Major MajorKey() { return NumberToString; }
409 int MinorKey() { return 0; }
410
411 void Generate(MacroAssembler* masm);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100412};
413
414
Ben Murdoch257744e2011-11-30 15:57:28 +0000415class StringDictionaryLookupStub: public CodeStub {
416 public:
417 enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
418
419 StringDictionaryLookupStub(Register dictionary,
420 Register result,
421 Register index,
422 LookupMode mode)
423 : dictionary_(dictionary), result_(result), index_(index), mode_(mode) { }
424
425 void Generate(MacroAssembler* masm);
426
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100427 static void GenerateNegativeLookup(MacroAssembler* masm,
428 Label* miss,
429 Label* done,
430 Register properties,
431 Handle<String> name,
432 Register r0);
Ben Murdoch257744e2011-11-30 15:57:28 +0000433
434 static void GeneratePositiveLookup(MacroAssembler* masm,
435 Label* miss,
436 Label* done,
437 Register elements,
438 Register name,
439 Register r0,
440 Register r1);
441
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100442 virtual bool SometimesSetsUpAFrame() { return false; }
443
Ben Murdoch257744e2011-11-30 15:57:28 +0000444 private:
445 static const int kInlinedProbes = 4;
446 static const int kTotalProbes = 20;
447
448 static const int kCapacityOffset =
449 StringDictionary::kHeaderSize +
450 StringDictionary::kCapacityIndex * kPointerSize;
451
452 static const int kElementsStartOffset =
453 StringDictionary::kHeaderSize +
454 StringDictionary::kElementsStartIndex * kPointerSize;
455
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100456 Major MajorKey() { return StringDictionaryLookup; }
Ben Murdoch257744e2011-11-30 15:57:28 +0000457
458 int MinorKey() {
459 return DictionaryBits::encode(dictionary_.code()) |
460 ResultBits::encode(result_.code()) |
461 IndexBits::encode(index_.code()) |
462 LookupModeBits::encode(mode_);
463 }
464
465 class DictionaryBits: public BitField<int, 0, 4> {};
466 class ResultBits: public BitField<int, 4, 4> {};
467 class IndexBits: public BitField<int, 8, 4> {};
468 class LookupModeBits: public BitField<LookupMode, 12, 1> {};
469
470 Register dictionary_;
471 Register result_;
472 Register index_;
473 LookupMode mode_;
474};
475
476
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100477class RecordWriteStub: public CodeStub {
478 public:
479 RecordWriteStub(Register object,
480 Register value,
481 Register address,
482 RememberedSetAction remembered_set_action,
483 SaveFPRegsMode fp_mode)
484 : object_(object),
485 value_(value),
486 address_(address),
487 remembered_set_action_(remembered_set_action),
488 save_fp_regs_mode_(fp_mode),
489 regs_(object, // An input reg.
490 address, // An input reg.
491 value) { // One scratch reg.
492 }
493
494 enum Mode {
495 STORE_BUFFER_ONLY,
496 INCREMENTAL,
497 INCREMENTAL_COMPACTION
498 };
499
500 virtual bool IsPregenerated();
501 static void GenerateFixedRegStubsAheadOfTime();
502 virtual bool SometimesSetsUpAFrame() { return false; }
503
504 static const byte kTwoByteNopInstruction = 0x3c; // Cmpb al, #imm8.
505 static const byte kTwoByteJumpInstruction = 0xeb; // Jmp #imm8.
506
507 static const byte kFiveByteNopInstruction = 0x3d; // Cmpl eax, #imm32.
508 static const byte kFiveByteJumpInstruction = 0xe9; // Jmp #imm32.
509
510 static Mode GetMode(Code* stub) {
511 byte first_instruction = stub->instruction_start()[0];
512 byte second_instruction = stub->instruction_start()[2];
513
514 if (first_instruction == kTwoByteJumpInstruction) {
515 return INCREMENTAL;
516 }
517
518 ASSERT(first_instruction == kTwoByteNopInstruction);
519
520 if (second_instruction == kFiveByteJumpInstruction) {
521 return INCREMENTAL_COMPACTION;
522 }
523
524 ASSERT(second_instruction == kFiveByteNopInstruction);
525
526 return STORE_BUFFER_ONLY;
527 }
528
529 static void Patch(Code* stub, Mode mode) {
530 switch (mode) {
531 case STORE_BUFFER_ONLY:
532 ASSERT(GetMode(stub) == INCREMENTAL ||
533 GetMode(stub) == INCREMENTAL_COMPACTION);
534 stub->instruction_start()[0] = kTwoByteNopInstruction;
535 stub->instruction_start()[2] = kFiveByteNopInstruction;
536 break;
537 case INCREMENTAL:
538 ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
539 stub->instruction_start()[0] = kTwoByteJumpInstruction;
540 break;
541 case INCREMENTAL_COMPACTION:
542 ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
543 stub->instruction_start()[0] = kTwoByteNopInstruction;
544 stub->instruction_start()[2] = kFiveByteJumpInstruction;
545 break;
546 }
547 ASSERT(GetMode(stub) == mode);
548 CPU::FlushICache(stub->instruction_start(), 7);
549 }
550
551 private:
552 // This is a helper class for freeing up 3 scratch registers, where the third
553 // is always rcx (needed for shift operations). The input is two registers
554 // that must be preserved and one scratch register provided by the caller.
555 class RegisterAllocation {
556 public:
557 RegisterAllocation(Register object,
558 Register address,
559 Register scratch0)
560 : object_orig_(object),
561 address_orig_(address),
562 scratch0_orig_(scratch0),
563 object_(object),
564 address_(address),
565 scratch0_(scratch0) {
566 ASSERT(!AreAliased(scratch0, object, address, no_reg));
567 scratch1_ = GetRegThatIsNotRcxOr(object_, address_, scratch0_);
568 if (scratch0.is(rcx)) {
569 scratch0_ = GetRegThatIsNotRcxOr(object_, address_, scratch1_);
570 }
571 if (object.is(rcx)) {
572 object_ = GetRegThatIsNotRcxOr(address_, scratch0_, scratch1_);
573 }
574 if (address.is(rcx)) {
575 address_ = GetRegThatIsNotRcxOr(object_, scratch0_, scratch1_);
576 }
577 ASSERT(!AreAliased(scratch0_, object_, address_, rcx));
578 }
579
580 void Save(MacroAssembler* masm) {
581 ASSERT(!address_orig_.is(object_));
582 ASSERT(object_.is(object_orig_) || address_.is(address_orig_));
583 ASSERT(!AreAliased(object_, address_, scratch1_, scratch0_));
584 ASSERT(!AreAliased(object_orig_, address_, scratch1_, scratch0_));
585 ASSERT(!AreAliased(object_, address_orig_, scratch1_, scratch0_));
586 // We don't have to save scratch0_orig_ because it was given to us as
587 // a scratch register. But if we had to switch to a different reg then
588 // we should save the new scratch0_.
589 if (!scratch0_.is(scratch0_orig_)) masm->push(scratch0_);
590 if (!rcx.is(scratch0_orig_) &&
591 !rcx.is(object_orig_) &&
592 !rcx.is(address_orig_)) {
593 masm->push(rcx);
594 }
595 masm->push(scratch1_);
596 if (!address_.is(address_orig_)) {
597 masm->push(address_);
598 masm->movq(address_, address_orig_);
599 }
600 if (!object_.is(object_orig_)) {
601 masm->push(object_);
602 masm->movq(object_, object_orig_);
603 }
604 }
605
606 void Restore(MacroAssembler* masm) {
607 // These will have been preserved the entire time, so we just need to move
608 // them back. Only in one case is the orig_ reg different from the plain
609 // one, since only one of them can alias with rcx.
610 if (!object_.is(object_orig_)) {
611 masm->movq(object_orig_, object_);
612 masm->pop(object_);
613 }
614 if (!address_.is(address_orig_)) {
615 masm->movq(address_orig_, address_);
616 masm->pop(address_);
617 }
618 masm->pop(scratch1_);
619 if (!rcx.is(scratch0_orig_) &&
620 !rcx.is(object_orig_) &&
621 !rcx.is(address_orig_)) {
622 masm->pop(rcx);
623 }
624 if (!scratch0_.is(scratch0_orig_)) masm->pop(scratch0_);
625 }
626
627 // If we have to call into C then we need to save and restore all caller-
628 // saved registers that were not already preserved.
629
630 // The three scratch registers (incl. rcx) will be restored by other means
631 // so we don't bother pushing them here. Rbx, rbp and r12-15 are callee
632 // save and don't need to be preserved.
633 void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
634 masm->PushCallerSaved(mode, scratch0_, scratch1_, rcx);
635 }
636
637 inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
638 SaveFPRegsMode mode) {
639 masm->PopCallerSaved(mode, scratch0_, scratch1_, rcx);
640 }
641
642 inline Register object() { return object_; }
643 inline Register address() { return address_; }
644 inline Register scratch0() { return scratch0_; }
645 inline Register scratch1() { return scratch1_; }
646
647 private:
648 Register object_orig_;
649 Register address_orig_;
650 Register scratch0_orig_;
651 Register object_;
652 Register address_;
653 Register scratch0_;
654 Register scratch1_;
655 // Third scratch register is always rcx.
656
657 Register GetRegThatIsNotRcxOr(Register r1,
658 Register r2,
659 Register r3) {
660 for (int i = 0; i < Register::kNumAllocatableRegisters; i++) {
661 Register candidate = Register::FromAllocationIndex(i);
662 if (candidate.is(rcx)) continue;
663 if (candidate.is(r1)) continue;
664 if (candidate.is(r2)) continue;
665 if (candidate.is(r3)) continue;
666 return candidate;
667 }
668 UNREACHABLE();
669 return no_reg;
670 }
671 friend class RecordWriteStub;
672 };
673
674 enum OnNoNeedToInformIncrementalMarker {
675 kReturnOnNoNeedToInformIncrementalMarker,
676 kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
677 };
678
679 void Generate(MacroAssembler* masm);
680 void GenerateIncremental(MacroAssembler* masm, Mode mode);
681 void CheckNeedsToInformIncrementalMarker(
682 MacroAssembler* masm,
683 OnNoNeedToInformIncrementalMarker on_no_need,
684 Mode mode);
685 void InformIncrementalMarker(MacroAssembler* masm, Mode mode);
686
687 Major MajorKey() { return RecordWrite; }
688
689 int MinorKey() {
690 return ObjectBits::encode(object_.code()) |
691 ValueBits::encode(value_.code()) |
692 AddressBits::encode(address_.code()) |
693 RememberedSetActionBits::encode(remembered_set_action_) |
694 SaveFPRegsModeBits::encode(save_fp_regs_mode_);
695 }
696
697 void Activate(Code* code) {
698 code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
699 }
700
701 class ObjectBits: public BitField<int, 0, 4> {};
702 class ValueBits: public BitField<int, 4, 4> {};
703 class AddressBits: public BitField<int, 8, 4> {};
704 class RememberedSetActionBits: public BitField<RememberedSetAction, 12, 1> {};
705 class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 13, 1> {};
706
707 Register object_;
708 Register value_;
709 Register address_;
710 RememberedSetAction remembered_set_action_;
711 SaveFPRegsMode save_fp_regs_mode_;
712 Label slow_;
713 RegisterAllocation regs_;
714};
715
716
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100717} } // namespace v8::internal
718
719#endif // V8_X64_CODE_STUBS_X64_H_