blob: 32a37b215d158e7d76a5f8b857e9d7110983fa72 [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
74// Flag that indicates how to generate code for the stub GenericBinaryOpStub.
75enum GenericBinaryFlags {
76 NO_GENERIC_BINARY_FLAGS = 0,
77 NO_SMI_CODE_IN_STUB = 1 << 0 // Omit smi code in stub.
78};
79
80
81class GenericBinaryOpStub: public CodeStub {
82 public:
83 GenericBinaryOpStub(Token::Value op,
84 OverwriteMode mode,
85 GenericBinaryFlags flags,
86 TypeInfo operands_type = TypeInfo::Unknown())
87 : op_(op),
88 mode_(mode),
89 flags_(flags),
90 args_in_registers_(false),
91 args_reversed_(false),
92 static_operands_type_(operands_type),
93 runtime_operands_type_(BinaryOpIC::DEFAULT),
94 name_(NULL) {
95 ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
96 }
97
Steve Block9fac8402011-05-12 15:51:54 +010098 GenericBinaryOpStub(int key, BinaryOpIC::TypeInfo runtime_operands_type)
Kristian Monsen80d68ea2010-09-08 11:05:35 +010099 : op_(OpBits::decode(key)),
100 mode_(ModeBits::decode(key)),
101 flags_(FlagBits::decode(key)),
102 args_in_registers_(ArgsInRegistersBits::decode(key)),
103 args_reversed_(ArgsReversedBits::decode(key)),
104 static_operands_type_(TypeInfo::ExpandedRepresentation(
105 StaticTypeInfoBits::decode(key))),
Steve Block9fac8402011-05-12 15:51:54 +0100106 runtime_operands_type_(runtime_operands_type),
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100107 name_(NULL) {
108 }
109
110 // Generate code to call the stub with the supplied arguments. This will add
111 // code at the call site to prepare arguments either in registers or on the
112 // stack together with the actual call.
113 void GenerateCall(MacroAssembler* masm, Register left, Register right);
114 void GenerateCall(MacroAssembler* masm, Register left, Smi* right);
115 void GenerateCall(MacroAssembler* masm, Smi* left, Register right);
116
117 bool ArgsInRegistersSupported() {
118 return (op_ == Token::ADD) || (op_ == Token::SUB)
119 || (op_ == Token::MUL) || (op_ == Token::DIV);
120 }
121
122 private:
123 Token::Value op_;
124 OverwriteMode mode_;
125 GenericBinaryFlags flags_;
126 bool args_in_registers_; // Arguments passed in registers not on the stack.
127 bool args_reversed_; // Left and right argument are swapped.
128
129 // Number type information of operands, determined by code generator.
130 TypeInfo static_operands_type_;
131
132 // Operand type information determined at runtime.
133 BinaryOpIC::TypeInfo runtime_operands_type_;
134
135 char* name_;
136
137 const char* GetName();
138
139#ifdef DEBUG
140 void Print() {
141 PrintF("GenericBinaryOpStub %d (op %s), "
Ben Murdoch086aeea2011-05-13 15:57:08 +0100142 "(mode %d, flags %d, registers %d, reversed %d, type_info %s)\n",
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100143 MinorKey(),
144 Token::String(op_),
145 static_cast<int>(mode_),
146 static_cast<int>(flags_),
147 static_cast<int>(args_in_registers_),
148 static_cast<int>(args_reversed_),
149 static_operands_type_.ToString());
150 }
151#endif
152
153 // Minor key encoding in 17 bits TTNNNFRAOOOOOOOMM.
154 class ModeBits: public BitField<OverwriteMode, 0, 2> {};
155 class OpBits: public BitField<Token::Value, 2, 7> {};
156 class ArgsInRegistersBits: public BitField<bool, 9, 1> {};
157 class ArgsReversedBits: public BitField<bool, 10, 1> {};
158 class FlagBits: public BitField<GenericBinaryFlags, 11, 1> {};
159 class StaticTypeInfoBits: public BitField<int, 12, 3> {};
Ben Murdochb0fe1622011-05-05 13:52:32 +0100160 class RuntimeTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 15, 3> {};
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100161
162 Major MajorKey() { return GenericBinaryOp; }
163 int MinorKey() {
164 // Encode the parameters in a unique 18 bit value.
165 return OpBits::encode(op_)
166 | ModeBits::encode(mode_)
167 | FlagBits::encode(flags_)
168 | ArgsInRegistersBits::encode(args_in_registers_)
169 | ArgsReversedBits::encode(args_reversed_)
170 | StaticTypeInfoBits::encode(
171 static_operands_type_.ThreeBitRepresentation())
172 | RuntimeTypeInfoBits::encode(runtime_operands_type_);
173 }
174
175 void Generate(MacroAssembler* masm);
176 void GenerateSmiCode(MacroAssembler* masm, Label* slow);
177 void GenerateLoadArguments(MacroAssembler* masm);
178 void GenerateReturn(MacroAssembler* masm);
179 void GenerateRegisterArgsPush(MacroAssembler* masm);
180 void GenerateTypeTransition(MacroAssembler* masm);
181
182 bool IsOperationCommutative() {
183 return (op_ == Token::ADD) || (op_ == Token::MUL);
184 }
185
186 void SetArgsInRegisters() { args_in_registers_ = true; }
187 void SetArgsReversed() { args_reversed_ = true; }
188 bool HasSmiCodeInStub() { return (flags_ & NO_SMI_CODE_IN_STUB) == 0; }
189 bool HasArgsInRegisters() { return args_in_registers_; }
190 bool HasArgsReversed() { return args_reversed_; }
191
192 bool ShouldGenerateSmiCode() {
193 return HasSmiCodeInStub() &&
194 runtime_operands_type_ != BinaryOpIC::HEAP_NUMBERS &&
195 runtime_operands_type_ != BinaryOpIC::STRINGS;
196 }
197
198 bool ShouldGenerateFPCode() {
199 return runtime_operands_type_ != BinaryOpIC::STRINGS;
200 }
201
202 virtual int GetCodeKind() { return Code::BINARY_OP_IC; }
203
204 virtual InlineCacheState GetICState() {
205 return BinaryOpIC::ToState(runtime_operands_type_);
206 }
207
208 friend class CodeGenerator;
Ben Murdochb8e0da22011-05-16 14:20:40 +0100209 friend class LCodeGen;
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100210};
211
Ben Murdoch086aeea2011-05-13 15:57:08 +0100212
213class TypeRecordingBinaryOpStub: public CodeStub {
214 public:
215 TypeRecordingBinaryOpStub(Token::Value op, OverwriteMode mode)
216 : op_(op),
217 mode_(mode),
218 operands_type_(TRBinaryOpIC::UNINITIALIZED),
219 result_type_(TRBinaryOpIC::UNINITIALIZED),
220 name_(NULL) {
221 ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
222 }
223
224 TypeRecordingBinaryOpStub(
225 int key,
226 TRBinaryOpIC::TypeInfo operands_type,
227 TRBinaryOpIC::TypeInfo result_type = TRBinaryOpIC::UNINITIALIZED)
228 : op_(OpBits::decode(key)),
229 mode_(ModeBits::decode(key)),
230 operands_type_(operands_type),
231 result_type_(result_type),
232 name_(NULL) { }
233
234 private:
235 enum SmiCodeGenerateHeapNumberResults {
236 ALLOW_HEAPNUMBER_RESULTS,
237 NO_HEAPNUMBER_RESULTS
238 };
239
240 Token::Value op_;
241 OverwriteMode mode_;
242
243 // Operand type information determined at runtime.
244 TRBinaryOpIC::TypeInfo operands_type_;
245 TRBinaryOpIC::TypeInfo result_type_;
246
247 char* name_;
248
249 const char* GetName();
250
251#ifdef DEBUG
252 void Print() {
253 PrintF("TypeRecordingBinaryOpStub %d (op %s), "
254 "(mode %d, runtime_type_info %s)\n",
255 MinorKey(),
256 Token::String(op_),
257 static_cast<int>(mode_),
258 TRBinaryOpIC::GetName(operands_type_));
259 }
260#endif
261
262 // Minor key encoding in 15 bits RRRTTTOOOOOOOMM.
263 class ModeBits: public BitField<OverwriteMode, 0, 2> {};
264 class OpBits: public BitField<Token::Value, 2, 7> {};
265 class OperandTypeInfoBits: public BitField<TRBinaryOpIC::TypeInfo, 9, 3> {};
266 class ResultTypeInfoBits: public BitField<TRBinaryOpIC::TypeInfo, 12, 3> {};
267
268 Major MajorKey() { return TypeRecordingBinaryOp; }
269 int MinorKey() {
270 return OpBits::encode(op_)
271 | ModeBits::encode(mode_)
272 | OperandTypeInfoBits::encode(operands_type_)
273 | ResultTypeInfoBits::encode(result_type_);
274 }
275
276 void Generate(MacroAssembler* masm);
277 void GenerateGeneric(MacroAssembler* masm);
278 void GenerateSmiCode(MacroAssembler* masm,
279 Label* slow,
280 SmiCodeGenerateHeapNumberResults heapnumber_results);
Steve Block1e0659c2011-05-24 12:43:12 +0100281 void GenerateFloatingPointCode(MacroAssembler* masm,
282 Label* allocation_failure,
283 Label* non_numeric_failure);
284 void GenerateStringAddCode(MacroAssembler* masm);
285 void GenerateCallRuntimeCode(MacroAssembler* masm);
Ben Murdoch086aeea2011-05-13 15:57:08 +0100286 void GenerateLoadArguments(MacroAssembler* masm);
287 void GenerateReturn(MacroAssembler* masm);
288 void GenerateUninitializedStub(MacroAssembler* masm);
289 void GenerateSmiStub(MacroAssembler* masm);
290 void GenerateInt32Stub(MacroAssembler* masm);
291 void GenerateHeapNumberStub(MacroAssembler* masm);
292 void GenerateStringStub(MacroAssembler* masm);
293 void GenerateGenericStub(MacroAssembler* masm);
294
295 void GenerateHeapResultAllocation(MacroAssembler* masm, Label* alloc_failure);
296 void GenerateRegisterArgsPush(MacroAssembler* masm);
297 void GenerateTypeTransition(MacroAssembler* masm);
298 void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm);
299
300 virtual int GetCodeKind() { return Code::TYPE_RECORDING_BINARY_OP_IC; }
301
302 virtual InlineCacheState GetICState() {
303 return TRBinaryOpIC::ToState(operands_type_);
304 }
305
306 virtual void FinishCode(Code* code) {
307 code->set_type_recording_binary_op_type(operands_type_);
308 code->set_type_recording_binary_op_result_type(result_type_);
309 }
310
311 friend class CodeGenerator;
312};
313
314
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100315class StringHelper : public AllStatic {
316 public:
317 // Generate code for copying characters using a simple loop. This should only
318 // be used in places where the number of characters is small and the
319 // additional setup and checking in GenerateCopyCharactersREP adds too much
320 // overhead. Copying of overlapping regions is not supported.
321 static void GenerateCopyCharacters(MacroAssembler* masm,
322 Register dest,
323 Register src,
324 Register count,
325 bool ascii);
326
327 // Generate code for copying characters using the rep movs instruction.
328 // Copies rcx characters from rsi to rdi. Copying of overlapping regions is
329 // not supported.
330 static void GenerateCopyCharactersREP(MacroAssembler* masm,
331 Register dest, // Must be rdi.
332 Register src, // Must be rsi.
333 Register count, // Must be rcx.
334 bool ascii);
335
336
337 // Probe the symbol table for a two character string. If the string is
338 // not found by probing a jump to the label not_found is performed. This jump
339 // does not guarantee that the string is not in the symbol table. If the
340 // string is found the code falls through with the string in register rax.
341 static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
342 Register c1,
343 Register c2,
344 Register scratch1,
345 Register scratch2,
346 Register scratch3,
347 Register scratch4,
348 Label* not_found);
349
350 // Generate string hash.
351 static void GenerateHashInit(MacroAssembler* masm,
352 Register hash,
353 Register character,
354 Register scratch);
355 static void GenerateHashAddCharacter(MacroAssembler* masm,
356 Register hash,
357 Register character,
358 Register scratch);
359 static void GenerateHashGetHash(MacroAssembler* masm,
360 Register hash,
361 Register scratch);
362
363 private:
364 DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
365};
366
367
368// Flag that indicates how to generate code for the stub StringAddStub.
369enum StringAddFlags {
370 NO_STRING_ADD_FLAGS = 0,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100371 // Omit left string check in stub (left is definitely a string).
372 NO_STRING_CHECK_LEFT_IN_STUB = 1 << 0,
373 // Omit right string check in stub (right is definitely a string).
374 NO_STRING_CHECK_RIGHT_IN_STUB = 1 << 1,
375 // Omit both string checks in stub.
376 NO_STRING_CHECK_IN_STUB =
377 NO_STRING_CHECK_LEFT_IN_STUB | NO_STRING_CHECK_RIGHT_IN_STUB
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100378};
379
380
381class StringAddStub: public CodeStub {
382 public:
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100383 explicit StringAddStub(StringAddFlags flags) : flags_(flags) {}
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100384
385 private:
386 Major MajorKey() { return StringAdd; }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100387 int MinorKey() { return flags_; }
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100388
389 void Generate(MacroAssembler* masm);
390
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100391 void GenerateConvertArgument(MacroAssembler* masm,
392 int stack_offset,
393 Register arg,
394 Register scratch1,
395 Register scratch2,
396 Register scratch3,
397 Label* slow);
398
399 const StringAddFlags flags_;
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100400};
401
402
403class SubStringStub: public CodeStub {
404 public:
405 SubStringStub() {}
406
407 private:
408 Major MajorKey() { return SubString; }
409 int MinorKey() { return 0; }
410
411 void Generate(MacroAssembler* masm);
412};
413
414
415class StringCompareStub: public CodeStub {
416 public:
417 explicit StringCompareStub() {}
418
419 // Compare two flat ascii strings and returns result in rax after popping two
420 // arguments from the stack.
421 static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
422 Register left,
423 Register right,
424 Register scratch1,
425 Register scratch2,
426 Register scratch3,
427 Register scratch4);
428
429 private:
430 Major MajorKey() { return StringCompare; }
431 int MinorKey() { return 0; }
432
433 void Generate(MacroAssembler* masm);
434};
435
436
437class NumberToStringStub: public CodeStub {
438 public:
439 NumberToStringStub() { }
440
441 // Generate code to do a lookup in the number string cache. If the number in
442 // the register object is found in the cache the generated code falls through
443 // with the result in the result register. The object and the result register
444 // can be the same. If the number is not found in the cache the code jumps to
445 // the label not_found with only the content of register object unchanged.
446 static void GenerateLookupNumberStringCache(MacroAssembler* masm,
447 Register object,
448 Register result,
449 Register scratch1,
450 Register scratch2,
451 bool object_is_smi,
452 Label* not_found);
453
454 private:
455 static void GenerateConvertHashCodeToIndex(MacroAssembler* masm,
456 Register hash,
457 Register mask);
458
459 Major MajorKey() { return NumberToString; }
460 int MinorKey() { return 0; }
461
462 void Generate(MacroAssembler* masm);
463
464 const char* GetName() { return "NumberToStringStub"; }
465
466#ifdef DEBUG
467 void Print() {
468 PrintF("NumberToStringStub\n");
469 }
470#endif
471};
472
473
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100474// Generate code to load an element from a pixel array. The receiver is assumed
475// to not be a smi and to have elements, the caller must guarantee this
476// precondition. If key is not a smi, then the generated code branches to
477// key_not_smi. Callers can specify NULL for key_not_smi to signal that a smi
478// check has already been performed on key so that the smi check is not
479// generated. If key is not a valid index within the bounds of the pixel array,
480// the generated code jumps to out_of_range. receiver, key and elements are
481// unchanged throughout the generated code sequence.
Steve Block1e0659c2011-05-24 12:43:12 +0100482void GenerateFastPixelArrayLoad(MacroAssembler* masm,
483 Register receiver,
484 Register key,
485 Register elements,
486 Register untagged_key,
487 Register result,
488 Label* not_pixel_array,
489 Label* key_not_smi,
490 Label* out_of_range);
491
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100492// Generate code to store an element into a pixel array, clamping values between
493// [0..255]. The receiver is assumed to not be a smi and to have elements, the
494// caller must guarantee this precondition. If key is not a smi, then the
495// generated code branches to key_not_smi. Callers can specify NULL for
496// key_not_smi to signal that a smi check has already been performed on key so
497// that the smi check is not generated. If the value is not a smi, the
498// generated code will branch to value_not_smi. If the receiver
499// doesn't have pixel array elements, the generated code will branch to
500// not_pixel_array, unless not_pixel_array is NULL, in which case the caller
501// must ensure that the receiver has pixel array elements. If key is not a
502// valid index within the bounds of the pixel array, the generated code jumps to
503// out_of_range.
504void GenerateFastPixelArrayStore(MacroAssembler* masm,
505 Register receiver,
506 Register key,
507 Register value,
508 Register elements,
509 Register scratch1,
510 bool load_elements_from_receiver,
511 bool key_is_untagged,
512 Label* key_not_smi,
513 Label* value_not_smi,
514 Label* not_pixel_array,
515 Label* out_of_range);
Steve Block1e0659c2011-05-24 12:43:12 +0100516
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100517} } // namespace v8::internal
518
519#endif // V8_X64_CODE_STUBS_X64_H_