blob: 803a711de9694efeacc907db44d1f7342980d006 [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +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_IA32_CODE_STUBS_IA32_H_
29#define V8_IA32_CODE_STUBS_IA32_H_
30
31#include "macro-assembler.h"
32#include "code-stubs.h"
33#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.
41class TranscendentalCacheStub: public CodeStub {
42 public:
Ben Murdochb0fe1622011-05-05 13:52:32 +010043 enum ArgumentType {
44 TAGGED = 0,
45 UNTAGGED = 1 << TranscendentalCache::kTranscendentalTypeBits
46 };
47
Ben Murdoche0cee9b2011-05-25 10:26:03 +010048 TranscendentalCacheStub(TranscendentalCache::Type type,
49 ArgumentType argument_type)
Ben Murdochb0fe1622011-05-05 13:52:32 +010050 : type_(type), argument_type_(argument_type) {}
Kristian Monsen80d68ea2010-09-08 11:05:35 +010051 void Generate(MacroAssembler* masm);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010052 static void GenerateOperation(MacroAssembler* masm,
53 TranscendentalCache::Type type);
Kristian Monsen80d68ea2010-09-08 11:05:35 +010054 private:
55 TranscendentalCache::Type type_;
Ben Murdochb0fe1622011-05-05 13:52:32 +010056 ArgumentType argument_type_;
57
Kristian Monsen80d68ea2010-09-08 11:05:35 +010058 Major MajorKey() { return TranscendentalCache; }
Ben Murdochb0fe1622011-05-05 13:52:32 +010059 int MinorKey() { return type_ | argument_type_; }
Kristian Monsen80d68ea2010-09-08 11:05:35 +010060 Runtime::FunctionId RuntimeFunction();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010061};
62
63
64class StoreBufferOverflowStub: public CodeStub {
65 public:
66 explicit StoreBufferOverflowStub(SaveFPRegsMode save_fp)
67 : save_doubles_(save_fp) { }
68
69 void Generate(MacroAssembler* masm);
70
71 virtual bool IsPregenerated() { return true; }
72 static void GenerateFixedRegStubsAheadOfTime();
73 virtual bool SometimesSetsUpAFrame() { return false; }
74
75 private:
76 SaveFPRegsMode save_doubles_;
77
78 Major MajorKey() { return StoreBufferOverflow; }
79 int MinorKey() { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; }
Ben Murdoch592a9fc2012-03-05 11:04:45 +000080};
81
82
Ben Murdoch257744e2011-11-30 15:57:28 +000083class UnaryOpStub: public CodeStub {
Ben Murdochb0fe1622011-05-05 13:52:32 +010084 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000085 UnaryOpStub(Token::Value op,
86 UnaryOverwriteMode mode,
87 UnaryOpIC::TypeInfo operand_type = UnaryOpIC::UNINITIALIZED)
Ben Murdochb0fe1622011-05-05 13:52:32 +010088 : op_(op),
89 mode_(mode),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000090 operand_type_(operand_type) {
Ben Murdoch257744e2011-11-30 15:57:28 +000091 }
92
93 private:
94 Token::Value op_;
95 UnaryOverwriteMode mode_;
96
97 // Operand type information determined at runtime.
98 UnaryOpIC::TypeInfo operand_type_;
99
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000100 virtual void PrintName(StringStream* stream);
Ben Murdoch257744e2011-11-30 15:57:28 +0000101
102 class ModeBits: public BitField<UnaryOverwriteMode, 0, 1> {};
103 class OpBits: public BitField<Token::Value, 1, 7> {};
104 class OperandTypeInfoBits: public BitField<UnaryOpIC::TypeInfo, 8, 3> {};
105
106 Major MajorKey() { return UnaryOp; }
107 int MinorKey() {
108 return ModeBits::encode(mode_)
109 | OpBits::encode(op_)
110 | OperandTypeInfoBits::encode(operand_type_);
111 }
112
113 // Note: A lot of the helper functions below will vanish when we use virtual
114 // function instead of switch more often.
115 void Generate(MacroAssembler* masm);
116
117 void GenerateTypeTransition(MacroAssembler* masm);
118
119 void GenerateSmiStub(MacroAssembler* masm);
120 void GenerateSmiStubSub(MacroAssembler* masm);
121 void GenerateSmiStubBitNot(MacroAssembler* masm);
122 void GenerateSmiCodeSub(MacroAssembler* masm,
123 Label* non_smi,
124 Label* undo,
125 Label* slow,
126 Label::Distance non_smi_near = Label::kFar,
127 Label::Distance undo_near = Label::kFar,
128 Label::Distance slow_near = Label::kFar);
129 void GenerateSmiCodeBitNot(MacroAssembler* masm,
130 Label* non_smi,
131 Label::Distance non_smi_near = Label::kFar);
132 void GenerateSmiCodeUndo(MacroAssembler* masm);
133
134 void GenerateHeapNumberStub(MacroAssembler* masm);
135 void GenerateHeapNumberStubSub(MacroAssembler* masm);
136 void GenerateHeapNumberStubBitNot(MacroAssembler* masm);
137 void GenerateHeapNumberCodeSub(MacroAssembler* masm, Label* slow);
138 void GenerateHeapNumberCodeBitNot(MacroAssembler* masm, Label* slow);
139
140 void GenerateGenericStub(MacroAssembler* masm);
141 void GenerateGenericStubSub(MacroAssembler* masm);
142 void GenerateGenericStubBitNot(MacroAssembler* masm);
143 void GenerateGenericCodeFallback(MacroAssembler* masm);
144
145 virtual int GetCodeKind() { return Code::UNARY_OP_IC; }
146
147 virtual InlineCacheState GetICState() {
148 return UnaryOpIC::ToState(operand_type_);
149 }
150
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100151 virtual void FinishCode(Handle<Code> code) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000152 code->set_unary_op_type(operand_type_);
153 }
154};
155
156
157class BinaryOpStub: public CodeStub {
158 public:
159 BinaryOpStub(Token::Value op, OverwriteMode mode)
160 : op_(op),
161 mode_(mode),
162 operands_type_(BinaryOpIC::UNINITIALIZED),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000163 result_type_(BinaryOpIC::UNINITIALIZED) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100164 use_sse3_ = CpuFeatures::IsSupported(SSE3);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100165 ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
166 }
167
Ben Murdoch257744e2011-11-30 15:57:28 +0000168 BinaryOpStub(
Ben Murdochb0fe1622011-05-05 13:52:32 +0100169 int key,
Ben Murdoch257744e2011-11-30 15:57:28 +0000170 BinaryOpIC::TypeInfo operands_type,
171 BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED)
Ben Murdochb0fe1622011-05-05 13:52:32 +0100172 : op_(OpBits::decode(key)),
173 mode_(ModeBits::decode(key)),
174 use_sse3_(SSE3Bits::decode(key)),
175 operands_type_(operands_type),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000176 result_type_(result_type) { }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100177
Ben Murdochb0fe1622011-05-05 13:52:32 +0100178 private:
179 enum SmiCodeGenerateHeapNumberResults {
180 ALLOW_HEAPNUMBER_RESULTS,
181 NO_HEAPNUMBER_RESULTS
182 };
183
184 Token::Value op_;
185 OverwriteMode mode_;
186 bool use_sse3_;
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 Murdochb0fe1622011-05-05 13:52:32 +0100191
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000192 virtual void PrintName(StringStream* stream);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100193
194 // Minor key encoding in 16 bits RRRTTTSOOOOOOOMM.
195 class ModeBits: public BitField<OverwriteMode, 0, 2> {};
196 class OpBits: public BitField<Token::Value, 2, 7> {};
197 class SSE3Bits: public BitField<bool, 9, 1> {};
Ben Murdoch257744e2011-11-30 15:57:28 +0000198 class OperandTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 10, 3> {};
199 class ResultTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 13, 3> {};
Ben Murdochb0fe1622011-05-05 13:52:32 +0100200
Ben Murdoch257744e2011-11-30 15:57:28 +0000201 Major MajorKey() { return BinaryOp; }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100202 int MinorKey() {
203 return OpBits::encode(op_)
204 | ModeBits::encode(mode_)
205 | SSE3Bits::encode(use_sse3_)
206 | OperandTypeInfoBits::encode(operands_type_)
207 | ResultTypeInfoBits::encode(result_type_);
208 }
209
210 void Generate(MacroAssembler* masm);
211 void GenerateGeneric(MacroAssembler* masm);
212 void GenerateSmiCode(MacroAssembler* masm,
213 Label* slow,
214 SmiCodeGenerateHeapNumberResults heapnumber_results);
215 void GenerateLoadArguments(MacroAssembler* masm);
216 void GenerateReturn(MacroAssembler* masm);
217 void GenerateUninitializedStub(MacroAssembler* masm);
218 void GenerateSmiStub(MacroAssembler* masm);
219 void GenerateInt32Stub(MacroAssembler* masm);
220 void GenerateHeapNumberStub(MacroAssembler* masm);
Steve Block44f0eee2011-05-26 01:26:41 +0100221 void GenerateOddballStub(MacroAssembler* masm);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100222 void GenerateStringStub(MacroAssembler* masm);
Ben Murdoch257744e2011-11-30 15:57:28 +0000223 void GenerateBothStringStub(MacroAssembler* masm);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100224 void GenerateGenericStub(MacroAssembler* masm);
Steve Block1e0659c2011-05-24 12:43:12 +0100225 void GenerateAddStrings(MacroAssembler* masm);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100226
227 void GenerateHeapResultAllocation(MacroAssembler* masm, Label* alloc_failure);
228 void GenerateRegisterArgsPush(MacroAssembler* masm);
229 void GenerateTypeTransition(MacroAssembler* masm);
230 void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm);
231
Ben Murdoch257744e2011-11-30 15:57:28 +0000232 virtual int GetCodeKind() { return Code::BINARY_OP_IC; }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100233
234 virtual InlineCacheState GetICState() {
Ben Murdoch257744e2011-11-30 15:57:28 +0000235 return BinaryOpIC::ToState(operands_type_);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100236 }
237
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100238 virtual void FinishCode(Handle<Code> code) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000239 code->set_binary_op_type(operands_type_);
240 code->set_binary_op_result_type(result_type_);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100241 }
242
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100243 friend class CodeGenerator;
244};
245
246
247class StringHelper : public AllStatic {
248 public:
249 // Generate code for copying characters using a simple loop. This should only
250 // be used in places where the number of characters is small and the
251 // additional setup and checking in GenerateCopyCharactersREP adds too much
252 // overhead. Copying of overlapping regions is not supported.
253 static void GenerateCopyCharacters(MacroAssembler* masm,
254 Register dest,
255 Register src,
256 Register count,
257 Register scratch,
258 bool ascii);
259
260 // Generate code for copying characters using the rep movs instruction.
261 // Copies ecx characters from esi to edi. Copying of overlapping regions is
262 // not supported.
263 static void GenerateCopyCharactersREP(MacroAssembler* masm,
264 Register dest, // Must be edi.
265 Register src, // Must be esi.
266 Register count, // Must be ecx.
267 Register scratch, // Neither of above.
268 bool ascii);
269
Iain Merrick9ac36c92010-09-13 15:29:50 +0100270 // Probe the symbol table for a two character string. If the string
271 // requires non-standard hashing a jump to the label not_probed is
272 // performed and registers c1 and c2 are preserved. In all other
273 // cases they are clobbered. If the string is not found by probing a
274 // jump to the label not_found is performed. This jump does not
275 // guarantee that the string is not in the symbol table. If the
276 // string is found the code falls through with the string in
277 // register eax.
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100278 static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
279 Register c1,
280 Register c2,
281 Register scratch1,
282 Register scratch2,
283 Register scratch3,
Iain Merrick9ac36c92010-09-13 15:29:50 +0100284 Label* not_probed,
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100285 Label* not_found);
286
287 // Generate string hash.
288 static void GenerateHashInit(MacroAssembler* masm,
289 Register hash,
290 Register character,
291 Register scratch);
292 static void GenerateHashAddCharacter(MacroAssembler* masm,
293 Register hash,
294 Register character,
295 Register scratch);
296 static void GenerateHashGetHash(MacroAssembler* masm,
297 Register hash,
298 Register scratch);
299
300 private:
301 DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
302};
303
304
305// Flag that indicates how to generate code for the stub StringAddStub.
306enum StringAddFlags {
307 NO_STRING_ADD_FLAGS = 0,
Iain Merrick9ac36c92010-09-13 15:29:50 +0100308 // Omit left string check in stub (left is definitely a string).
309 NO_STRING_CHECK_LEFT_IN_STUB = 1 << 0,
310 // Omit right string check in stub (right is definitely a string).
311 NO_STRING_CHECK_RIGHT_IN_STUB = 1 << 1,
312 // Omit both string checks in stub.
313 NO_STRING_CHECK_IN_STUB =
314 NO_STRING_CHECK_LEFT_IN_STUB | NO_STRING_CHECK_RIGHT_IN_STUB
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100315};
316
317
318class StringAddStub: public CodeStub {
319 public:
Iain Merrick9ac36c92010-09-13 15:29:50 +0100320 explicit StringAddStub(StringAddFlags flags) : flags_(flags) {}
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100321
322 private:
323 Major MajorKey() { return StringAdd; }
Iain Merrick9ac36c92010-09-13 15:29:50 +0100324 int MinorKey() { return flags_; }
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100325
326 void Generate(MacroAssembler* masm);
327
Iain Merrick9ac36c92010-09-13 15:29:50 +0100328 void GenerateConvertArgument(MacroAssembler* masm,
329 int stack_offset,
330 Register arg,
331 Register scratch1,
332 Register scratch2,
333 Register scratch3,
334 Label* slow);
335
336 const StringAddFlags flags_;
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100337};
338
339
340class SubStringStub: public CodeStub {
341 public:
342 SubStringStub() {}
343
344 private:
345 Major MajorKey() { return SubString; }
346 int MinorKey() { return 0; }
347
348 void Generate(MacroAssembler* masm);
349};
350
351
352class StringCompareStub: public CodeStub {
353 public:
Ben Murdoch257744e2011-11-30 15:57:28 +0000354 StringCompareStub() { }
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100355
Ben Murdoch257744e2011-11-30 15:57:28 +0000356 // Compares two flat ASCII strings and returns result in eax.
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100357 static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
358 Register left,
359 Register right,
360 Register scratch1,
361 Register scratch2,
362 Register scratch3);
363
Ben Murdoch257744e2011-11-30 15:57:28 +0000364 // Compares two flat ASCII strings for equality and returns result
365 // in eax.
366 static void GenerateFlatAsciiStringEquals(MacroAssembler* masm,
367 Register left,
368 Register right,
369 Register scratch1,
370 Register scratch2);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100371
Ben Murdoch257744e2011-11-30 15:57:28 +0000372 private:
373 virtual Major MajorKey() { return StringCompare; }
374 virtual int MinorKey() { return 0; }
375 virtual void Generate(MacroAssembler* masm);
376
377 static void GenerateAsciiCharsCompareLoop(
378 MacroAssembler* masm,
379 Register left,
380 Register right,
381 Register length,
382 Register scratch,
383 Label* chars_not_equal,
384 Label::Distance chars_not_equal_near = Label::kFar);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100385};
386
387
388class NumberToStringStub: public CodeStub {
389 public:
390 NumberToStringStub() { }
391
392 // Generate code to do a lookup in the number string cache. If the number in
393 // the register object is found in the cache the generated code falls through
394 // with the result in the result register. The object and the result register
395 // can be the same. If the number is not found in the cache the code jumps to
396 // the label not_found with only the content of register object unchanged.
397 static void GenerateLookupNumberStringCache(MacroAssembler* masm,
398 Register object,
399 Register result,
400 Register scratch1,
401 Register scratch2,
402 bool object_is_smi,
403 Label* not_found);
404
405 private:
406 Major MajorKey() { return NumberToString; }
407 int MinorKey() { return 0; }
408
409 void Generate(MacroAssembler* masm);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100410};
411
Ben Murdoch257744e2011-11-30 15:57:28 +0000412
413class StringDictionaryLookupStub: public CodeStub {
414 public:
415 enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
416
417 StringDictionaryLookupStub(Register dictionary,
418 Register result,
419 Register index,
420 LookupMode mode)
421 : dictionary_(dictionary), result_(result), index_(index), mode_(mode) { }
422
423 void Generate(MacroAssembler* masm);
424
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100425 static void GenerateNegativeLookup(MacroAssembler* masm,
426 Label* miss,
427 Label* done,
428 Register properties,
429 Handle<String> name,
430 Register r0);
Ben Murdoch257744e2011-11-30 15:57:28 +0000431
432 static void GeneratePositiveLookup(MacroAssembler* masm,
433 Label* miss,
434 Label* done,
435 Register elements,
436 Register name,
437 Register r0,
438 Register r1);
439
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100440 virtual bool SometimesSetsUpAFrame() { return false; }
441
Ben Murdoch257744e2011-11-30 15:57:28 +0000442 private:
443 static const int kInlinedProbes = 4;
444 static const int kTotalProbes = 20;
445
446 static const int kCapacityOffset =
447 StringDictionary::kHeaderSize +
448 StringDictionary::kCapacityIndex * kPointerSize;
449
450 static const int kElementsStartOffset =
451 StringDictionary::kHeaderSize +
452 StringDictionary::kElementsStartIndex * kPointerSize;
453
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100454 Major MajorKey() { return StringDictionaryLookup; }
Ben Murdoch257744e2011-11-30 15:57:28 +0000455
456 int MinorKey() {
457 return DictionaryBits::encode(dictionary_.code()) |
458 ResultBits::encode(result_.code()) |
459 IndexBits::encode(index_.code()) |
460 LookupModeBits::encode(mode_);
461 }
462
463 class DictionaryBits: public BitField<int, 0, 3> {};
464 class ResultBits: public BitField<int, 3, 3> {};
465 class IndexBits: public BitField<int, 6, 3> {};
466 class LookupModeBits: public BitField<LookupMode, 9, 1> {};
467
468 Register dictionary_;
469 Register result_;
470 Register index_;
471 LookupMode mode_;
472};
473
474
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100475class RecordWriteStub: public CodeStub {
476 public:
477 RecordWriteStub(Register object,
478 Register value,
479 Register address,
480 RememberedSetAction remembered_set_action,
481 SaveFPRegsMode fp_mode)
482 : object_(object),
483 value_(value),
484 address_(address),
485 remembered_set_action_(remembered_set_action),
486 save_fp_regs_mode_(fp_mode),
487 regs_(object, // An input reg.
488 address, // An input reg.
489 value) { // One scratch reg.
490 }
491
492 enum Mode {
493 STORE_BUFFER_ONLY,
494 INCREMENTAL,
495 INCREMENTAL_COMPACTION
496 };
497
498 virtual bool IsPregenerated();
499 static void GenerateFixedRegStubsAheadOfTime();
500 virtual bool SometimesSetsUpAFrame() { return false; }
501
502 static const byte kTwoByteNopInstruction = 0x3c; // Cmpb al, #imm8.
503 static const byte kTwoByteJumpInstruction = 0xeb; // Jmp #imm8.
504
505 static const byte kFiveByteNopInstruction = 0x3d; // Cmpl eax, #imm32.
506 static const byte kFiveByteJumpInstruction = 0xe9; // Jmp #imm32.
507
508 static Mode GetMode(Code* stub) {
509 byte first_instruction = stub->instruction_start()[0];
510 byte second_instruction = stub->instruction_start()[2];
511
512 if (first_instruction == kTwoByteJumpInstruction) {
513 return INCREMENTAL;
514 }
515
516 ASSERT(first_instruction == kTwoByteNopInstruction);
517
518 if (second_instruction == kFiveByteJumpInstruction) {
519 return INCREMENTAL_COMPACTION;
520 }
521
522 ASSERT(second_instruction == kFiveByteNopInstruction);
523
524 return STORE_BUFFER_ONLY;
525 }
526
527 static void Patch(Code* stub, Mode mode) {
528 switch (mode) {
529 case STORE_BUFFER_ONLY:
530 ASSERT(GetMode(stub) == INCREMENTAL ||
531 GetMode(stub) == INCREMENTAL_COMPACTION);
532 stub->instruction_start()[0] = kTwoByteNopInstruction;
533 stub->instruction_start()[2] = kFiveByteNopInstruction;
534 break;
535 case INCREMENTAL:
536 ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
537 stub->instruction_start()[0] = kTwoByteJumpInstruction;
538 break;
539 case INCREMENTAL_COMPACTION:
540 ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
541 stub->instruction_start()[0] = kTwoByteNopInstruction;
542 stub->instruction_start()[2] = kFiveByteJumpInstruction;
543 break;
544 }
545 ASSERT(GetMode(stub) == mode);
546 CPU::FlushICache(stub->instruction_start(), 7);
547 }
548
549 private:
550 // This is a helper class for freeing up 3 scratch registers, where the third
551 // is always ecx (needed for shift operations). The input is two registers
552 // that must be preserved and one scratch register provided by the caller.
553 class RegisterAllocation {
554 public:
555 RegisterAllocation(Register object,
556 Register address,
557 Register scratch0)
558 : object_orig_(object),
559 address_orig_(address),
560 scratch0_orig_(scratch0),
561 object_(object),
562 address_(address),
563 scratch0_(scratch0) {
564 ASSERT(!AreAliased(scratch0, object, address, no_reg));
565 scratch1_ = GetRegThatIsNotEcxOr(object_, address_, scratch0_);
566 if (scratch0.is(ecx)) {
567 scratch0_ = GetRegThatIsNotEcxOr(object_, address_, scratch1_);
568 }
569 if (object.is(ecx)) {
570 object_ = GetRegThatIsNotEcxOr(address_, scratch0_, scratch1_);
571 }
572 if (address.is(ecx)) {
573 address_ = GetRegThatIsNotEcxOr(object_, scratch0_, scratch1_);
574 }
575 ASSERT(!AreAliased(scratch0_, object_, address_, ecx));
576 }
577
578 void Save(MacroAssembler* masm) {
579 ASSERT(!address_orig_.is(object_));
580 ASSERT(object_.is(object_orig_) || address_.is(address_orig_));
581 ASSERT(!AreAliased(object_, address_, scratch1_, scratch0_));
582 ASSERT(!AreAliased(object_orig_, address_, scratch1_, scratch0_));
583 ASSERT(!AreAliased(object_, address_orig_, scratch1_, scratch0_));
584 // We don't have to save scratch0_orig_ because it was given to us as
585 // a scratch register. But if we had to switch to a different reg then
586 // we should save the new scratch0_.
587 if (!scratch0_.is(scratch0_orig_)) masm->push(scratch0_);
588 if (!ecx.is(scratch0_orig_) &&
589 !ecx.is(object_orig_) &&
590 !ecx.is(address_orig_)) {
591 masm->push(ecx);
592 }
593 masm->push(scratch1_);
594 if (!address_.is(address_orig_)) {
595 masm->push(address_);
596 masm->mov(address_, address_orig_);
597 }
598 if (!object_.is(object_orig_)) {
599 masm->push(object_);
600 masm->mov(object_, object_orig_);
601 }
602 }
603
604 void Restore(MacroAssembler* masm) {
605 // These will have been preserved the entire time, so we just need to move
606 // them back. Only in one case is the orig_ reg different from the plain
607 // one, since only one of them can alias with ecx.
608 if (!object_.is(object_orig_)) {
609 masm->mov(object_orig_, object_);
610 masm->pop(object_);
611 }
612 if (!address_.is(address_orig_)) {
613 masm->mov(address_orig_, address_);
614 masm->pop(address_);
615 }
616 masm->pop(scratch1_);
617 if (!ecx.is(scratch0_orig_) &&
618 !ecx.is(object_orig_) &&
619 !ecx.is(address_orig_)) {
620 masm->pop(ecx);
621 }
622 if (!scratch0_.is(scratch0_orig_)) masm->pop(scratch0_);
623 }
624
625 // If we have to call into C then we need to save and restore all caller-
626 // saved registers that were not already preserved. The caller saved
627 // registers are eax, ecx and edx. The three scratch registers (incl. ecx)
628 // will be restored by other means so we don't bother pushing them here.
629 void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
630 if (!scratch0_.is(eax) && !scratch1_.is(eax)) masm->push(eax);
631 if (!scratch0_.is(edx) && !scratch1_.is(edx)) masm->push(edx);
632 if (mode == kSaveFPRegs) {
633 CpuFeatures::Scope scope(SSE2);
634 masm->sub(esp,
635 Immediate(kDoubleSize * (XMMRegister::kNumRegisters - 1)));
636 // Save all XMM registers except XMM0.
637 for (int i = XMMRegister::kNumRegisters - 1; i > 0; i--) {
638 XMMRegister reg = XMMRegister::from_code(i);
639 masm->movdbl(Operand(esp, (i - 1) * kDoubleSize), reg);
640 }
641 }
642 }
643
644 inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
645 SaveFPRegsMode mode) {
646 if (mode == kSaveFPRegs) {
647 CpuFeatures::Scope scope(SSE2);
648 // Restore all XMM registers except XMM0.
649 for (int i = XMMRegister::kNumRegisters - 1; i > 0; i--) {
650 XMMRegister reg = XMMRegister::from_code(i);
651 masm->movdbl(reg, Operand(esp, (i - 1) * kDoubleSize));
652 }
653 masm->add(esp,
654 Immediate(kDoubleSize * (XMMRegister::kNumRegisters - 1)));
655 }
656 if (!scratch0_.is(edx) && !scratch1_.is(edx)) masm->pop(edx);
657 if (!scratch0_.is(eax) && !scratch1_.is(eax)) masm->pop(eax);
658 }
659
660 inline Register object() { return object_; }
661 inline Register address() { return address_; }
662 inline Register scratch0() { return scratch0_; }
663 inline Register scratch1() { return scratch1_; }
664
665 private:
666 Register object_orig_;
667 Register address_orig_;
668 Register scratch0_orig_;
669 Register object_;
670 Register address_;
671 Register scratch0_;
672 Register scratch1_;
673 // Third scratch register is always ecx.
674
675 Register GetRegThatIsNotEcxOr(Register r1,
676 Register r2,
677 Register r3) {
678 for (int i = 0; i < Register::kNumAllocatableRegisters; i++) {
679 Register candidate = Register::FromAllocationIndex(i);
680 if (candidate.is(ecx)) continue;
681 if (candidate.is(r1)) continue;
682 if (candidate.is(r2)) continue;
683 if (candidate.is(r3)) continue;
684 return candidate;
685 }
686 UNREACHABLE();
687 return no_reg;
688 }
689 friend class RecordWriteStub;
690 };
691
692 enum OnNoNeedToInformIncrementalMarker {
693 kReturnOnNoNeedToInformIncrementalMarker,
694 kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
695 }
696;
697 void Generate(MacroAssembler* masm);
698 void GenerateIncremental(MacroAssembler* masm, Mode mode);
699 void CheckNeedsToInformIncrementalMarker(
700 MacroAssembler* masm,
701 OnNoNeedToInformIncrementalMarker on_no_need,
702 Mode mode);
703 void InformIncrementalMarker(MacroAssembler* masm, Mode mode);
704
705 Major MajorKey() { return RecordWrite; }
706
707 int MinorKey() {
708 return ObjectBits::encode(object_.code()) |
709 ValueBits::encode(value_.code()) |
710 AddressBits::encode(address_.code()) |
711 RememberedSetActionBits::encode(remembered_set_action_) |
712 SaveFPRegsModeBits::encode(save_fp_regs_mode_);
713 }
714
715 void Activate(Code* code) {
716 code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
717 }
718
719 class ObjectBits: public BitField<int, 0, 3> {};
720 class ValueBits: public BitField<int, 3, 3> {};
721 class AddressBits: public BitField<int, 6, 3> {};
722 class RememberedSetActionBits: public BitField<RememberedSetAction, 9, 1> {};
723 class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 10, 1> {};
724
725 Register object_;
726 Register value_;
727 Register address_;
728 RememberedSetAction remembered_set_action_;
729 SaveFPRegsMode save_fp_regs_mode_;
730 RegisterAllocation regs_;
731};
732
733
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100734} } // namespace v8::internal
735
736#endif // V8_IA32_CODE_STUBS_IA32_H_