blob: 27744034af8ff23f27a4b40ee7b1d095d715dabf [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);
51 private:
52 TranscendentalCache::Type type_;
Ben Murdoche0cee9b2011-05-25 10:26:03 +010053 ArgumentType argument_type_;
54
Kristian Monsen80d68ea2010-09-08 11:05:35 +010055 Major MajorKey() { return TranscendentalCache; }
Ben Murdoche0cee9b2011-05-25 10:26:03 +010056 int MinorKey() { return type_ | argument_type_; }
Kristian Monsen80d68ea2010-09-08 11:05:35 +010057 Runtime::FunctionId RuntimeFunction();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010058 void GenerateOperation(MacroAssembler* masm);
Kristian Monsen80d68ea2010-09-08 11:05:35 +010059};
60
61
62class ToBooleanStub: public CodeStub {
63 public:
64 ToBooleanStub() { }
65
66 void Generate(MacroAssembler* masm);
67
68 private:
69 Major MajorKey() { return ToBoolean; }
70 int MinorKey() { return 0; }
71};
72
73
Ben Murdoch257744e2011-11-30 15:57:28 +000074class UnaryOpStub: public CodeStub {
Ben Murdoch086aeea2011-05-13 15:57:08 +010075 public:
Ben Murdoch257744e2011-11-30 15:57:28 +000076 UnaryOpStub(Token::Value op, UnaryOverwriteMode mode)
Ben Murdoch086aeea2011-05-13 15:57:08 +010077 : op_(op),
78 mode_(mode),
Ben Murdoch257744e2011-11-30 15:57:28 +000079 operand_type_(UnaryOpIC::UNINITIALIZED),
80 name_(NULL) {
81 }
82
83 UnaryOpStub(
84 int key,
85 UnaryOpIC::TypeInfo operand_type)
86 : op_(OpBits::decode(key)),
87 mode_(ModeBits::decode(key)),
88 operand_type_(operand_type),
89 name_(NULL) {
90 }
91
92 private:
93 Token::Value op_;
94 UnaryOverwriteMode mode_;
95
96 // Operand type information determined at runtime.
97 UnaryOpIC::TypeInfo operand_type_;
98
99 char* name_;
100
101 const char* GetName();
102
103#ifdef DEBUG
104 void Print() {
105 PrintF("UnaryOpStub %d (op %s), "
106 "(mode %d, runtime_type_info %s)\n",
107 MinorKey(),
108 Token::String(op_),
109 static_cast<int>(mode_),
110 UnaryOpIC::GetName(operand_type_));
111 }
112#endif
113
114 class ModeBits: public BitField<UnaryOverwriteMode, 0, 1> {};
115 class OpBits: public BitField<Token::Value, 1, 7> {};
116 class OperandTypeInfoBits: public BitField<UnaryOpIC::TypeInfo, 8, 3> {};
117
118 Major MajorKey() { return UnaryOp; }
119 int MinorKey() {
120 return ModeBits::encode(mode_)
121 | OpBits::encode(op_)
122 | OperandTypeInfoBits::encode(operand_type_);
123 }
124
125 // Note: A lot of the helper functions below will vanish when we use virtual
126 // function instead of switch more often.
127 void Generate(MacroAssembler* masm);
128
129 void GenerateTypeTransition(MacroAssembler* masm);
130
131 void GenerateSmiStub(MacroAssembler* masm);
132 void GenerateSmiStubSub(MacroAssembler* masm);
133 void GenerateSmiStubBitNot(MacroAssembler* masm);
134 void GenerateSmiCodeSub(MacroAssembler* masm,
135 Label* non_smi,
136 Label* slow,
137 Label::Distance non_smi_near = Label::kFar,
138 Label::Distance slow_near = Label::kFar);
139 void GenerateSmiCodeBitNot(MacroAssembler* masm,
140 Label* non_smi,
141 Label::Distance non_smi_near);
142
143 void GenerateHeapNumberStub(MacroAssembler* masm);
144 void GenerateHeapNumberStubSub(MacroAssembler* masm);
145 void GenerateHeapNumberStubBitNot(MacroAssembler* masm);
146 void GenerateHeapNumberCodeSub(MacroAssembler* masm, Label* slow);
147 void GenerateHeapNumberCodeBitNot(MacroAssembler* masm, Label* slow);
148
149 void GenerateGenericStub(MacroAssembler* masm);
150 void GenerateGenericStubSub(MacroAssembler* masm);
151 void GenerateGenericStubBitNot(MacroAssembler* masm);
152 void GenerateGenericCodeFallback(MacroAssembler* masm);
153
154 virtual int GetCodeKind() { return Code::UNARY_OP_IC; }
155
156 virtual InlineCacheState GetICState() {
157 return UnaryOpIC::ToState(operand_type_);
158 }
159
160 virtual void FinishCode(Code* code) {
161 code->set_unary_op_type(operand_type_);
162 }
163};
164
165
166class BinaryOpStub: public CodeStub {
167 public:
168 BinaryOpStub(Token::Value op, OverwriteMode mode)
169 : op_(op),
170 mode_(mode),
171 operands_type_(BinaryOpIC::UNINITIALIZED),
172 result_type_(BinaryOpIC::UNINITIALIZED),
Ben Murdoch086aeea2011-05-13 15:57:08 +0100173 name_(NULL) {
174 ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
175 }
176
Ben Murdoch257744e2011-11-30 15:57:28 +0000177 BinaryOpStub(
Ben Murdoch086aeea2011-05-13 15:57:08 +0100178 int key,
Ben Murdoch257744e2011-11-30 15:57:28 +0000179 BinaryOpIC::TypeInfo operands_type,
180 BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED)
Ben Murdoch086aeea2011-05-13 15:57:08 +0100181 : op_(OpBits::decode(key)),
182 mode_(ModeBits::decode(key)),
183 operands_type_(operands_type),
184 result_type_(result_type),
185 name_(NULL) { }
186
187 private:
188 enum SmiCodeGenerateHeapNumberResults {
189 ALLOW_HEAPNUMBER_RESULTS,
190 NO_HEAPNUMBER_RESULTS
191 };
192
193 Token::Value op_;
194 OverwriteMode mode_;
195
196 // Operand type information determined at runtime.
Ben Murdoch257744e2011-11-30 15:57:28 +0000197 BinaryOpIC::TypeInfo operands_type_;
198 BinaryOpIC::TypeInfo result_type_;
Ben Murdoch086aeea2011-05-13 15:57:08 +0100199
200 char* name_;
201
202 const char* GetName();
203
204#ifdef DEBUG
205 void Print() {
Ben Murdoch257744e2011-11-30 15:57:28 +0000206 PrintF("BinaryOpStub %d (op %s), "
Ben Murdoch086aeea2011-05-13 15:57:08 +0100207 "(mode %d, runtime_type_info %s)\n",
208 MinorKey(),
209 Token::String(op_),
210 static_cast<int>(mode_),
Ben Murdoch257744e2011-11-30 15:57:28 +0000211 BinaryOpIC::GetName(operands_type_));
Ben Murdoch086aeea2011-05-13 15:57:08 +0100212 }
213#endif
214
215 // Minor key encoding in 15 bits RRRTTTOOOOOOOMM.
216 class ModeBits: public BitField<OverwriteMode, 0, 2> {};
217 class OpBits: public BitField<Token::Value, 2, 7> {};
Ben Murdoch257744e2011-11-30 15:57:28 +0000218 class OperandTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 9, 3> {};
219 class ResultTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 12, 3> {};
Ben Murdoch086aeea2011-05-13 15:57:08 +0100220
Ben Murdoch257744e2011-11-30 15:57:28 +0000221 Major MajorKey() { return BinaryOp; }
Ben Murdoch086aeea2011-05-13 15:57:08 +0100222 int MinorKey() {
223 return OpBits::encode(op_)
224 | ModeBits::encode(mode_)
225 | OperandTypeInfoBits::encode(operands_type_)
226 | ResultTypeInfoBits::encode(result_type_);
227 }
228
229 void Generate(MacroAssembler* masm);
230 void GenerateGeneric(MacroAssembler* masm);
231 void GenerateSmiCode(MacroAssembler* masm,
232 Label* slow,
233 SmiCodeGenerateHeapNumberResults heapnumber_results);
Steve Block1e0659c2011-05-24 12:43:12 +0100234 void GenerateFloatingPointCode(MacroAssembler* masm,
235 Label* allocation_failure,
236 Label* non_numeric_failure);
237 void GenerateStringAddCode(MacroAssembler* masm);
238 void GenerateCallRuntimeCode(MacroAssembler* masm);
Ben Murdoch086aeea2011-05-13 15:57:08 +0100239 void GenerateLoadArguments(MacroAssembler* masm);
240 void GenerateReturn(MacroAssembler* masm);
241 void GenerateUninitializedStub(MacroAssembler* masm);
242 void GenerateSmiStub(MacroAssembler* masm);
243 void GenerateInt32Stub(MacroAssembler* masm);
244 void GenerateHeapNumberStub(MacroAssembler* masm);
Steve Block44f0eee2011-05-26 01:26:41 +0100245 void GenerateOddballStub(MacroAssembler* masm);
Ben Murdoch086aeea2011-05-13 15:57:08 +0100246 void GenerateStringStub(MacroAssembler* masm);
Ben Murdoch257744e2011-11-30 15:57:28 +0000247 void GenerateBothStringStub(MacroAssembler* masm);
Ben Murdoch086aeea2011-05-13 15:57:08 +0100248 void GenerateGenericStub(MacroAssembler* masm);
249
250 void GenerateHeapResultAllocation(MacroAssembler* masm, Label* alloc_failure);
251 void GenerateRegisterArgsPush(MacroAssembler* masm);
252 void GenerateTypeTransition(MacroAssembler* masm);
253 void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm);
254
Ben Murdoch257744e2011-11-30 15:57:28 +0000255 virtual int GetCodeKind() { return Code::BINARY_OP_IC; }
Ben Murdoch086aeea2011-05-13 15:57:08 +0100256
257 virtual InlineCacheState GetICState() {
Ben Murdoch257744e2011-11-30 15:57:28 +0000258 return BinaryOpIC::ToState(operands_type_);
Ben Murdoch086aeea2011-05-13 15:57:08 +0100259 }
260
261 virtual void FinishCode(Code* code) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000262 code->set_binary_op_type(operands_type_);
263 code->set_binary_op_result_type(result_type_);
Ben Murdoch086aeea2011-05-13 15:57:08 +0100264 }
265
266 friend class CodeGenerator;
267};
268
269
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100270class StringHelper : public AllStatic {
271 public:
272 // Generate code for copying characters using a simple loop. This should only
273 // be used in places where the number of characters is small and the
274 // additional setup and checking in GenerateCopyCharactersREP adds too much
275 // overhead. Copying of overlapping regions is not supported.
276 static void GenerateCopyCharacters(MacroAssembler* masm,
277 Register dest,
278 Register src,
279 Register count,
280 bool ascii);
281
282 // Generate code for copying characters using the rep movs instruction.
283 // Copies rcx characters from rsi to rdi. Copying of overlapping regions is
284 // not supported.
285 static void GenerateCopyCharactersREP(MacroAssembler* masm,
286 Register dest, // Must be rdi.
287 Register src, // Must be rsi.
288 Register count, // Must be rcx.
289 bool ascii);
290
291
292 // Probe the symbol table for a two character string. If the string is
293 // not found by probing a jump to the label not_found is performed. This jump
294 // does not guarantee that the string is not in the symbol table. If the
295 // string is found the code falls through with the string in register rax.
296 static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
297 Register c1,
298 Register c2,
299 Register scratch1,
300 Register scratch2,
301 Register scratch3,
302 Register scratch4,
303 Label* not_found);
304
305 // Generate string hash.
306 static void GenerateHashInit(MacroAssembler* masm,
307 Register hash,
308 Register character,
309 Register scratch);
310 static void GenerateHashAddCharacter(MacroAssembler* masm,
311 Register hash,
312 Register character,
313 Register scratch);
314 static void GenerateHashGetHash(MacroAssembler* masm,
315 Register hash,
316 Register scratch);
317
318 private:
319 DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
320};
321
322
323// Flag that indicates how to generate code for the stub StringAddStub.
324enum StringAddFlags {
325 NO_STRING_ADD_FLAGS = 0,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100326 // Omit left string check in stub (left is definitely a string).
327 NO_STRING_CHECK_LEFT_IN_STUB = 1 << 0,
328 // Omit right string check in stub (right is definitely a string).
329 NO_STRING_CHECK_RIGHT_IN_STUB = 1 << 1,
330 // Omit both string checks in stub.
331 NO_STRING_CHECK_IN_STUB =
332 NO_STRING_CHECK_LEFT_IN_STUB | NO_STRING_CHECK_RIGHT_IN_STUB
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100333};
334
335
336class StringAddStub: public CodeStub {
337 public:
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100338 explicit StringAddStub(StringAddFlags flags) : flags_(flags) {}
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100339
340 private:
341 Major MajorKey() { return StringAdd; }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100342 int MinorKey() { return flags_; }
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100343
344 void Generate(MacroAssembler* masm);
345
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100346 void GenerateConvertArgument(MacroAssembler* masm,
347 int stack_offset,
348 Register arg,
349 Register scratch1,
350 Register scratch2,
351 Register scratch3,
352 Label* slow);
353
354 const StringAddFlags flags_;
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100355};
356
357
358class SubStringStub: public CodeStub {
359 public:
360 SubStringStub() {}
361
362 private:
363 Major MajorKey() { return SubString; }
364 int MinorKey() { return 0; }
365
366 void Generate(MacroAssembler* masm);
367};
368
369
370class StringCompareStub: public CodeStub {
371 public:
Ben Murdoch257744e2011-11-30 15:57:28 +0000372 StringCompareStub() {}
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100373
Ben Murdoch257744e2011-11-30 15:57:28 +0000374 // Compares two flat ASCII strings and returns result in rax.
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100375 static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
376 Register left,
377 Register right,
378 Register scratch1,
379 Register scratch2,
380 Register scratch3,
381 Register scratch4);
382
Ben Murdoch257744e2011-11-30 15:57:28 +0000383 // Compares two flat ASCII strings for equality and returns result
384 // in rax.
385 static void GenerateFlatAsciiStringEquals(MacroAssembler* masm,
386 Register left,
387 Register right,
388 Register scratch1,
389 Register scratch2);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100390
Ben Murdoch257744e2011-11-30 15:57:28 +0000391 private:
392 virtual Major MajorKey() { return StringCompare; }
393 virtual int MinorKey() { return 0; }
394 virtual void Generate(MacroAssembler* masm);
395
396 static void GenerateAsciiCharsCompareLoop(
397 MacroAssembler* masm,
398 Register left,
399 Register right,
400 Register length,
401 Register scratch,
402 Label* chars_not_equal,
403 Label::Distance near_jump = Label::kFar);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100404};
405
406
407class NumberToStringStub: public CodeStub {
408 public:
409 NumberToStringStub() { }
410
411 // Generate code to do a lookup in the number string cache. If the number in
412 // the register object is found in the cache the generated code falls through
413 // with the result in the result register. The object and the result register
414 // can be the same. If the number is not found in the cache the code jumps to
415 // the label not_found with only the content of register object unchanged.
416 static void GenerateLookupNumberStringCache(MacroAssembler* masm,
417 Register object,
418 Register result,
419 Register scratch1,
420 Register scratch2,
421 bool object_is_smi,
422 Label* not_found);
423
424 private:
425 static void GenerateConvertHashCodeToIndex(MacroAssembler* masm,
426 Register hash,
427 Register mask);
428
429 Major MajorKey() { return NumberToString; }
430 int MinorKey() { return 0; }
431
432 void Generate(MacroAssembler* masm);
433
434 const char* GetName() { return "NumberToStringStub"; }
435
436#ifdef DEBUG
437 void Print() {
438 PrintF("NumberToStringStub\n");
439 }
440#endif
441};
442
443
Ben Murdoch257744e2011-11-30 15:57:28 +0000444class StringDictionaryLookupStub: public CodeStub {
445 public:
446 enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
447
448 StringDictionaryLookupStub(Register dictionary,
449 Register result,
450 Register index,
451 LookupMode mode)
452 : dictionary_(dictionary), result_(result), index_(index), mode_(mode) { }
453
454 void Generate(MacroAssembler* masm);
455
456 MUST_USE_RESULT static MaybeObject* GenerateNegativeLookup(
457 MacroAssembler* masm,
458 Label* miss,
459 Label* done,
460 Register properties,
461 String* name,
462 Register r0);
463
464 static void GeneratePositiveLookup(MacroAssembler* masm,
465 Label* miss,
466 Label* done,
467 Register elements,
468 Register name,
469 Register r0,
470 Register r1);
471
472 private:
473 static const int kInlinedProbes = 4;
474 static const int kTotalProbes = 20;
475
476 static const int kCapacityOffset =
477 StringDictionary::kHeaderSize +
478 StringDictionary::kCapacityIndex * kPointerSize;
479
480 static const int kElementsStartOffset =
481 StringDictionary::kHeaderSize +
482 StringDictionary::kElementsStartIndex * kPointerSize;
483
484
485#ifdef DEBUG
486 void Print() {
487 PrintF("StringDictionaryLookupStub\n");
488 }
489#endif
490
491 Major MajorKey() { return StringDictionaryNegativeLookup; }
492
493 int MinorKey() {
494 return DictionaryBits::encode(dictionary_.code()) |
495 ResultBits::encode(result_.code()) |
496 IndexBits::encode(index_.code()) |
497 LookupModeBits::encode(mode_);
498 }
499
500 class DictionaryBits: public BitField<int, 0, 4> {};
501 class ResultBits: public BitField<int, 4, 4> {};
502 class IndexBits: public BitField<int, 8, 4> {};
503 class LookupModeBits: public BitField<LookupMode, 12, 1> {};
504
505 Register dictionary_;
506 Register result_;
507 Register index_;
508 LookupMode mode_;
509};
510
511
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100512} } // namespace v8::internal
513
514#endif // V8_X64_CODE_STUBS_X64_H_