blob: 6dc63bdd4910c2356f654b3a54c94915ec927efd [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
danno@chromium.orgca29dd82013-04-26 11:59:48 +000039void ArrayNativeCode(MacroAssembler* masm,
40 bool construct_call,
41 Label* call_generic_code);
42
ricow@chromium.org65fae842010-08-25 15:26:24 +000043// Compute a transcendental math function natively, or call the
44// TranscendentalCache runtime function.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000045class TranscendentalCacheStub: public PlatformCodeStub {
ricow@chromium.org65fae842010-08-25 15:26:24 +000046 public:
whesse@chromium.org023421e2010-12-21 12:19:12 +000047 enum ArgumentType {
48 TAGGED = 0,
49 UNTAGGED = 1 << TranscendentalCache::kTranscendentalTypeBits
50 };
51
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000052 TranscendentalCacheStub(TranscendentalCache::Type type,
53 ArgumentType argument_type)
whesse@chromium.org023421e2010-12-21 12:19:12 +000054 : type_(type), argument_type_(argument_type) {}
ricow@chromium.org65fae842010-08-25 15:26:24 +000055 void Generate(MacroAssembler* masm);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +000056 static void GenerateOperation(MacroAssembler* masm,
57 TranscendentalCache::Type type);
ricow@chromium.org65fae842010-08-25 15:26:24 +000058 private:
59 TranscendentalCache::Type type_;
whesse@chromium.org023421e2010-12-21 12:19:12 +000060 ArgumentType argument_type_;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000061
ricow@chromium.org65fae842010-08-25 15:26:24 +000062 Major MajorKey() { return TranscendentalCache; }
whesse@chromium.org023421e2010-12-21 12:19:12 +000063 int MinorKey() { return type_ | argument_type_; }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000064 Runtime::FunctionId RuntimeFunction();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000065};
66
67
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000068class StoreBufferOverflowStub: public PlatformCodeStub {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000069 public:
70 explicit StoreBufferOverflowStub(SaveFPRegsMode save_fp)
ulan@chromium.org750145a2013-03-07 15:14:13 +000071 : save_doubles_(save_fp) {
72 ASSERT(CpuFeatures::IsSafeForSnapshot(SSE2) || save_fp == kDontSaveFPRegs);
73 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000074
75 void Generate(MacroAssembler* masm);
76
77 virtual bool IsPregenerated() { return true; }
hpayer@chromium.org8432c912013-02-28 15:55:26 +000078 static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000079 virtual bool SometimesSetsUpAFrame() { return false; }
80
81 private:
82 SaveFPRegsMode save_doubles_;
83
84 Major MajorKey() { return StoreBufferOverflow; }
85 int MinorKey() { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; }
86};
87
88
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000089class UnaryOpStub: public PlatformCodeStub {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000090 public:
ricow@chromium.org4f693d62011-07-04 14:01:31 +000091 UnaryOpStub(Token::Value op,
92 UnaryOverwriteMode mode,
93 UnaryOpIC::TypeInfo operand_type = UnaryOpIC::UNINITIALIZED)
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000094 : op_(op),
95 mode_(mode),
whesse@chromium.org030d38e2011-07-13 13:23:34 +000096 operand_type_(operand_type) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000097 }
98
99 private:
100 Token::Value op_;
101 UnaryOverwriteMode mode_;
102
103 // Operand type information determined at runtime.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000104 UnaryOpIC::TypeInfo operand_type_;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000105
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000106 virtual void PrintName(StringStream* stream);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000107
108 class ModeBits: public BitField<UnaryOverwriteMode, 0, 1> {};
109 class OpBits: public BitField<Token::Value, 1, 7> {};
danno@chromium.org40cb8782011-05-25 07:58:50 +0000110 class OperandTypeInfoBits: public BitField<UnaryOpIC::TypeInfo, 8, 3> {};
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000111
danno@chromium.org40cb8782011-05-25 07:58:50 +0000112 Major MajorKey() { return UnaryOp; }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000113 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);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000128 void GenerateSmiCodeSub(MacroAssembler* masm,
129 Label* non_smi,
130 Label* undo,
131 Label* slow,
132 Label::Distance non_smi_near = Label::kFar,
133 Label::Distance undo_near = Label::kFar,
134 Label::Distance slow_near = Label::kFar);
135 void GenerateSmiCodeBitNot(MacroAssembler* masm,
136 Label* non_smi,
137 Label::Distance non_smi_near = Label::kFar);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000138 void GenerateSmiCodeUndo(MacroAssembler* masm);
139
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000140 void GenerateNumberStub(MacroAssembler* masm);
141 void GenerateNumberStubSub(MacroAssembler* masm);
142 void GenerateNumberStubBitNot(MacroAssembler* masm);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000143 void GenerateHeapNumberCodeSub(MacroAssembler* masm, Label* slow);
144 void GenerateHeapNumberCodeBitNot(MacroAssembler* masm, Label* slow);
145
146 void GenerateGenericStub(MacroAssembler* masm);
147 void GenerateGenericStubSub(MacroAssembler* masm);
148 void GenerateGenericStubBitNot(MacroAssembler* masm);
149 void GenerateGenericCodeFallback(MacroAssembler* masm);
150
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +0000151 virtual Code::Kind GetCodeKind() const { return Code::UNARY_OP_IC; }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000152
153 virtual InlineCacheState GetICState() {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000154 return UnaryOpIC::ToState(operand_type_);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000155 }
156
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +0000157 virtual void FinishCode(Handle<Code> code) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000158 code->set_unary_op_type(operand_type_);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000159 }
160};
161
162
ricow@chromium.org65fae842010-08-25 15:26:24 +0000163class StringHelper : public AllStatic {
164 public:
165 // Generate code for copying characters using a simple loop. This should only
166 // be used in places where the number of characters is small and the
167 // additional setup and checking in GenerateCopyCharactersREP adds too much
168 // overhead. Copying of overlapping regions is not supported.
169 static void GenerateCopyCharacters(MacroAssembler* masm,
170 Register dest,
171 Register src,
172 Register count,
173 Register scratch,
174 bool ascii);
175
176 // Generate code for copying characters using the rep movs instruction.
177 // Copies ecx characters from esi to edi. Copying of overlapping regions is
178 // not supported.
179 static void GenerateCopyCharactersREP(MacroAssembler* masm,
180 Register dest, // Must be edi.
181 Register src, // Must be esi.
182 Register count, // Must be ecx.
183 Register scratch, // Neither of above.
184 bool ascii);
185
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000186 // Probe the string table for a two character string. If the string
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000187 // requires non-standard hashing a jump to the label not_probed is
188 // performed and registers c1 and c2 are preserved. In all other
189 // cases they are clobbered. If the string is not found by probing a
190 // jump to the label not_found is performed. This jump does not
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000191 // guarantee that the string is not in the string table. If the
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000192 // string is found the code falls through with the string in
193 // register eax.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000194 static void GenerateTwoCharacterStringTableProbe(MacroAssembler* masm,
ricow@chromium.org65fae842010-08-25 15:26:24 +0000195 Register c1,
196 Register c2,
197 Register scratch1,
198 Register scratch2,
199 Register scratch3,
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000200 Label* not_probed,
ricow@chromium.org65fae842010-08-25 15:26:24 +0000201 Label* not_found);
202
203 // Generate string hash.
204 static void GenerateHashInit(MacroAssembler* masm,
205 Register hash,
206 Register character,
207 Register scratch);
208 static void GenerateHashAddCharacter(MacroAssembler* masm,
209 Register hash,
210 Register character,
211 Register scratch);
212 static void GenerateHashGetHash(MacroAssembler* masm,
213 Register hash,
214 Register scratch);
215
216 private:
217 DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
218};
219
220
ricow@chromium.org65fae842010-08-25 15:26:24 +0000221enum StringAddFlags {
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000222 NO_STRING_ADD_FLAGS = 1 << 0,
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000223 // Omit left string check in stub (left is definitely a string).
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000224 NO_STRING_CHECK_LEFT_IN_STUB = 1 << 1,
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000225 // Omit right string check in stub (right is definitely a string).
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000226 NO_STRING_CHECK_RIGHT_IN_STUB = 1 << 2,
227 // Stub needs a frame before calling the runtime
228 ERECT_FRAME = 1 << 3,
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000229 // Omit both string checks in stub.
230 NO_STRING_CHECK_IN_STUB =
231 NO_STRING_CHECK_LEFT_IN_STUB | NO_STRING_CHECK_RIGHT_IN_STUB
ricow@chromium.org65fae842010-08-25 15:26:24 +0000232};
233
234
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000235class StringAddStub: public PlatformCodeStub {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000236 public:
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000237 explicit StringAddStub(StringAddFlags flags) : flags_(flags) {}
ricow@chromium.org65fae842010-08-25 15:26:24 +0000238
239 private:
240 Major MajorKey() { return StringAdd; }
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000241 int MinorKey() { return flags_; }
ricow@chromium.org65fae842010-08-25 15:26:24 +0000242
243 void Generate(MacroAssembler* masm);
244
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000245 void GenerateConvertArgument(MacroAssembler* masm,
246 int stack_offset,
247 Register arg,
248 Register scratch1,
249 Register scratch2,
250 Register scratch3,
251 Label* slow);
252
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000253 void GenerateRegisterArgsPush(MacroAssembler* masm);
254 void GenerateRegisterArgsPop(MacroAssembler* masm, Register temp);
255
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000256 const StringAddFlags flags_;
ricow@chromium.org65fae842010-08-25 15:26:24 +0000257};
258
259
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000260class SubStringStub: public PlatformCodeStub {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000261 public:
262 SubStringStub() {}
263
264 private:
265 Major MajorKey() { return SubString; }
266 int MinorKey() { return 0; }
267
268 void Generate(MacroAssembler* masm);
269};
270
271
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000272class StringCompareStub: public PlatformCodeStub {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000273 public:
lrn@chromium.org1c092762011-05-09 09:42:16 +0000274 StringCompareStub() { }
ricow@chromium.org65fae842010-08-25 15:26:24 +0000275
lrn@chromium.org1c092762011-05-09 09:42:16 +0000276 // Compares two flat ASCII strings and returns result in eax.
ricow@chromium.org65fae842010-08-25 15:26:24 +0000277 static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
278 Register left,
279 Register right,
280 Register scratch1,
281 Register scratch2,
282 Register scratch3);
283
lrn@chromium.org1c092762011-05-09 09:42:16 +0000284 // Compares two flat ASCII strings for equality and returns result
285 // in eax.
286 static void GenerateFlatAsciiStringEquals(MacroAssembler* masm,
287 Register left,
288 Register right,
289 Register scratch1,
290 Register scratch2);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000291
lrn@chromium.org1c092762011-05-09 09:42:16 +0000292 private:
293 virtual Major MajorKey() { return StringCompare; }
294 virtual int MinorKey() { return 0; }
295 virtual void Generate(MacroAssembler* masm);
296
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000297 static void GenerateAsciiCharsCompareLoop(
298 MacroAssembler* masm,
299 Register left,
300 Register right,
301 Register length,
302 Register scratch,
303 Label* chars_not_equal,
304 Label::Distance chars_not_equal_near = Label::kFar);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000305};
306
307
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000308class NumberToStringStub: public PlatformCodeStub {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000309 public:
310 NumberToStringStub() { }
311
312 // Generate code to do a lookup in the number string cache. If the number in
313 // the register object is found in the cache the generated code falls through
314 // with the result in the result register. The object and the result register
315 // can be the same. If the number is not found in the cache the code jumps to
316 // the label not_found with only the content of register object unchanged.
317 static void GenerateLookupNumberStringCache(MacroAssembler* masm,
318 Register object,
319 Register result,
320 Register scratch1,
321 Register scratch2,
322 bool object_is_smi,
323 Label* not_found);
324
325 private:
326 Major MajorKey() { return NumberToString; }
327 int MinorKey() { return 0; }
328
329 void Generate(MacroAssembler* masm);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000330};
331
lrn@chromium.org1c092762011-05-09 09:42:16 +0000332
ulan@chromium.org750145a2013-03-07 15:14:13 +0000333class NameDictionaryLookupStub: public PlatformCodeStub {
lrn@chromium.org1c092762011-05-09 09:42:16 +0000334 public:
335 enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
336
ulan@chromium.org750145a2013-03-07 15:14:13 +0000337 NameDictionaryLookupStub(Register dictionary,
338 Register result,
339 Register index,
340 LookupMode mode)
lrn@chromium.org1c092762011-05-09 09:42:16 +0000341 : dictionary_(dictionary), result_(result), index_(index), mode_(mode) { }
342
343 void Generate(MacroAssembler* masm);
344
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000345 static void GenerateNegativeLookup(MacroAssembler* masm,
346 Label* miss,
347 Label* done,
348 Register properties,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000349 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000350 Register r0);
351
lrn@chromium.org1c092762011-05-09 09:42:16 +0000352 static void GeneratePositiveLookup(MacroAssembler* masm,
353 Label* miss,
354 Label* done,
355 Register elements,
356 Register name,
357 Register r0,
358 Register r1);
359
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000360 virtual bool SometimesSetsUpAFrame() { return false; }
361
lrn@chromium.org1c092762011-05-09 09:42:16 +0000362 private:
363 static const int kInlinedProbes = 4;
364 static const int kTotalProbes = 20;
365
366 static const int kCapacityOffset =
ulan@chromium.org750145a2013-03-07 15:14:13 +0000367 NameDictionary::kHeaderSize +
368 NameDictionary::kCapacityIndex * kPointerSize;
lrn@chromium.org1c092762011-05-09 09:42:16 +0000369
370 static const int kElementsStartOffset =
ulan@chromium.org750145a2013-03-07 15:14:13 +0000371 NameDictionary::kHeaderSize +
372 NameDictionary::kElementsStartIndex * kPointerSize;
lrn@chromium.org1c092762011-05-09 09:42:16 +0000373
ulan@chromium.org750145a2013-03-07 15:14:13 +0000374 Major MajorKey() { return NameDictionaryLookup; }
lrn@chromium.org1c092762011-05-09 09:42:16 +0000375
376 int MinorKey() {
377 return DictionaryBits::encode(dictionary_.code()) |
378 ResultBits::encode(result_.code()) |
379 IndexBits::encode(index_.code()) |
380 LookupModeBits::encode(mode_);
381 }
382
383 class DictionaryBits: public BitField<int, 0, 3> {};
384 class ResultBits: public BitField<int, 3, 3> {};
385 class IndexBits: public BitField<int, 6, 3> {};
386 class LookupModeBits: public BitField<LookupMode, 9, 1> {};
387
388 Register dictionary_;
389 Register result_;
390 Register index_;
391 LookupMode mode_;
392};
393
394
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000395class RecordWriteStub: public PlatformCodeStub {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000396 public:
397 RecordWriteStub(Register object,
398 Register value,
399 Register address,
400 RememberedSetAction remembered_set_action,
401 SaveFPRegsMode fp_mode)
402 : object_(object),
403 value_(value),
404 address_(address),
405 remembered_set_action_(remembered_set_action),
406 save_fp_regs_mode_(fp_mode),
407 regs_(object, // An input reg.
408 address, // An input reg.
409 value) { // One scratch reg.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000410 ASSERT(CpuFeatures::IsSafeForSnapshot(SSE2) || fp_mode == kDontSaveFPRegs);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000411 }
412
413 enum Mode {
414 STORE_BUFFER_ONLY,
415 INCREMENTAL,
416 INCREMENTAL_COMPACTION
417 };
418
419 virtual bool IsPregenerated();
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000420 static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000421 virtual bool SometimesSetsUpAFrame() { return false; }
422
423 static const byte kTwoByteNopInstruction = 0x3c; // Cmpb al, #imm8.
424 static const byte kTwoByteJumpInstruction = 0xeb; // Jmp #imm8.
425
426 static const byte kFiveByteNopInstruction = 0x3d; // Cmpl eax, #imm32.
427 static const byte kFiveByteJumpInstruction = 0xe9; // Jmp #imm32.
428
429 static Mode GetMode(Code* stub) {
430 byte first_instruction = stub->instruction_start()[0];
431 byte second_instruction = stub->instruction_start()[2];
432
433 if (first_instruction == kTwoByteJumpInstruction) {
434 return INCREMENTAL;
435 }
436
437 ASSERT(first_instruction == kTwoByteNopInstruction);
438
439 if (second_instruction == kFiveByteJumpInstruction) {
440 return INCREMENTAL_COMPACTION;
441 }
442
443 ASSERT(second_instruction == kFiveByteNopInstruction);
444
445 return STORE_BUFFER_ONLY;
446 }
447
448 static void Patch(Code* stub, Mode mode) {
449 switch (mode) {
450 case STORE_BUFFER_ONLY:
451 ASSERT(GetMode(stub) == INCREMENTAL ||
452 GetMode(stub) == INCREMENTAL_COMPACTION);
453 stub->instruction_start()[0] = kTwoByteNopInstruction;
454 stub->instruction_start()[2] = kFiveByteNopInstruction;
455 break;
456 case INCREMENTAL:
457 ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
458 stub->instruction_start()[0] = kTwoByteJumpInstruction;
459 break;
460 case INCREMENTAL_COMPACTION:
461 ASSERT(GetMode(stub) == STORE_BUFFER_ONLY);
462 stub->instruction_start()[0] = kTwoByteNopInstruction;
463 stub->instruction_start()[2] = kFiveByteJumpInstruction;
464 break;
465 }
466 ASSERT(GetMode(stub) == mode);
467 CPU::FlushICache(stub->instruction_start(), 7);
468 }
469
470 private:
471 // This is a helper class for freeing up 3 scratch registers, where the third
472 // is always ecx (needed for shift operations). The input is two registers
473 // that must be preserved and one scratch register provided by the caller.
474 class RegisterAllocation {
475 public:
476 RegisterAllocation(Register object,
477 Register address,
478 Register scratch0)
479 : object_orig_(object),
480 address_orig_(address),
481 scratch0_orig_(scratch0),
482 object_(object),
483 address_(address),
484 scratch0_(scratch0) {
485 ASSERT(!AreAliased(scratch0, object, address, no_reg));
486 scratch1_ = GetRegThatIsNotEcxOr(object_, address_, scratch0_);
487 if (scratch0.is(ecx)) {
488 scratch0_ = GetRegThatIsNotEcxOr(object_, address_, scratch1_);
489 }
490 if (object.is(ecx)) {
491 object_ = GetRegThatIsNotEcxOr(address_, scratch0_, scratch1_);
492 }
493 if (address.is(ecx)) {
494 address_ = GetRegThatIsNotEcxOr(object_, scratch0_, scratch1_);
495 }
496 ASSERT(!AreAliased(scratch0_, object_, address_, ecx));
497 }
498
499 void Save(MacroAssembler* masm) {
500 ASSERT(!address_orig_.is(object_));
501 ASSERT(object_.is(object_orig_) || address_.is(address_orig_));
502 ASSERT(!AreAliased(object_, address_, scratch1_, scratch0_));
503 ASSERT(!AreAliased(object_orig_, address_, scratch1_, scratch0_));
504 ASSERT(!AreAliased(object_, address_orig_, scratch1_, scratch0_));
505 // We don't have to save scratch0_orig_ because it was given to us as
506 // a scratch register. But if we had to switch to a different reg then
507 // we should save the new scratch0_.
508 if (!scratch0_.is(scratch0_orig_)) masm->push(scratch0_);
509 if (!ecx.is(scratch0_orig_) &&
510 !ecx.is(object_orig_) &&
511 !ecx.is(address_orig_)) {
512 masm->push(ecx);
513 }
514 masm->push(scratch1_);
515 if (!address_.is(address_orig_)) {
516 masm->push(address_);
517 masm->mov(address_, address_orig_);
518 }
519 if (!object_.is(object_orig_)) {
520 masm->push(object_);
521 masm->mov(object_, object_orig_);
522 }
523 }
524
525 void Restore(MacroAssembler* masm) {
526 // These will have been preserved the entire time, so we just need to move
527 // them back. Only in one case is the orig_ reg different from the plain
528 // one, since only one of them can alias with ecx.
529 if (!object_.is(object_orig_)) {
530 masm->mov(object_orig_, object_);
531 masm->pop(object_);
532 }
533 if (!address_.is(address_orig_)) {
534 masm->mov(address_orig_, address_);
535 masm->pop(address_);
536 }
537 masm->pop(scratch1_);
538 if (!ecx.is(scratch0_orig_) &&
539 !ecx.is(object_orig_) &&
540 !ecx.is(address_orig_)) {
541 masm->pop(ecx);
542 }
543 if (!scratch0_.is(scratch0_orig_)) masm->pop(scratch0_);
544 }
545
546 // If we have to call into C then we need to save and restore all caller-
547 // saved registers that were not already preserved. The caller saved
548 // registers are eax, ecx and edx. The three scratch registers (incl. ecx)
549 // will be restored by other means so we don't bother pushing them here.
550 void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
551 if (!scratch0_.is(eax) && !scratch1_.is(eax)) masm->push(eax);
552 if (!scratch0_.is(edx) && !scratch1_.is(edx)) masm->push(edx);
553 if (mode == kSaveFPRegs) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000554 CpuFeatureScope scope(masm, SSE2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000555 masm->sub(esp,
556 Immediate(kDoubleSize * (XMMRegister::kNumRegisters - 1)));
557 // Save all XMM registers except XMM0.
558 for (int i = XMMRegister::kNumRegisters - 1; i > 0; i--) {
559 XMMRegister reg = XMMRegister::from_code(i);
560 masm->movdbl(Operand(esp, (i - 1) * kDoubleSize), reg);
561 }
562 }
563 }
564
565 inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
566 SaveFPRegsMode mode) {
567 if (mode == kSaveFPRegs) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000568 CpuFeatureScope scope(masm, SSE2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000569 // Restore all XMM registers except XMM0.
570 for (int i = XMMRegister::kNumRegisters - 1; i > 0; i--) {
571 XMMRegister reg = XMMRegister::from_code(i);
572 masm->movdbl(reg, Operand(esp, (i - 1) * kDoubleSize));
573 }
574 masm->add(esp,
575 Immediate(kDoubleSize * (XMMRegister::kNumRegisters - 1)));
576 }
577 if (!scratch0_.is(edx) && !scratch1_.is(edx)) masm->pop(edx);
578 if (!scratch0_.is(eax) && !scratch1_.is(eax)) masm->pop(eax);
579 }
580
581 inline Register object() { return object_; }
582 inline Register address() { return address_; }
583 inline Register scratch0() { return scratch0_; }
584 inline Register scratch1() { return scratch1_; }
585
586 private:
587 Register object_orig_;
588 Register address_orig_;
589 Register scratch0_orig_;
590 Register object_;
591 Register address_;
592 Register scratch0_;
593 Register scratch1_;
594 // Third scratch register is always ecx.
595
596 Register GetRegThatIsNotEcxOr(Register r1,
597 Register r2,
598 Register r3) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000599 for (int i = 0; i < Register::NumAllocatableRegisters(); i++) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000600 Register candidate = Register::FromAllocationIndex(i);
601 if (candidate.is(ecx)) continue;
602 if (candidate.is(r1)) continue;
603 if (candidate.is(r2)) continue;
604 if (candidate.is(r3)) continue;
605 return candidate;
606 }
607 UNREACHABLE();
608 return no_reg;
609 }
610 friend class RecordWriteStub;
611 };
612
613 enum OnNoNeedToInformIncrementalMarker {
614 kReturnOnNoNeedToInformIncrementalMarker,
615 kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
616 }
617;
618 void Generate(MacroAssembler* masm);
619 void GenerateIncremental(MacroAssembler* masm, Mode mode);
620 void CheckNeedsToInformIncrementalMarker(
621 MacroAssembler* masm,
622 OnNoNeedToInformIncrementalMarker on_no_need,
623 Mode mode);
624 void InformIncrementalMarker(MacroAssembler* masm, Mode mode);
625
626 Major MajorKey() { return RecordWrite; }
627
628 int MinorKey() {
629 return ObjectBits::encode(object_.code()) |
630 ValueBits::encode(value_.code()) |
631 AddressBits::encode(address_.code()) |
632 RememberedSetActionBits::encode(remembered_set_action_) |
633 SaveFPRegsModeBits::encode(save_fp_regs_mode_);
634 }
635
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000636 void Activate(Code* code) {
637 code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
638 }
639
640 class ObjectBits: public BitField<int, 0, 3> {};
641 class ValueBits: public BitField<int, 3, 3> {};
642 class AddressBits: public BitField<int, 6, 3> {};
643 class RememberedSetActionBits: public BitField<RememberedSetAction, 9, 1> {};
644 class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 10, 1> {};
645
646 Register object_;
647 Register value_;
648 Register address_;
649 RememberedSetAction remembered_set_action_;
650 SaveFPRegsMode save_fp_regs_mode_;
651 RegisterAllocation regs_;
652};
653
654
ricow@chromium.org65fae842010-08-25 15:26:24 +0000655} } // namespace v8::internal
656
657#endif // V8_IA32_CODE_STUBS_IA32_H_