blob: 7ab0b7c5c9cc32b4ffad3c8bee591055c6ce3538 [file] [log] [blame]
Ben Murdoch086aeea2011-05-13 15:57:08 +01001// Copyright 2011 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +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_CODE_STUBS_H_
29#define V8_CODE_STUBS_H_
30
Ben Murdoch257744e2011-11-30 15:57:28 +000031#include "allocation.h"
Steve Block6ded16b2010-05-10 14:33:55 +010032#include "globals.h"
33
Steve Blocka7e24c12009-10-30 11:49:00 +000034namespace v8 {
35namespace internal {
36
Steve Blockd0582a62009-12-15 09:54:21 +000037// List of code stubs used on all platforms. The order in this list is important
Ben Murdoch086aeea2011-05-13 15:57:08 +010038// as only the stubs up to and including Instanceof allows nested stub calls.
Steve Blockd0582a62009-12-15 09:54:21 +000039#define CODE_STUB_LIST_ALL_PLATFORMS(V) \
40 V(CallFunction) \
Ben Murdoch257744e2011-11-30 15:57:28 +000041 V(UnaryOp) \
42 V(BinaryOp) \
Steve Blockd0582a62009-12-15 09:54:21 +000043 V(StringAdd) \
Leon Clarkee46be812010-01-19 14:06:41 +000044 V(SubString) \
45 V(StringCompare) \
Steve Blockd0582a62009-12-15 09:54:21 +000046 V(SmiOp) \
47 V(Compare) \
Ben Murdochb0fe1622011-05-05 13:52:32 +010048 V(CompareIC) \
49 V(MathPow) \
50 V(TranscendentalCache) \
Ben Murdoch086aeea2011-05-13 15:57:08 +010051 V(Instanceof) \
Steve Blockd0582a62009-12-15 09:54:21 +000052 V(ConvertToDouble) \
53 V(WriteInt32ToHeapNumber) \
54 V(StackCheck) \
Leon Clarkee46be812010-01-19 14:06:41 +000055 V(FastNewClosure) \
56 V(FastNewContext) \
57 V(FastCloneShallowArray) \
Steve Blockd0582a62009-12-15 09:54:21 +000058 V(RevertToNumber) \
59 V(ToBoolean) \
Steve Block1e0659c2011-05-24 12:43:12 +010060 V(ToNumber) \
Steve Blockd0582a62009-12-15 09:54:21 +000061 V(CounterOp) \
62 V(ArgumentsAccess) \
Leon Clarkee46be812010-01-19 14:06:41 +000063 V(RegExpExec) \
Ben Murdochb0fe1622011-05-05 13:52:32 +010064 V(RegExpConstructResult) \
Andrei Popescu402d9372010-02-26 13:31:12 +000065 V(NumberToString) \
Steve Blockd0582a62009-12-15 09:54:21 +000066 V(CEntry) \
Leon Clarke4515c472010-02-03 11:58:03 +000067 V(JSEntry) \
Ben Murdoch257744e2011-11-30 15:57:28 +000068 V(KeyedLoadFastElement) \
69 V(KeyedStoreFastElement) \
70 V(KeyedLoadExternalArray) \
71 V(KeyedStoreExternalArray) \
72 V(DebuggerStatement) \
73 V(StringDictionaryNegativeLookup)
Steve Blockd0582a62009-12-15 09:54:21 +000074
75// List of code stubs only used on ARM platforms.
76#ifdef V8_TARGET_ARCH_ARM
77#define CODE_STUB_LIST_ARM(V) \
78 V(GetProperty) \
79 V(SetProperty) \
80 V(InvokeBuiltin) \
Steve Block1e0659c2011-05-24 12:43:12 +010081 V(RegExpCEntry) \
82 V(DirectCEntry)
Steve Blockd0582a62009-12-15 09:54:21 +000083#else
84#define CODE_STUB_LIST_ARM(V)
85#endif
86
Steve Block44f0eee2011-05-26 01:26:41 +010087// List of code stubs only used on MIPS platforms.
88#ifdef V8_TARGET_ARCH_MIPS
89#define CODE_STUB_LIST_MIPS(V) \
Ben Murdoch257744e2011-11-30 15:57:28 +000090 V(RegExpCEntry) \
91 V(DirectCEntry)
Steve Block44f0eee2011-05-26 01:26:41 +010092#else
93#define CODE_STUB_LIST_MIPS(V)
94#endif
95
Steve Blockd0582a62009-12-15 09:54:21 +000096// Combined list of code stubs.
97#define CODE_STUB_LIST(V) \
98 CODE_STUB_LIST_ALL_PLATFORMS(V) \
Steve Block44f0eee2011-05-26 01:26:41 +010099 CODE_STUB_LIST_ARM(V) \
100 CODE_STUB_LIST_MIPS(V)
Steve Blocka7e24c12009-10-30 11:49:00 +0000101
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100102// Mode to overwrite BinaryExpression values.
103enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
104enum UnaryOverwriteMode { UNARY_OVERWRITE, UNARY_NO_OVERWRITE };
105
106
Steve Blocka7e24c12009-10-30 11:49:00 +0000107// Stub is base classes of all stubs.
108class CodeStub BASE_EMBEDDED {
109 public:
110 enum Major {
Steve Blockd0582a62009-12-15 09:54:21 +0000111#define DEF_ENUM(name) name,
112 CODE_STUB_LIST(DEF_ENUM)
113#undef DEF_ENUM
114 NoCache, // marker for stubs that do custom caching
Steve Blocka7e24c12009-10-30 11:49:00 +0000115 NUMBER_OF_IDS
116 };
117
118 // Retrieve the code for the stub. Generate the code if needed.
119 Handle<Code> GetCode();
120
Leon Clarkee46be812010-01-19 14:06:41 +0000121 // Retrieve the code for the stub if already generated. Do not
122 // generate the code if not already generated and instead return a
123 // retry after GC Failure object.
John Reck59135872010-11-02 12:39:01 -0700124 MUST_USE_RESULT MaybeObject* TryGetCode();
Leon Clarkee46be812010-01-19 14:06:41 +0000125
Steve Blocka7e24c12009-10-30 11:49:00 +0000126 static Major MajorKeyFromKey(uint32_t key) {
127 return static_cast<Major>(MajorKeyBits::decode(key));
Iain Merrick9ac36c92010-09-13 15:29:50 +0100128 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000129 static int MinorKeyFromKey(uint32_t key) {
130 return MinorKeyBits::decode(key);
Iain Merrick9ac36c92010-09-13 15:29:50 +0100131 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100132
133 // Gets the major key from a code object that is a code stub or binary op IC.
134 static Major GetMajorKey(Code* code_stub) {
135 return static_cast<Major>(code_stub->major_key());
136 }
137
Andrei Popescu31002712010-02-23 13:46:05 +0000138 static const char* MajorName(Major major_key, bool allow_unknown_keys);
Steve Blocka7e24c12009-10-30 11:49:00 +0000139
140 virtual ~CodeStub() {}
141
Steve Blocka7e24c12009-10-30 11:49:00 +0000142 protected:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100143 static const int kMajorBits = 6;
Steve Blocka7e24c12009-10-30 11:49:00 +0000144 static const int kMinorBits = kBitsPerInt - kSmiTagSize - kMajorBits;
145
146 private:
Leon Clarkee46be812010-01-19 14:06:41 +0000147 // Lookup the code in the (possibly custom) cache.
148 bool FindCodeInCache(Code** code_out);
149
150 // Nonvirtual wrapper around the stub-specific Generate function. Call
151 // this function to set up the macro assembler and generate the code.
152 void GenerateCode(MacroAssembler* masm);
153
Steve Blocka7e24c12009-10-30 11:49:00 +0000154 // Generates the assembler code for the stub.
155 virtual void Generate(MacroAssembler* masm) = 0;
156
Leon Clarkee46be812010-01-19 14:06:41 +0000157 // Perform bookkeeping required after code generation when stub code is
158 // initially generated.
159 void RecordCodeGeneration(Code* code, MacroAssembler* masm);
160
Ben Murdochb0fe1622011-05-05 13:52:32 +0100161 // Finish the code object after it has been generated.
162 virtual void FinishCode(Code* code) { }
163
Steve Blocka7e24c12009-10-30 11:49:00 +0000164 // Returns information for computing the number key.
165 virtual Major MajorKey() = 0;
166 virtual int MinorKey() = 0;
167
168 // The CallFunctionStub needs to override this so it can encode whether a
169 // lazily generated function should be fully optimized or not.
170 virtual InLoopFlag InLoop() { return NOT_IN_LOOP; }
171
Ben Murdoch257744e2011-11-30 15:57:28 +0000172 // BinaryOpStub needs to override this.
Steve Block6ded16b2010-05-10 14:33:55 +0100173 virtual int GetCodeKind();
174
Ben Murdoch257744e2011-11-30 15:57:28 +0000175 // BinaryOpStub needs to override this.
Steve Block6ded16b2010-05-10 14:33:55 +0100176 virtual InlineCacheState GetICState() {
177 return UNINITIALIZED;
178 }
179
Steve Blocka7e24c12009-10-30 11:49:00 +0000180 // Returns a name for logging/debugging purposes.
Andrei Popescu31002712010-02-23 13:46:05 +0000181 virtual const char* GetName() { return MajorName(MajorKey(), false); }
Steve Blocka7e24c12009-10-30 11:49:00 +0000182
Steve Block44f0eee2011-05-26 01:26:41 +0100183 // Returns whether the code generated for this stub needs to be allocated as
184 // a fixed (non-moveable) code object.
185 virtual bool NeedsImmovableCode() { return false; }
186
187 #ifdef DEBUG
Steve Blocka7e24c12009-10-30 11:49:00 +0000188 virtual void Print() { PrintF("%s\n", GetName()); }
189#endif
190
191 // Computes the key based on major and minor.
192 uint32_t GetKey() {
193 ASSERT(static_cast<int>(MajorKey()) < NUMBER_OF_IDS);
194 return MinorKeyBits::encode(MinorKey()) |
195 MajorKeyBits::encode(MajorKey());
196 }
197
Ben Murdoch086aeea2011-05-13 15:57:08 +0100198 bool AllowsStubCalls() { return MajorKey() <= Instanceof; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000199
200 class MajorKeyBits: public BitField<uint32_t, 0, kMajorBits> {};
201 class MinorKeyBits: public BitField<uint32_t, kMajorBits, kMinorBits> {};
202
203 friend class BreakPointIterator;
204};
205
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100206
207// Helper interface to prepare to/restore after making runtime calls.
208class RuntimeCallHelper {
209 public:
210 virtual ~RuntimeCallHelper() {}
211
212 virtual void BeforeCall(MacroAssembler* masm) const = 0;
213
214 virtual void AfterCall(MacroAssembler* masm) const = 0;
215
216 protected:
217 RuntimeCallHelper() {}
218
219 private:
220 DISALLOW_COPY_AND_ASSIGN(RuntimeCallHelper);
221};
222
223} } // namespace v8::internal
224
225#if V8_TARGET_ARCH_IA32
226#include "ia32/code-stubs-ia32.h"
227#elif V8_TARGET_ARCH_X64
228#include "x64/code-stubs-x64.h"
229#elif V8_TARGET_ARCH_ARM
230#include "arm/code-stubs-arm.h"
231#elif V8_TARGET_ARCH_MIPS
232#include "mips/code-stubs-mips.h"
233#else
234#error Unsupported target architecture.
235#endif
236
237namespace v8 {
238namespace internal {
239
240
Ben Murdochb0fe1622011-05-05 13:52:32 +0100241// RuntimeCallHelper implementation used in stubs: enters/leaves a
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100242// newly created internal frame before/after the runtime call.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100243class StubRuntimeCallHelper : public RuntimeCallHelper {
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100244 public:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100245 StubRuntimeCallHelper() {}
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100246
247 virtual void BeforeCall(MacroAssembler* masm) const;
248
249 virtual void AfterCall(MacroAssembler* masm) const;
250};
251
252
253// Trivial RuntimeCallHelper implementation.
254class NopRuntimeCallHelper : public RuntimeCallHelper {
255 public:
256 NopRuntimeCallHelper() {}
257
258 virtual void BeforeCall(MacroAssembler* masm) const {}
259
260 virtual void AfterCall(MacroAssembler* masm) const {}
261};
262
263
264class StackCheckStub : public CodeStub {
265 public:
266 StackCheckStub() { }
267
268 void Generate(MacroAssembler* masm);
269
270 private:
271
272 const char* GetName() { return "StackCheckStub"; }
273
274 Major MajorKey() { return StackCheck; }
275 int MinorKey() { return 0; }
276};
277
278
Steve Block1e0659c2011-05-24 12:43:12 +0100279class ToNumberStub: public CodeStub {
280 public:
281 ToNumberStub() { }
282
283 void Generate(MacroAssembler* masm);
284
285 private:
286 Major MajorKey() { return ToNumber; }
287 int MinorKey() { return 0; }
288 const char* GetName() { return "ToNumberStub"; }
289};
290
291
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100292class FastNewClosureStub : public CodeStub {
293 public:
Steve Block44f0eee2011-05-26 01:26:41 +0100294 explicit FastNewClosureStub(StrictModeFlag strict_mode)
295 : strict_mode_(strict_mode) { }
296
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100297 void Generate(MacroAssembler* masm);
298
299 private:
300 const char* GetName() { return "FastNewClosureStub"; }
301 Major MajorKey() { return FastNewClosure; }
Steve Block44f0eee2011-05-26 01:26:41 +0100302 int MinorKey() { return strict_mode_; }
303
304 StrictModeFlag strict_mode_;
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100305};
306
307
308class FastNewContextStub : public CodeStub {
309 public:
310 static const int kMaximumSlots = 64;
311
312 explicit FastNewContextStub(int slots) : slots_(slots) {
313 ASSERT(slots_ > 0 && slots <= kMaximumSlots);
314 }
315
316 void Generate(MacroAssembler* masm);
317
318 private:
319 int slots_;
320
321 const char* GetName() { return "FastNewContextStub"; }
322 Major MajorKey() { return FastNewContext; }
323 int MinorKey() { return slots_; }
324};
325
326
327class FastCloneShallowArrayStub : public CodeStub {
328 public:
329 // Maximum length of copied elements array.
330 static const int kMaximumClonedLength = 8;
331
332 enum Mode {
333 CLONE_ELEMENTS,
334 COPY_ON_WRITE_ELEMENTS
335 };
336
337 FastCloneShallowArrayStub(Mode mode, int length)
338 : mode_(mode),
339 length_((mode == COPY_ON_WRITE_ELEMENTS) ? 0 : length) {
340 ASSERT(length_ >= 0);
341 ASSERT(length_ <= kMaximumClonedLength);
342 }
343
344 void Generate(MacroAssembler* masm);
345
346 private:
347 Mode mode_;
348 int length_;
349
350 const char* GetName() { return "FastCloneShallowArrayStub"; }
351 Major MajorKey() { return FastCloneShallowArray; }
352 int MinorKey() {
353 ASSERT(mode_ == 0 || mode_ == 1);
354 return (length_ << 1) | mode_;
355 }
356};
357
358
359class InstanceofStub: public CodeStub {
360 public:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100361 enum Flags {
362 kNoFlags = 0,
Ben Murdoch086aeea2011-05-13 15:57:08 +0100363 kArgsInRegisters = 1 << 0,
364 kCallSiteInlineCheck = 1 << 1,
365 kReturnTrueFalseObject = 1 << 2
Ben Murdochb0fe1622011-05-05 13:52:32 +0100366 };
367
Ben Murdoch086aeea2011-05-13 15:57:08 +0100368 explicit InstanceofStub(Flags flags) : flags_(flags), name_(NULL) { }
369
370 static Register left();
371 static Register right();
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100372
373 void Generate(MacroAssembler* masm);
374
375 private:
376 Major MajorKey() { return Instanceof; }
Ben Murdoch086aeea2011-05-13 15:57:08 +0100377 int MinorKey() { return static_cast<int>(flags_); }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100378
Ben Murdoch086aeea2011-05-13 15:57:08 +0100379 bool HasArgsInRegisters() const {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100380 return (flags_ & kArgsInRegisters) != 0;
381 }
382
Ben Murdoch086aeea2011-05-13 15:57:08 +0100383 bool HasCallSiteInlineCheck() const {
384 return (flags_ & kCallSiteInlineCheck) != 0;
385 }
386
387 bool ReturnTrueFalseObject() const {
388 return (flags_ & kReturnTrueFalseObject) != 0;
389 }
390
391 const char* GetName();
392
Ben Murdochb0fe1622011-05-05 13:52:32 +0100393 Flags flags_;
Ben Murdoch086aeea2011-05-13 15:57:08 +0100394 char* name_;
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100395};
396
397
Ben Murdochb0fe1622011-05-05 13:52:32 +0100398class MathPowStub: public CodeStub {
399 public:
400 MathPowStub() {}
401 virtual void Generate(MacroAssembler* masm);
402
403 private:
404 virtual CodeStub::Major MajorKey() { return MathPow; }
405 virtual int MinorKey() { return 0; }
406
407 const char* GetName() { return "MathPowStub"; }
408};
409
410
Ben Murdochb0fe1622011-05-05 13:52:32 +0100411class ICCompareStub: public CodeStub {
412 public:
413 ICCompareStub(Token::Value op, CompareIC::State state)
414 : op_(op), state_(state) {
415 ASSERT(Token::IsCompareOp(op));
416 }
417
418 virtual void Generate(MacroAssembler* masm);
419
420 private:
421 class OpField: public BitField<int, 0, 3> { };
422 class StateField: public BitField<int, 3, 5> { };
423
424 virtual void FinishCode(Code* code) { code->set_compare_state(state_); }
425
426 virtual CodeStub::Major MajorKey() { return CompareIC; }
427 virtual int MinorKey();
428
429 virtual int GetCodeKind() { return Code::COMPARE_IC; }
430
431 void GenerateSmis(MacroAssembler* masm);
432 void GenerateHeapNumbers(MacroAssembler* masm);
Ben Murdoch257744e2011-11-30 15:57:28 +0000433 void GenerateSymbols(MacroAssembler* masm);
434 void GenerateStrings(MacroAssembler* masm);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100435 void GenerateObjects(MacroAssembler* masm);
436 void GenerateMiss(MacroAssembler* masm);
437
438 bool strict() const { return op_ == Token::EQ_STRICT; }
439 Condition GetCondition() const { return CompareIC::ComputeCondition(op_); }
440
441 Token::Value op_;
442 CompareIC::State state_;
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100443};
444
445
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100446// Flags that control the compare stub code generation.
447enum CompareFlags {
448 NO_COMPARE_FLAGS = 0,
449 NO_SMI_COMPARE_IN_STUB = 1 << 0,
450 NO_NUMBER_COMPARE_IN_STUB = 1 << 1,
451 CANT_BOTH_BE_NAN = 1 << 2
452};
453
454
Ben Murdochb0fe1622011-05-05 13:52:32 +0100455enum NaNInformation {
456 kBothCouldBeNaN,
457 kCantBothBeNaN
458};
459
460
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100461class CompareStub: public CodeStub {
462 public:
463 CompareStub(Condition cc,
464 bool strict,
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100465 CompareFlags flags,
466 Register lhs,
467 Register rhs) :
Ben Murdochb0fe1622011-05-05 13:52:32 +0100468 cc_(cc),
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100469 strict_(strict),
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100470 never_nan_nan_((flags & CANT_BOTH_BE_NAN) != 0),
471 include_number_compare_((flags & NO_NUMBER_COMPARE_IN_STUB) == 0),
472 include_smi_compare_((flags & NO_SMI_COMPARE_IN_STUB) == 0),
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100473 lhs_(lhs),
474 rhs_(rhs),
475 name_(NULL) { }
476
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100477 CompareStub(Condition cc,
478 bool strict,
479 CompareFlags flags) :
480 cc_(cc),
481 strict_(strict),
482 never_nan_nan_((flags & CANT_BOTH_BE_NAN) != 0),
483 include_number_compare_((flags & NO_NUMBER_COMPARE_IN_STUB) == 0),
484 include_smi_compare_((flags & NO_SMI_COMPARE_IN_STUB) == 0),
485 lhs_(no_reg),
486 rhs_(no_reg),
487 name_(NULL) { }
488
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100489 void Generate(MacroAssembler* masm);
490
491 private:
492 Condition cc_;
493 bool strict_;
494 // Only used for 'equal' comparisons. Tells the stub that we already know
495 // that at least one side of the comparison is not NaN. This allows the
496 // stub to use object identity in the positive case. We ignore it when
497 // generating the minor key for other comparisons to avoid creating more
498 // stubs.
499 bool never_nan_nan_;
500 // Do generate the number comparison code in the stub. Stubs without number
501 // comparison code is used when the number comparison has been inlined, and
502 // the stub will be called if one of the operands is not a number.
503 bool include_number_compare_;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100504
505 // Generate the comparison code for two smi operands in the stub.
506 bool include_smi_compare_;
507
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100508 // Register holding the left hand side of the comparison if the stub gives
509 // a choice, no_reg otherwise.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100510
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100511 Register lhs_;
512 // Register holding the right hand side of the comparison if the stub gives
513 // a choice, no_reg otherwise.
514 Register rhs_;
515
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100516 // Encoding of the minor key in 16 bits.
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100517 class StrictField: public BitField<bool, 0, 1> {};
518 class NeverNanNanField: public BitField<bool, 1, 1> {};
519 class IncludeNumberCompareField: public BitField<bool, 2, 1> {};
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100520 class IncludeSmiCompareField: public BitField<bool, 3, 1> {};
521 class RegisterField: public BitField<bool, 4, 1> {};
522 class ConditionField: public BitField<int, 5, 11> {};
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100523
524 Major MajorKey() { return Compare; }
525
526 int MinorKey();
527
Ben Murdochb0fe1622011-05-05 13:52:32 +0100528 virtual int GetCodeKind() { return Code::COMPARE_IC; }
529 virtual void FinishCode(Code* code) {
530 code->set_compare_state(CompareIC::GENERIC);
531 }
532
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100533 // Branch to the label if the given object isn't a symbol.
534 void BranchIfNonSymbol(MacroAssembler* masm,
535 Label* label,
536 Register object,
537 Register scratch);
538
539 // Unfortunately you have to run without snapshots to see most of these
540 // names in the profile since most compare stubs end up in the snapshot.
541 char* name_;
542 const char* GetName();
543#ifdef DEBUG
544 void Print() {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100545 PrintF("CompareStub (minor %d) (cc %d), (strict %s), "
546 "(never_nan_nan %s), (smi_compare %s) (number_compare %s) ",
547 MinorKey(),
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100548 static_cast<int>(cc_),
549 strict_ ? "true" : "false",
550 never_nan_nan_ ? "true" : "false",
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100551 include_smi_compare_ ? "inluded" : "not included",
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100552 include_number_compare_ ? "included" : "not included");
553
554 if (!lhs_.is(no_reg) && !rhs_.is(no_reg)) {
555 PrintF("(lhs r%d), (rhs r%d)\n", lhs_.code(), rhs_.code());
556 } else {
557 PrintF("\n");
558 }
559 }
560#endif
561};
562
563
564class CEntryStub : public CodeStub {
565 public:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100566 explicit CEntryStub(int result_size)
567 : result_size_(result_size), save_doubles_(false) { }
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100568
569 void Generate(MacroAssembler* masm);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100570 void SaveDoubles() { save_doubles_ = true; }
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100571
572 private:
573 void GenerateCore(MacroAssembler* masm,
574 Label* throw_normal_exception,
575 Label* throw_termination_exception,
576 Label* throw_out_of_memory_exception,
577 bool do_gc,
Steve Block1e0659c2011-05-24 12:43:12 +0100578 bool always_allocate_scope);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100579 void GenerateThrowTOS(MacroAssembler* masm);
580 void GenerateThrowUncatchable(MacroAssembler* masm,
581 UncatchableExceptionType type);
582
583 // Number of pointers/values returned.
584 const int result_size_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100585 bool save_doubles_;
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100586
587 Major MajorKey() { return CEntry; }
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100588 int MinorKey();
589
Steve Block44f0eee2011-05-26 01:26:41 +0100590 bool NeedsImmovableCode();
591
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100592 const char* GetName() { return "CEntryStub"; }
593};
594
595
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100596class JSEntryStub : public CodeStub {
597 public:
598 JSEntryStub() { }
599
600 void Generate(MacroAssembler* masm) { GenerateBody(masm, false); }
601
602 protected:
603 void GenerateBody(MacroAssembler* masm, bool is_construct);
604
605 private:
606 Major MajorKey() { return JSEntry; }
607 int MinorKey() { return 0; }
608
609 const char* GetName() { return "JSEntryStub"; }
610};
611
612
613class JSConstructEntryStub : public JSEntryStub {
614 public:
615 JSConstructEntryStub() { }
616
617 void Generate(MacroAssembler* masm) { GenerateBody(masm, true); }
618
619 private:
620 int MinorKey() { return 1; }
621
622 const char* GetName() { return "JSConstructEntryStub"; }
623};
624
625
626class ArgumentsAccessStub: public CodeStub {
627 public:
628 enum Type {
629 READ_ELEMENT,
Steve Block44f0eee2011-05-26 01:26:41 +0100630 NEW_NON_STRICT,
631 NEW_STRICT
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100632 };
633
634 explicit ArgumentsAccessStub(Type type) : type_(type) { }
635
636 private:
637 Type type_;
638
639 Major MajorKey() { return ArgumentsAccess; }
640 int MinorKey() { return type_; }
641
642 void Generate(MacroAssembler* masm);
643 void GenerateReadElement(MacroAssembler* masm);
644 void GenerateNewObject(MacroAssembler* masm);
645
Steve Block44f0eee2011-05-26 01:26:41 +0100646 int GetArgumentsBoilerplateIndex() const {
647 return (type_ == NEW_STRICT)
648 ? Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX
649 : Context::ARGUMENTS_BOILERPLATE_INDEX;
650 }
651
652 int GetArgumentsObjectSize() const {
653 if (type_ == NEW_STRICT)
654 return Heap::kArgumentsObjectSizeStrict;
655 else
656 return Heap::kArgumentsObjectSize;
657 }
658
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100659 const char* GetName() { return "ArgumentsAccessStub"; }
660
661#ifdef DEBUG
662 void Print() {
663 PrintF("ArgumentsAccessStub (type %d)\n", type_);
664 }
665#endif
666};
667
668
669class RegExpExecStub: public CodeStub {
670 public:
671 RegExpExecStub() { }
672
673 private:
674 Major MajorKey() { return RegExpExec; }
675 int MinorKey() { return 0; }
676
677 void Generate(MacroAssembler* masm);
678
679 const char* GetName() { return "RegExpExecStub"; }
680
681#ifdef DEBUG
682 void Print() {
683 PrintF("RegExpExecStub\n");
684 }
685#endif
686};
687
688
Ben Murdochb0fe1622011-05-05 13:52:32 +0100689class RegExpConstructResultStub: public CodeStub {
690 public:
691 RegExpConstructResultStub() { }
692
693 private:
694 Major MajorKey() { return RegExpConstructResult; }
695 int MinorKey() { return 0; }
696
697 void Generate(MacroAssembler* masm);
698
699 const char* GetName() { return "RegExpConstructResultStub"; }
700
701#ifdef DEBUG
702 void Print() {
703 PrintF("RegExpConstructResultStub\n");
704 }
705#endif
706};
707
708
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100709class CallFunctionStub: public CodeStub {
710 public:
711 CallFunctionStub(int argc, InLoopFlag in_loop, CallFunctionFlags flags)
712 : argc_(argc), in_loop_(in_loop), flags_(flags) { }
713
714 void Generate(MacroAssembler* masm);
715
Ben Murdoch086aeea2011-05-13 15:57:08 +0100716 static int ExtractArgcFromMinorKey(int minor_key) {
717 return ArgcBits::decode(minor_key);
718 }
719
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100720 private:
721 int argc_;
722 InLoopFlag in_loop_;
723 CallFunctionFlags flags_;
724
725#ifdef DEBUG
726 void Print() {
727 PrintF("CallFunctionStub (args %d, in_loop %d, flags %d)\n",
728 argc_,
729 static_cast<int>(in_loop_),
730 static_cast<int>(flags_));
731 }
732#endif
733
734 // Minor key encoding in 32 bits with Bitfield <Type, shift, size>.
735 class InLoopBits: public BitField<InLoopFlag, 0, 1> {};
736 class FlagBits: public BitField<CallFunctionFlags, 1, 1> {};
737 class ArgcBits: public BitField<int, 2, 32 - 2> {};
738
739 Major MajorKey() { return CallFunction; }
740 int MinorKey() {
741 // Encode the parameters in a unique 32 bit value.
742 return InLoopBits::encode(in_loop_)
743 | FlagBits::encode(flags_)
744 | ArgcBits::encode(argc_);
745 }
746
747 InLoopFlag InLoop() { return in_loop_; }
Ben Murdoch257744e2011-11-30 15:57:28 +0000748
749 bool ReceiverMightBeImplicit() {
750 return (flags_ & RECEIVER_MIGHT_BE_IMPLICIT) != 0;
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100751 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100752};
753
754
755enum StringIndexFlags {
756 // Accepts smis or heap numbers.
757 STRING_INDEX_IS_NUMBER,
758
759 // Accepts smis or heap numbers that are valid array indices
760 // (ECMA-262 15.4). Invalid indices are reported as being out of
761 // range.
762 STRING_INDEX_IS_ARRAY_INDEX
763};
764
765
766// Generates code implementing String.prototype.charCodeAt.
767//
768// Only supports the case when the receiver is a string and the index
769// is a number (smi or heap number) that is a valid index into the
770// string. Additional index constraints are specified by the
771// flags. Otherwise, bails out to the provided labels.
772//
773// Register usage: |object| may be changed to another string in a way
774// that doesn't affect charCodeAt/charAt semantics, |index| is
775// preserved, |scratch| and |result| are clobbered.
776class StringCharCodeAtGenerator {
777 public:
778 StringCharCodeAtGenerator(Register object,
779 Register index,
780 Register scratch,
781 Register result,
782 Label* receiver_not_string,
783 Label* index_not_number,
784 Label* index_out_of_range,
785 StringIndexFlags index_flags)
786 : object_(object),
787 index_(index),
788 scratch_(scratch),
789 result_(result),
790 receiver_not_string_(receiver_not_string),
791 index_not_number_(index_not_number),
792 index_out_of_range_(index_out_of_range),
793 index_flags_(index_flags) {
794 ASSERT(!scratch_.is(object_));
795 ASSERT(!scratch_.is(index_));
796 ASSERT(!scratch_.is(result_));
797 ASSERT(!result_.is(object_));
798 ASSERT(!result_.is(index_));
799 }
800
801 // Generates the fast case code. On the fallthrough path |result|
802 // register contains the result.
803 void GenerateFast(MacroAssembler* masm);
804
805 // Generates the slow case code. Must not be naturally
806 // reachable. Expected to be put after a ret instruction (e.g., in
807 // deferred code). Always jumps back to the fast case.
808 void GenerateSlow(MacroAssembler* masm,
809 const RuntimeCallHelper& call_helper);
810
811 private:
812 Register object_;
813 Register index_;
814 Register scratch_;
815 Register result_;
816
817 Label* receiver_not_string_;
818 Label* index_not_number_;
819 Label* index_out_of_range_;
820
821 StringIndexFlags index_flags_;
822
823 Label call_runtime_;
824 Label index_not_smi_;
825 Label got_smi_index_;
826 Label exit_;
827
828 DISALLOW_COPY_AND_ASSIGN(StringCharCodeAtGenerator);
829};
830
831
832// Generates code for creating a one-char string from a char code.
833class StringCharFromCodeGenerator {
834 public:
835 StringCharFromCodeGenerator(Register code,
836 Register result)
837 : code_(code),
838 result_(result) {
839 ASSERT(!code_.is(result_));
840 }
841
842 // Generates the fast case code. On the fallthrough path |result|
843 // register contains the result.
844 void GenerateFast(MacroAssembler* masm);
845
846 // Generates the slow case code. Must not be naturally
847 // reachable. Expected to be put after a ret instruction (e.g., in
848 // deferred code). Always jumps back to the fast case.
849 void GenerateSlow(MacroAssembler* masm,
850 const RuntimeCallHelper& call_helper);
851
852 private:
853 Register code_;
854 Register result_;
855
856 Label slow_case_;
857 Label exit_;
858
859 DISALLOW_COPY_AND_ASSIGN(StringCharFromCodeGenerator);
860};
861
862
863// Generates code implementing String.prototype.charAt.
864//
865// Only supports the case when the receiver is a string and the index
866// is a number (smi or heap number) that is a valid index into the
867// string. Additional index constraints are specified by the
868// flags. Otherwise, bails out to the provided labels.
869//
870// Register usage: |object| may be changed to another string in a way
871// that doesn't affect charCodeAt/charAt semantics, |index| is
872// preserved, |scratch1|, |scratch2|, and |result| are clobbered.
873class StringCharAtGenerator {
874 public:
875 StringCharAtGenerator(Register object,
876 Register index,
877 Register scratch1,
878 Register scratch2,
879 Register result,
880 Label* receiver_not_string,
881 Label* index_not_number,
882 Label* index_out_of_range,
883 StringIndexFlags index_flags)
884 : char_code_at_generator_(object,
885 index,
886 scratch1,
887 scratch2,
888 receiver_not_string,
889 index_not_number,
890 index_out_of_range,
891 index_flags),
892 char_from_code_generator_(scratch2, result) {}
893
894 // Generates the fast case code. On the fallthrough path |result|
895 // register contains the result.
896 void GenerateFast(MacroAssembler* masm);
897
898 // Generates the slow case code. Must not be naturally
899 // reachable. Expected to be put after a ret instruction (e.g., in
900 // deferred code). Always jumps back to the fast case.
901 void GenerateSlow(MacroAssembler* masm,
902 const RuntimeCallHelper& call_helper);
903
904 private:
905 StringCharCodeAtGenerator char_code_at_generator_;
906 StringCharFromCodeGenerator char_from_code_generator_;
907
908 DISALLOW_COPY_AND_ASSIGN(StringCharAtGenerator);
909};
910
Ben Murdoch086aeea2011-05-13 15:57:08 +0100911
912class AllowStubCallsScope {
913 public:
914 AllowStubCallsScope(MacroAssembler* masm, bool allow)
915 : masm_(masm), previous_allow_(masm->allow_stub_calls()) {
916 masm_->set_allow_stub_calls(allow);
917 }
918 ~AllowStubCallsScope() {
919 masm_->set_allow_stub_calls(previous_allow_);
920 }
921
922 private:
923 MacroAssembler* masm_;
924 bool previous_allow_;
925
926 DISALLOW_COPY_AND_ASSIGN(AllowStubCallsScope);
927};
928
Ben Murdoch257744e2011-11-30 15:57:28 +0000929#ifdef DEBUG
930#define DECLARE_ARRAY_STUB_PRINT(name) void Print() { PrintF(#name); }
931#else
932#define DECLARE_ARRAY_STUB_PRINT(name)
933#endif
934
935
936class KeyedLoadFastElementStub : public CodeStub {
937 public:
938 explicit KeyedLoadFastElementStub() {
939 }
940
941 Major MajorKey() { return KeyedLoadFastElement; }
942 int MinorKey() { return 0; }
943
944 void Generate(MacroAssembler* masm);
945
946 const char* GetName() { return "KeyedLoadFastElementStub"; }
947
948 DECLARE_ARRAY_STUB_PRINT(KeyedLoadFastElementStub)
949};
950
951
952class KeyedStoreFastElementStub : public CodeStub {
953 public:
954 explicit KeyedStoreFastElementStub(bool is_js_array)
955 : is_js_array_(is_js_array) { }
956
957 Major MajorKey() { return KeyedStoreFastElement; }
958 int MinorKey() { return is_js_array_ ? 1 : 0; }
959
960 void Generate(MacroAssembler* masm);
961
962 const char* GetName() { return "KeyedStoreFastElementStub"; }
963
964 DECLARE_ARRAY_STUB_PRINT(KeyedStoreFastElementStub)
965
966 private:
967 bool is_js_array_;
968};
969
970
971class KeyedLoadExternalArrayStub : public CodeStub {
972 public:
973 explicit KeyedLoadExternalArrayStub(ExternalArrayType array_type)
974 : array_type_(array_type) { }
975
976 Major MajorKey() { return KeyedLoadExternalArray; }
977 int MinorKey() { return array_type_; }
978
979 void Generate(MacroAssembler* masm);
980
981 const char* GetName() { return "KeyedLoadExternalArrayStub"; }
982
983 DECLARE_ARRAY_STUB_PRINT(KeyedLoadExternalArrayStub)
984
985 protected:
986 ExternalArrayType array_type_;
987};
988
989
990class KeyedStoreExternalArrayStub : public CodeStub {
991 public:
992 explicit KeyedStoreExternalArrayStub(ExternalArrayType array_type)
993 : array_type_(array_type) { }
994
995 Major MajorKey() { return KeyedStoreExternalArray; }
996 int MinorKey() { return array_type_; }
997
998 void Generate(MacroAssembler* masm);
999
1000 const char* GetName() { return "KeyedStoreExternalArrayStub"; }
1001
1002 DECLARE_ARRAY_STUB_PRINT(KeyedStoreExternalArrayStub)
1003
1004 protected:
1005 ExternalArrayType array_type_;
1006};
1007
1008
Steve Blocka7e24c12009-10-30 11:49:00 +00001009} } // namespace v8::internal
1010
1011#endif // V8_CODE_STUBS_H_