blob: ead7761f6576d0b08e1ef288a01267e78979997a [file] [log] [blame]
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001// Copyright 2010 the V8 project authors. All rights reserved.
2// 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);
52 private:
53 TranscendentalCache::Type type_;
Ben Murdochb0fe1622011-05-05 13:52:32 +010054 ArgumentType argument_type_;
55
Kristian Monsen80d68ea2010-09-08 11:05:35 +010056 Major MajorKey() { return TranscendentalCache; }
Ben Murdochb0fe1622011-05-05 13:52:32 +010057 int MinorKey() { return type_ | argument_type_; }
Kristian Monsen80d68ea2010-09-08 11:05:35 +010058 Runtime::FunctionId RuntimeFunction();
59 void GenerateOperation(MacroAssembler* masm);
60};
61
62
63class ToBooleanStub: public CodeStub {
64 public:
65 ToBooleanStub() { }
66
67 void Generate(MacroAssembler* masm);
68
69 private:
70 Major MajorKey() { return ToBoolean; }
71 int MinorKey() { return 0; }
72};
73
74
Ben Murdoch257744e2011-11-30 15:57:28 +000075class UnaryOpStub: public CodeStub {
Ben Murdochb0fe1622011-05-05 13:52:32 +010076 public:
Ben Murdoch257744e2011-11-30 15:57:28 +000077 UnaryOpStub(Token::Value op, UnaryOverwriteMode mode)
Ben Murdochb0fe1622011-05-05 13:52:32 +010078 : op_(op),
79 mode_(mode),
Ben Murdoch257744e2011-11-30 15:57:28 +000080 operand_type_(UnaryOpIC::UNINITIALIZED),
81 name_(NULL) {
82 }
83
84 UnaryOpStub(int key, UnaryOpIC::TypeInfo operand_type)
85 : op_(OpBits::decode(key)),
86 mode_(ModeBits::decode(key)),
87 operand_type_(operand_type),
88 name_(NULL) {
89 }
90
91 private:
92 Token::Value op_;
93 UnaryOverwriteMode mode_;
94
95 // Operand type information determined at runtime.
96 UnaryOpIC::TypeInfo operand_type_;
97
98 char* name_;
99
100 const char* GetName();
101
102#ifdef DEBUG
103 void Print() {
104 PrintF("TypeRecordingUnaryOpStub %d (op %s), "
105 "(mode %d, runtime_type_info %s)\n",
106 MinorKey(),
107 Token::String(op_),
108 static_cast<int>(mode_),
109 UnaryOpIC::GetName(operand_type_));
110 }
111#endif
112
113 class ModeBits: public BitField<UnaryOverwriteMode, 0, 1> {};
114 class OpBits: public BitField<Token::Value, 1, 7> {};
115 class OperandTypeInfoBits: public BitField<UnaryOpIC::TypeInfo, 8, 3> {};
116
117 Major MajorKey() { return UnaryOp; }
118 int MinorKey() {
119 return ModeBits::encode(mode_)
120 | OpBits::encode(op_)
121 | OperandTypeInfoBits::encode(operand_type_);
122 }
123
124 // Note: A lot of the helper functions below will vanish when we use virtual
125 // function instead of switch more often.
126 void Generate(MacroAssembler* masm);
127
128 void GenerateTypeTransition(MacroAssembler* masm);
129
130 void GenerateSmiStub(MacroAssembler* masm);
131 void GenerateSmiStubSub(MacroAssembler* masm);
132 void GenerateSmiStubBitNot(MacroAssembler* masm);
133 void GenerateSmiCodeSub(MacroAssembler* masm,
134 Label* non_smi,
135 Label* undo,
136 Label* slow,
137 Label::Distance non_smi_near = Label::kFar,
138 Label::Distance undo_near = Label::kFar,
139 Label::Distance slow_near = Label::kFar);
140 void GenerateSmiCodeBitNot(MacroAssembler* masm,
141 Label* non_smi,
142 Label::Distance non_smi_near = Label::kFar);
143 void GenerateSmiCodeUndo(MacroAssembler* masm);
144
145 void GenerateHeapNumberStub(MacroAssembler* masm);
146 void GenerateHeapNumberStubSub(MacroAssembler* masm);
147 void GenerateHeapNumberStubBitNot(MacroAssembler* masm);
148 void GenerateHeapNumberCodeSub(MacroAssembler* masm, Label* slow);
149 void GenerateHeapNumberCodeBitNot(MacroAssembler* masm, Label* slow);
150
151 void GenerateGenericStub(MacroAssembler* masm);
152 void GenerateGenericStubSub(MacroAssembler* masm);
153 void GenerateGenericStubBitNot(MacroAssembler* masm);
154 void GenerateGenericCodeFallback(MacroAssembler* masm);
155
156 virtual int GetCodeKind() { return Code::UNARY_OP_IC; }
157
158 virtual InlineCacheState GetICState() {
159 return UnaryOpIC::ToState(operand_type_);
160 }
161
162 virtual void FinishCode(Code* code) {
163 code->set_unary_op_type(operand_type_);
164 }
165};
166
167
168class BinaryOpStub: public CodeStub {
169 public:
170 BinaryOpStub(Token::Value op, OverwriteMode mode)
171 : op_(op),
172 mode_(mode),
173 operands_type_(BinaryOpIC::UNINITIALIZED),
174 result_type_(BinaryOpIC::UNINITIALIZED),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100175 name_(NULL) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100176 use_sse3_ = CpuFeatures::IsSupported(SSE3);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100177 ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
178 }
179
Ben Murdoch257744e2011-11-30 15:57:28 +0000180 BinaryOpStub(
Ben Murdochb0fe1622011-05-05 13:52:32 +0100181 int key,
Ben Murdoch257744e2011-11-30 15:57:28 +0000182 BinaryOpIC::TypeInfo operands_type,
183 BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED)
Ben Murdochb0fe1622011-05-05 13:52:32 +0100184 : op_(OpBits::decode(key)),
185 mode_(ModeBits::decode(key)),
186 use_sse3_(SSE3Bits::decode(key)),
187 operands_type_(operands_type),
188 result_type_(result_type),
189 name_(NULL) { }
190
Ben Murdochb0fe1622011-05-05 13:52:32 +0100191 private:
192 enum SmiCodeGenerateHeapNumberResults {
193 ALLOW_HEAPNUMBER_RESULTS,
194 NO_HEAPNUMBER_RESULTS
195 };
196
197 Token::Value op_;
198 OverwriteMode mode_;
199 bool use_sse3_;
200
201 // Operand type information determined at runtime.
Ben Murdoch257744e2011-11-30 15:57:28 +0000202 BinaryOpIC::TypeInfo operands_type_;
203 BinaryOpIC::TypeInfo result_type_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100204
205 char* name_;
206
207 const char* GetName();
208
209#ifdef DEBUG
210 void Print() {
Ben Murdoch257744e2011-11-30 15:57:28 +0000211 PrintF("BinaryOpStub %d (op %s), "
Ben Murdochb0fe1622011-05-05 13:52:32 +0100212 "(mode %d, runtime_type_info %s)\n",
213 MinorKey(),
214 Token::String(op_),
215 static_cast<int>(mode_),
Ben Murdoch257744e2011-11-30 15:57:28 +0000216 BinaryOpIC::GetName(operands_type_));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100217 }
218#endif
219
220 // Minor key encoding in 16 bits RRRTTTSOOOOOOOMM.
221 class ModeBits: public BitField<OverwriteMode, 0, 2> {};
222 class OpBits: public BitField<Token::Value, 2, 7> {};
223 class SSE3Bits: public BitField<bool, 9, 1> {};
Ben Murdoch257744e2011-11-30 15:57:28 +0000224 class OperandTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 10, 3> {};
225 class ResultTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 13, 3> {};
Ben Murdochb0fe1622011-05-05 13:52:32 +0100226
Ben Murdoch257744e2011-11-30 15:57:28 +0000227 Major MajorKey() { return BinaryOp; }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100228 int MinorKey() {
229 return OpBits::encode(op_)
230 | ModeBits::encode(mode_)
231 | SSE3Bits::encode(use_sse3_)
232 | OperandTypeInfoBits::encode(operands_type_)
233 | ResultTypeInfoBits::encode(result_type_);
234 }
235
236 void Generate(MacroAssembler* masm);
237 void GenerateGeneric(MacroAssembler* masm);
238 void GenerateSmiCode(MacroAssembler* masm,
239 Label* slow,
240 SmiCodeGenerateHeapNumberResults heapnumber_results);
241 void GenerateLoadArguments(MacroAssembler* masm);
242 void GenerateReturn(MacroAssembler* masm);
243 void GenerateUninitializedStub(MacroAssembler* masm);
244 void GenerateSmiStub(MacroAssembler* masm);
245 void GenerateInt32Stub(MacroAssembler* masm);
246 void GenerateHeapNumberStub(MacroAssembler* masm);
Steve Block44f0eee2011-05-26 01:26:41 +0100247 void GenerateOddballStub(MacroAssembler* masm);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100248 void GenerateStringStub(MacroAssembler* masm);
Ben Murdoch257744e2011-11-30 15:57:28 +0000249 void GenerateBothStringStub(MacroAssembler* masm);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100250 void GenerateGenericStub(MacroAssembler* masm);
Steve Block1e0659c2011-05-24 12:43:12 +0100251 void GenerateAddStrings(MacroAssembler* masm);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100252
253 void GenerateHeapResultAllocation(MacroAssembler* masm, Label* alloc_failure);
254 void GenerateRegisterArgsPush(MacroAssembler* masm);
255 void GenerateTypeTransition(MacroAssembler* masm);
256 void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm);
257
Ben Murdoch257744e2011-11-30 15:57:28 +0000258 virtual int GetCodeKind() { return Code::BINARY_OP_IC; }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100259
260 virtual InlineCacheState GetICState() {
Ben Murdoch257744e2011-11-30 15:57:28 +0000261 return BinaryOpIC::ToState(operands_type_);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100262 }
263
264 virtual void FinishCode(Code* code) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000265 code->set_binary_op_type(operands_type_);
266 code->set_binary_op_result_type(result_type_);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100267 }
268
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100269 friend class CodeGenerator;
270};
271
272
273class StringHelper : public AllStatic {
274 public:
275 // Generate code for copying characters using a simple loop. This should only
276 // be used in places where the number of characters is small and the
277 // additional setup and checking in GenerateCopyCharactersREP adds too much
278 // overhead. Copying of overlapping regions is not supported.
279 static void GenerateCopyCharacters(MacroAssembler* masm,
280 Register dest,
281 Register src,
282 Register count,
283 Register scratch,
284 bool ascii);
285
286 // Generate code for copying characters using the rep movs instruction.
287 // Copies ecx characters from esi to edi. Copying of overlapping regions is
288 // not supported.
289 static void GenerateCopyCharactersREP(MacroAssembler* masm,
290 Register dest, // Must be edi.
291 Register src, // Must be esi.
292 Register count, // Must be ecx.
293 Register scratch, // Neither of above.
294 bool ascii);
295
Iain Merrick9ac36c92010-09-13 15:29:50 +0100296 // Probe the symbol table for a two character string. If the string
297 // requires non-standard hashing a jump to the label not_probed is
298 // performed and registers c1 and c2 are preserved. In all other
299 // cases they are clobbered. If the string is not found by probing a
300 // jump to the label not_found is performed. This jump does not
301 // guarantee that the string is not in the symbol table. If the
302 // string is found the code falls through with the string in
303 // register eax.
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100304 static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
305 Register c1,
306 Register c2,
307 Register scratch1,
308 Register scratch2,
309 Register scratch3,
Iain Merrick9ac36c92010-09-13 15:29:50 +0100310 Label* not_probed,
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100311 Label* not_found);
312
313 // Generate string hash.
314 static void GenerateHashInit(MacroAssembler* masm,
315 Register hash,
316 Register character,
317 Register scratch);
318 static void GenerateHashAddCharacter(MacroAssembler* masm,
319 Register hash,
320 Register character,
321 Register scratch);
322 static void GenerateHashGetHash(MacroAssembler* masm,
323 Register hash,
324 Register scratch);
325
326 private:
327 DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
328};
329
330
331// Flag that indicates how to generate code for the stub StringAddStub.
332enum StringAddFlags {
333 NO_STRING_ADD_FLAGS = 0,
Iain Merrick9ac36c92010-09-13 15:29:50 +0100334 // Omit left string check in stub (left is definitely a string).
335 NO_STRING_CHECK_LEFT_IN_STUB = 1 << 0,
336 // Omit right string check in stub (right is definitely a string).
337 NO_STRING_CHECK_RIGHT_IN_STUB = 1 << 1,
338 // Omit both string checks in stub.
339 NO_STRING_CHECK_IN_STUB =
340 NO_STRING_CHECK_LEFT_IN_STUB | NO_STRING_CHECK_RIGHT_IN_STUB
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100341};
342
343
344class StringAddStub: public CodeStub {
345 public:
Iain Merrick9ac36c92010-09-13 15:29:50 +0100346 explicit StringAddStub(StringAddFlags flags) : flags_(flags) {}
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100347
348 private:
349 Major MajorKey() { return StringAdd; }
Iain Merrick9ac36c92010-09-13 15:29:50 +0100350 int MinorKey() { return flags_; }
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100351
352 void Generate(MacroAssembler* masm);
353
Iain Merrick9ac36c92010-09-13 15:29:50 +0100354 void GenerateConvertArgument(MacroAssembler* masm,
355 int stack_offset,
356 Register arg,
357 Register scratch1,
358 Register scratch2,
359 Register scratch3,
360 Label* slow);
361
362 const StringAddFlags flags_;
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100363};
364
365
366class SubStringStub: public CodeStub {
367 public:
368 SubStringStub() {}
369
370 private:
371 Major MajorKey() { return SubString; }
372 int MinorKey() { return 0; }
373
374 void Generate(MacroAssembler* masm);
375};
376
377
378class StringCompareStub: public CodeStub {
379 public:
Ben Murdoch257744e2011-11-30 15:57:28 +0000380 StringCompareStub() { }
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100381
Ben Murdoch257744e2011-11-30 15:57:28 +0000382 // Compares two flat ASCII strings and returns result in eax.
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100383 static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
384 Register left,
385 Register right,
386 Register scratch1,
387 Register scratch2,
388 Register scratch3);
389
Ben Murdoch257744e2011-11-30 15:57:28 +0000390 // Compares two flat ASCII strings for equality and returns result
391 // in eax.
392 static void GenerateFlatAsciiStringEquals(MacroAssembler* masm,
393 Register left,
394 Register right,
395 Register scratch1,
396 Register scratch2);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100397
Ben Murdoch257744e2011-11-30 15:57:28 +0000398 private:
399 virtual Major MajorKey() { return StringCompare; }
400 virtual int MinorKey() { return 0; }
401 virtual void Generate(MacroAssembler* masm);
402
403 static void GenerateAsciiCharsCompareLoop(
404 MacroAssembler* masm,
405 Register left,
406 Register right,
407 Register length,
408 Register scratch,
409 Label* chars_not_equal,
410 Label::Distance chars_not_equal_near = Label::kFar);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100411};
412
413
414class NumberToStringStub: public CodeStub {
415 public:
416 NumberToStringStub() { }
417
418 // Generate code to do a lookup in the number string cache. If the number in
419 // the register object is found in the cache the generated code falls through
420 // with the result in the result register. The object and the result register
421 // can be the same. If the number is not found in the cache the code jumps to
422 // the label not_found with only the content of register object unchanged.
423 static void GenerateLookupNumberStringCache(MacroAssembler* masm,
424 Register object,
425 Register result,
426 Register scratch1,
427 Register scratch2,
428 bool object_is_smi,
429 Label* not_found);
430
431 private:
432 Major MajorKey() { return NumberToString; }
433 int MinorKey() { return 0; }
434
435 void Generate(MacroAssembler* masm);
436
437 const char* GetName() { return "NumberToStringStub"; }
438
439#ifdef DEBUG
440 void Print() {
441 PrintF("NumberToStringStub\n");
442 }
443#endif
444};
445
Ben Murdoch257744e2011-11-30 15:57:28 +0000446
447class StringDictionaryLookupStub: public CodeStub {
448 public:
449 enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
450
451 StringDictionaryLookupStub(Register dictionary,
452 Register result,
453 Register index,
454 LookupMode mode)
455 : dictionary_(dictionary), result_(result), index_(index), mode_(mode) { }
456
457 void Generate(MacroAssembler* masm);
458
459 MUST_USE_RESULT static MaybeObject* GenerateNegativeLookup(
460 MacroAssembler* masm,
461 Label* miss,
462 Label* done,
463 Register properties,
464 String* name,
465 Register r0);
466
467 static void GeneratePositiveLookup(MacroAssembler* masm,
468 Label* miss,
469 Label* done,
470 Register elements,
471 Register name,
472 Register r0,
473 Register r1);
474
475 private:
476 static const int kInlinedProbes = 4;
477 static const int kTotalProbes = 20;
478
479 static const int kCapacityOffset =
480 StringDictionary::kHeaderSize +
481 StringDictionary::kCapacityIndex * kPointerSize;
482
483 static const int kElementsStartOffset =
484 StringDictionary::kHeaderSize +
485 StringDictionary::kElementsStartIndex * kPointerSize;
486
487
488#ifdef DEBUG
489 void Print() {
490 PrintF("StringDictionaryLookupStub\n");
491 }
492#endif
493
494 Major MajorKey() { return StringDictionaryNegativeLookup; }
495
496 int MinorKey() {
497 return DictionaryBits::encode(dictionary_.code()) |
498 ResultBits::encode(result_.code()) |
499 IndexBits::encode(index_.code()) |
500 LookupModeBits::encode(mode_);
501 }
502
503 class DictionaryBits: public BitField<int, 0, 3> {};
504 class ResultBits: public BitField<int, 3, 3> {};
505 class IndexBits: public BitField<int, 6, 3> {};
506 class LookupModeBits: public BitField<LookupMode, 9, 1> {};
507
508 Register dictionary_;
509 Register result_;
510 Register index_;
511 LookupMode mode_;
512};
513
514
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100515} } // namespace v8::internal
516
517#endif // V8_IA32_CODE_STUBS_IA32_H_