blob: 6a7b6616df26be410f667c59aa04ab0a2da75b97 [file] [log] [blame]
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001// Copyright 2011 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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
lrn@chromium.org1c092762011-05-09 09:42:16 +000031#include "allocation.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000032#include "globals.h"
33
kasperl@chromium.org71affb52009-05-26 05:44:31 +000034namespace v8 {
35namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000036
ricow@chromium.orgc54d3652011-05-30 09:20:16 +000037// List of code stubs used on all platforms.
ager@chromium.orgc4c92722009-11-18 14:12:51 +000038#define CODE_STUB_LIST_ALL_PLATFORMS(V) \
39 V(CallFunction) \
danno@chromium.org40cb8782011-05-25 07:58:50 +000040 V(UnaryOp) \
41 V(BinaryOp) \
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000042 V(StringAdd) \
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000043 V(SubString) \
44 V(StringCompare) \
ager@chromium.orgc4c92722009-11-18 14:12:51 +000045 V(Compare) \
kasperl@chromium.orga5551262010-12-07 12:49:48 +000046 V(CompareIC) \
47 V(MathPow) \
whesse@chromium.org871db8c2010-12-21 15:17:57 +000048 V(TranscendentalCache) \
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000049 V(Instanceof) \
ricow@chromium.orgc54d3652011-05-30 09:20:16 +000050 /* All stubs above this line only exist in a few versions, which are */ \
51 /* generated ahead of time. Therefore compiling a call to one of */ \
52 /* them can't cause a new stub to be compiled, so compiling a call to */ \
53 /* them is GC safe. The ones below this line exist in many variants */ \
54 /* so code compiling a call to one can cause a GC. This means they */ \
55 /* can't be called from other stubs, since stub generation code is */ \
56 /* not GC safe. */ \
ager@chromium.orgc4c92722009-11-18 14:12:51 +000057 V(ConvertToDouble) \
58 V(WriteInt32ToHeapNumber) \
59 V(StackCheck) \
sgjesse@chromium.org846fb742009-12-18 08:56:33 +000060 V(FastNewClosure) \
61 V(FastNewContext) \
62 V(FastCloneShallowArray) \
ager@chromium.orgc4c92722009-11-18 14:12:51 +000063 V(RevertToNumber) \
64 V(ToBoolean) \
whesse@chromium.org7a392b32011-01-31 11:30:36 +000065 V(ToNumber) \
ager@chromium.orgc4c92722009-11-18 14:12:51 +000066 V(CounterOp) \
67 V(ArgumentsAccess) \
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000068 V(RegExpExec) \
kasperl@chromium.orga5551262010-12-07 12:49:48 +000069 V(RegExpConstructResult) \
ager@chromium.org5c838252010-02-19 08:53:10 +000070 V(NumberToString) \
ager@chromium.orgc4c92722009-11-18 14:12:51 +000071 V(CEntry) \
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000072 V(JSEntry) \
ager@chromium.orgea91cc52011-05-23 06:06:11 +000073 V(KeyedLoadFastElement) \
74 V(KeyedStoreFastElement) \
75 V(KeyedLoadExternalArray) \
76 V(KeyedStoreExternalArray) \
lrn@chromium.org1c092762011-05-09 09:42:16 +000077 V(DebuggerStatement) \
78 V(StringDictionaryNegativeLookup)
ager@chromium.org3811b432009-10-28 14:53:37 +000079
80// List of code stubs only used on ARM platforms.
81#ifdef V8_TARGET_ARCH_ARM
82#define CODE_STUB_LIST_ARM(V) \
83 V(GetProperty) \
84 V(SetProperty) \
85 V(InvokeBuiltin) \
ricow@chromium.org83aa5492011-02-07 12:42:56 +000086 V(RegExpCEntry) \
87 V(DirectCEntry)
ager@chromium.org3811b432009-10-28 14:53:37 +000088#else
89#define CODE_STUB_LIST_ARM(V)
90#endif
91
lrn@chromium.org7516f052011-03-30 08:52:27 +000092// List of code stubs only used on MIPS platforms.
93#ifdef V8_TARGET_ARCH_MIPS
94#define CODE_STUB_LIST_MIPS(V) \
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000095 V(RegExpCEntry) \
96 V(DirectCEntry)
lrn@chromium.org7516f052011-03-30 08:52:27 +000097#else
98#define CODE_STUB_LIST_MIPS(V)
99#endif
100
ager@chromium.org3811b432009-10-28 14:53:37 +0000101// Combined list of code stubs.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000102#define CODE_STUB_LIST(V) \
103 CODE_STUB_LIST_ALL_PLATFORMS(V) \
lrn@chromium.org7516f052011-03-30 08:52:27 +0000104 CODE_STUB_LIST_ARM(V) \
105 CODE_STUB_LIST_MIPS(V)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000106
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000107// Mode to overwrite BinaryExpression values.
108enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
109enum UnaryOverwriteMode { UNARY_OVERWRITE, UNARY_NO_OVERWRITE };
110
111
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000112// Stub is base classes of all stubs.
113class CodeStub BASE_EMBEDDED {
114 public:
115 enum Major {
ager@chromium.org3811b432009-10-28 14:53:37 +0000116#define DEF_ENUM(name) name,
117 CODE_STUB_LIST(DEF_ENUM)
118#undef DEF_ENUM
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000119 NoCache, // marker for stubs that do custom caching
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000120 NUMBER_OF_IDS
121 };
122
123 // Retrieve the code for the stub. Generate the code if needed.
124 Handle<Code> GetCode();
125
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000126 // Retrieve the code for the stub if already generated. Do not
127 // generate the code if not already generated and instead return a
128 // retry after GC Failure object.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000129 MUST_USE_RESULT MaybeObject* TryGetCode();
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000130
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000131 static Major MajorKeyFromKey(uint32_t key) {
132 return static_cast<Major>(MajorKeyBits::decode(key));
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000133 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000134 static int MinorKeyFromKey(uint32_t key) {
135 return MinorKeyBits::decode(key);
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000136 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000137
138 // Gets the major key from a code object that is a code stub or binary op IC.
139 static Major GetMajorKey(Code* code_stub) {
140 return static_cast<Major>(code_stub->major_key());
141 }
142
ager@chromium.org5c838252010-02-19 08:53:10 +0000143 static const char* MajorName(Major major_key, bool allow_unknown_keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000144
145 virtual ~CodeStub() {}
146
mads.s.ager31e71382008-08-13 09:32:07 +0000147 protected:
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000148 static const int kMajorBits = 6;
ager@chromium.org9085a012009-05-11 19:22:57 +0000149 static const int kMinorBits = kBitsPerInt - kSmiTagSize - kMajorBits;
mads.s.ager31e71382008-08-13 09:32:07 +0000150
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000151 private:
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000152 // Lookup the code in the (possibly custom) cache.
153 bool FindCodeInCache(Code** code_out);
154
155 // Nonvirtual wrapper around the stub-specific Generate function. Call
156 // this function to set up the macro assembler and generate the code.
157 void GenerateCode(MacroAssembler* masm);
158
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000159 // Generates the assembler code for the stub.
160 virtual void Generate(MacroAssembler* masm) = 0;
161
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000162 // Perform bookkeeping required after code generation when stub code is
163 // initially generated.
164 void RecordCodeGeneration(Code* code, MacroAssembler* masm);
165
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000166 // Finish the code object after it has been generated.
167 virtual void FinishCode(Code* code) { }
168
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000169 // Returns information for computing the number key.
170 virtual Major MajorKey() = 0;
171 virtual int MinorKey() = 0;
172
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000173 // The CallFunctionStub needs to override this so it can encode whether a
174 // lazily generated function should be fully optimized or not.
175 virtual InLoopFlag InLoop() { return NOT_IN_LOOP; }
176
danno@chromium.org40cb8782011-05-25 07:58:50 +0000177 // BinaryOpStub needs to override this.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000178 virtual int GetCodeKind();
179
danno@chromium.org40cb8782011-05-25 07:58:50 +0000180 // BinaryOpStub needs to override this.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000181 virtual InlineCacheState GetICState() {
182 return UNINITIALIZED;
183 }
184
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000185 // Returns a name for logging/debugging purposes.
ager@chromium.org5c838252010-02-19 08:53:10 +0000186 virtual const char* GetName() { return MajorName(MajorKey(), false); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000187
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000188 // Returns whether the code generated for this stub needs to be allocated as
189 // a fixed (non-moveable) code object.
190 virtual bool NeedsImmovableCode() { return false; }
191
192 #ifdef DEBUG
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000193 virtual void Print() { PrintF("%s\n", GetName()); }
194#endif
195
196 // Computes the key based on major and minor.
197 uint32_t GetKey() {
198 ASSERT(static_cast<int>(MajorKey()) < NUMBER_OF_IDS);
199 return MinorKeyBits::encode(MinorKey()) |
200 MajorKeyBits::encode(MajorKey());
201 }
202
ricow@chromium.orgc54d3652011-05-30 09:20:16 +0000203 // See comment above, where Instanceof is defined.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000204 bool AllowsStubCalls() { return MajorKey() <= Instanceof; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000205
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000206 class MajorKeyBits: public BitField<uint32_t, 0, kMajorBits> {};
207 class MinorKeyBits: public BitField<uint32_t, kMajorBits, kMinorBits> {};
208
209 friend class BreakPointIterator;
210};
211
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000212
213// Helper interface to prepare to/restore after making runtime calls.
214class RuntimeCallHelper {
215 public:
216 virtual ~RuntimeCallHelper() {}
217
218 virtual void BeforeCall(MacroAssembler* masm) const = 0;
219
220 virtual void AfterCall(MacroAssembler* masm) const = 0;
221
222 protected:
223 RuntimeCallHelper() {}
224
225 private:
226 DISALLOW_COPY_AND_ASSIGN(RuntimeCallHelper);
227};
228
229} } // namespace v8::internal
230
231#if V8_TARGET_ARCH_IA32
232#include "ia32/code-stubs-ia32.h"
233#elif V8_TARGET_ARCH_X64
234#include "x64/code-stubs-x64.h"
235#elif V8_TARGET_ARCH_ARM
236#include "arm/code-stubs-arm.h"
237#elif V8_TARGET_ARCH_MIPS
238#include "mips/code-stubs-mips.h"
239#else
240#error Unsupported target architecture.
241#endif
242
243namespace v8 {
244namespace internal {
245
246
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000247// RuntimeCallHelper implementation used in stubs: enters/leaves a
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000248// newly created internal frame before/after the runtime call.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000249class StubRuntimeCallHelper : public RuntimeCallHelper {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000250 public:
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000251 StubRuntimeCallHelper() {}
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000252
253 virtual void BeforeCall(MacroAssembler* masm) const;
254
255 virtual void AfterCall(MacroAssembler* masm) const;
256};
257
258
259// Trivial RuntimeCallHelper implementation.
260class NopRuntimeCallHelper : public RuntimeCallHelper {
261 public:
262 NopRuntimeCallHelper() {}
263
264 virtual void BeforeCall(MacroAssembler* masm) const {}
265
266 virtual void AfterCall(MacroAssembler* masm) const {}
267};
268
269
270class StackCheckStub : public CodeStub {
271 public:
272 StackCheckStub() { }
273
274 void Generate(MacroAssembler* masm);
275
276 private:
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000277 const char* GetName() { return "StackCheckStub"; }
278
279 Major MajorKey() { return StackCheck; }
280 int MinorKey() { return 0; }
281};
282
283
whesse@chromium.org7a392b32011-01-31 11:30:36 +0000284class ToNumberStub: public CodeStub {
285 public:
286 ToNumberStub() { }
287
288 void Generate(MacroAssembler* masm);
289
290 private:
291 Major MajorKey() { return ToNumber; }
292 int MinorKey() { return 0; }
293 const char* GetName() { return "ToNumberStub"; }
294};
295
296
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000297class FastNewClosureStub : public CodeStub {
298 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000299 explicit FastNewClosureStub(StrictModeFlag strict_mode)
300 : strict_mode_(strict_mode) { }
301
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000302 void Generate(MacroAssembler* masm);
303
304 private:
305 const char* GetName() { return "FastNewClosureStub"; }
306 Major MajorKey() { return FastNewClosure; }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000307 int MinorKey() { return strict_mode_; }
308
309 StrictModeFlag strict_mode_;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000310};
311
312
313class FastNewContextStub : public CodeStub {
314 public:
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000315 static const int kMaximumSlots = 64;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000316
317 explicit FastNewContextStub(int slots) : slots_(slots) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000318 ASSERT(slots_ > 0 && slots <= kMaximumSlots);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000319 }
320
321 void Generate(MacroAssembler* masm);
322
323 private:
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000324 int slots_;
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000325
326 const char* GetName() { return "FastNewContextStub"; }
327 Major MajorKey() { return FastNewContext; }
328 int MinorKey() { return slots_; }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000329};
330
331
332class FastCloneShallowArrayStub : public CodeStub {
333 public:
334 // Maximum length of copied elements array.
335 static const int kMaximumClonedLength = 8;
336
337 enum Mode {
338 CLONE_ELEMENTS,
339 COPY_ON_WRITE_ELEMENTS
340 };
341
342 FastCloneShallowArrayStub(Mode mode, int length)
343 : mode_(mode),
344 length_((mode == COPY_ON_WRITE_ELEMENTS) ? 0 : length) {
345 ASSERT(length_ >= 0);
346 ASSERT(length_ <= kMaximumClonedLength);
347 }
348
349 void Generate(MacroAssembler* masm);
350
351 private:
352 Mode mode_;
353 int length_;
354
355 const char* GetName() { return "FastCloneShallowArrayStub"; }
356 Major MajorKey() { return FastCloneShallowArray; }
357 int MinorKey() {
358 ASSERT(mode_ == 0 || mode_ == 1);
359 return (length_ << 1) | mode_;
360 }
361};
362
363
364class InstanceofStub: public CodeStub {
365 public:
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000366 enum Flags {
367 kNoFlags = 0,
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000368 kArgsInRegisters = 1 << 0,
369 kCallSiteInlineCheck = 1 << 1,
370 kReturnTrueFalseObject = 1 << 2
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000371 };
372
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000373 explicit InstanceofStub(Flags flags) : flags_(flags), name_(NULL) { }
374
375 static Register left();
376 static Register right();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000377
378 void Generate(MacroAssembler* masm);
379
380 private:
381 Major MajorKey() { return Instanceof; }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000382 int MinorKey() { return static_cast<int>(flags_); }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000383
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000384 bool HasArgsInRegisters() const {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000385 return (flags_ & kArgsInRegisters) != 0;
386 }
387
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000388 bool HasCallSiteInlineCheck() const {
389 return (flags_ & kCallSiteInlineCheck) != 0;
390 }
391
392 bool ReturnTrueFalseObject() const {
393 return (flags_ & kReturnTrueFalseObject) != 0;
394 }
395
396 const char* GetName();
397
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000398 Flags flags_;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000399 char* name_;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000400};
401
402
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000403class MathPowStub: public CodeStub {
404 public:
405 MathPowStub() {}
406 virtual void Generate(MacroAssembler* masm);
407
408 private:
409 virtual CodeStub::Major MajorKey() { return MathPow; }
410 virtual int MinorKey() { return 0; }
411
412 const char* GetName() { return "MathPowStub"; }
413};
414
415
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000416class ICCompareStub: public CodeStub {
417 public:
418 ICCompareStub(Token::Value op, CompareIC::State state)
419 : op_(op), state_(state) {
420 ASSERT(Token::IsCompareOp(op));
421 }
422
423 virtual void Generate(MacroAssembler* masm);
424
425 private:
426 class OpField: public BitField<int, 0, 3> { };
427 class StateField: public BitField<int, 3, 5> { };
428
429 virtual void FinishCode(Code* code) { code->set_compare_state(state_); }
430
431 virtual CodeStub::Major MajorKey() { return CompareIC; }
432 virtual int MinorKey();
433
434 virtual int GetCodeKind() { return Code::COMPARE_IC; }
435
436 void GenerateSmis(MacroAssembler* masm);
437 void GenerateHeapNumbers(MacroAssembler* masm);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000438 void GenerateSymbols(MacroAssembler* masm);
lrn@chromium.org1c092762011-05-09 09:42:16 +0000439 void GenerateStrings(MacroAssembler* masm);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000440 void GenerateObjects(MacroAssembler* masm);
441 void GenerateMiss(MacroAssembler* masm);
442
443 bool strict() const { return op_ == Token::EQ_STRICT; }
444 Condition GetCondition() const { return CompareIC::ComputeCondition(op_); }
445
446 Token::Value op_;
447 CompareIC::State state_;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000448};
449
450
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000451// Flags that control the compare stub code generation.
452enum CompareFlags {
453 NO_COMPARE_FLAGS = 0,
454 NO_SMI_COMPARE_IN_STUB = 1 << 0,
455 NO_NUMBER_COMPARE_IN_STUB = 1 << 1,
456 CANT_BOTH_BE_NAN = 1 << 2
457};
458
459
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000460enum NaNInformation {
461 kBothCouldBeNaN,
462 kCantBothBeNaN
463};
464
465
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000466class CompareStub: public CodeStub {
467 public:
468 CompareStub(Condition cc,
469 bool strict,
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000470 CompareFlags flags,
471 Register lhs,
472 Register rhs) :
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000473 cc_(cc),
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000474 strict_(strict),
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000475 never_nan_nan_((flags & CANT_BOTH_BE_NAN) != 0),
476 include_number_compare_((flags & NO_NUMBER_COMPARE_IN_STUB) == 0),
477 include_smi_compare_((flags & NO_SMI_COMPARE_IN_STUB) == 0),
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000478 lhs_(lhs),
479 rhs_(rhs),
480 name_(NULL) { }
481
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000482 CompareStub(Condition cc,
483 bool strict,
484 CompareFlags flags) :
485 cc_(cc),
486 strict_(strict),
487 never_nan_nan_((flags & CANT_BOTH_BE_NAN) != 0),
488 include_number_compare_((flags & NO_NUMBER_COMPARE_IN_STUB) == 0),
489 include_smi_compare_((flags & NO_SMI_COMPARE_IN_STUB) == 0),
490 lhs_(no_reg),
491 rhs_(no_reg),
492 name_(NULL) { }
493
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000494 void Generate(MacroAssembler* masm);
495
496 private:
497 Condition cc_;
498 bool strict_;
499 // Only used for 'equal' comparisons. Tells the stub that we already know
500 // that at least one side of the comparison is not NaN. This allows the
501 // stub to use object identity in the positive case. We ignore it when
502 // generating the minor key for other comparisons to avoid creating more
503 // stubs.
504 bool never_nan_nan_;
505 // Do generate the number comparison code in the stub. Stubs without number
506 // comparison code is used when the number comparison has been inlined, and
507 // the stub will be called if one of the operands is not a number.
508 bool include_number_compare_;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000509
510 // Generate the comparison code for two smi operands in the stub.
511 bool include_smi_compare_;
512
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000513 // Register holding the left hand side of the comparison if the stub gives
514 // a choice, no_reg otherwise.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000515
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000516 Register lhs_;
517 // Register holding the right hand side of the comparison if the stub gives
518 // a choice, no_reg otherwise.
519 Register rhs_;
520
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000521 // Encoding of the minor key in 16 bits.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000522 class StrictField: public BitField<bool, 0, 1> {};
523 class NeverNanNanField: public BitField<bool, 1, 1> {};
524 class IncludeNumberCompareField: public BitField<bool, 2, 1> {};
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000525 class IncludeSmiCompareField: public BitField<bool, 3, 1> {};
526 class RegisterField: public BitField<bool, 4, 1> {};
527 class ConditionField: public BitField<int, 5, 11> {};
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000528
529 Major MajorKey() { return Compare; }
530
531 int MinorKey();
532
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000533 virtual int GetCodeKind() { return Code::COMPARE_IC; }
534 virtual void FinishCode(Code* code) {
535 code->set_compare_state(CompareIC::GENERIC);
536 }
537
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000538 // Branch to the label if the given object isn't a symbol.
539 void BranchIfNonSymbol(MacroAssembler* masm,
540 Label* label,
541 Register object,
542 Register scratch);
543
544 // Unfortunately you have to run without snapshots to see most of these
545 // names in the profile since most compare stubs end up in the snapshot.
546 char* name_;
547 const char* GetName();
548#ifdef DEBUG
549 void Print() {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000550 PrintF("CompareStub (minor %d) (cc %d), (strict %s), "
551 "(never_nan_nan %s), (smi_compare %s) (number_compare %s) ",
552 MinorKey(),
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000553 static_cast<int>(cc_),
554 strict_ ? "true" : "false",
555 never_nan_nan_ ? "true" : "false",
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000556 include_smi_compare_ ? "inluded" : "not included",
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000557 include_number_compare_ ? "included" : "not included");
558
559 if (!lhs_.is(no_reg) && !rhs_.is(no_reg)) {
560 PrintF("(lhs r%d), (rhs r%d)\n", lhs_.code(), rhs_.code());
561 } else {
562 PrintF("\n");
563 }
564 }
565#endif
566};
567
568
569class CEntryStub : public CodeStub {
570 public:
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000571 explicit CEntryStub(int result_size)
572 : result_size_(result_size), save_doubles_(false) { }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000573
574 void Generate(MacroAssembler* masm);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000575 void SaveDoubles() { save_doubles_ = true; }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000576
577 private:
578 void GenerateCore(MacroAssembler* masm,
579 Label* throw_normal_exception,
580 Label* throw_termination_exception,
581 Label* throw_out_of_memory_exception,
582 bool do_gc,
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000583 bool always_allocate_scope);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000584 void GenerateThrowTOS(MacroAssembler* masm);
585 void GenerateThrowUncatchable(MacroAssembler* masm,
586 UncatchableExceptionType type);
587
588 // Number of pointers/values returned.
589 const int result_size_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000590 bool save_doubles_;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000591
592 Major MajorKey() { return CEntry; }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000593 int MinorKey();
594
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000595 bool NeedsImmovableCode();
596
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000597 const char* GetName() { return "CEntryStub"; }
598};
599
600
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000601class JSEntryStub : public CodeStub {
602 public:
603 JSEntryStub() { }
604
605 void Generate(MacroAssembler* masm) { GenerateBody(masm, false); }
606
607 protected:
608 void GenerateBody(MacroAssembler* masm, bool is_construct);
609
610 private:
611 Major MajorKey() { return JSEntry; }
612 int MinorKey() { return 0; }
613
614 const char* GetName() { return "JSEntryStub"; }
615};
616
617
618class JSConstructEntryStub : public JSEntryStub {
619 public:
620 JSConstructEntryStub() { }
621
622 void Generate(MacroAssembler* masm) { GenerateBody(masm, true); }
623
624 private:
625 int MinorKey() { return 1; }
626
627 const char* GetName() { return "JSConstructEntryStub"; }
628};
629
630
631class ArgumentsAccessStub: public CodeStub {
632 public:
633 enum Type {
634 READ_ELEMENT,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000635 NEW_NON_STRICT,
636 NEW_STRICT
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000637 };
638
639 explicit ArgumentsAccessStub(Type type) : type_(type) { }
640
641 private:
642 Type type_;
643
644 Major MajorKey() { return ArgumentsAccess; }
645 int MinorKey() { return type_; }
646
647 void Generate(MacroAssembler* masm);
648 void GenerateReadElement(MacroAssembler* masm);
649 void GenerateNewObject(MacroAssembler* masm);
650
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000651 int GetArgumentsBoilerplateIndex() const {
652 return (type_ == NEW_STRICT)
653 ? Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX
654 : Context::ARGUMENTS_BOILERPLATE_INDEX;
655 }
656
657 int GetArgumentsObjectSize() const {
658 if (type_ == NEW_STRICT)
659 return Heap::kArgumentsObjectSizeStrict;
660 else
661 return Heap::kArgumentsObjectSize;
662 }
663
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000664 const char* GetName() { return "ArgumentsAccessStub"; }
665
666#ifdef DEBUG
667 void Print() {
668 PrintF("ArgumentsAccessStub (type %d)\n", type_);
669 }
670#endif
671};
672
673
674class RegExpExecStub: public CodeStub {
675 public:
676 RegExpExecStub() { }
677
678 private:
679 Major MajorKey() { return RegExpExec; }
680 int MinorKey() { return 0; }
681
682 void Generate(MacroAssembler* masm);
683
684 const char* GetName() { return "RegExpExecStub"; }
685
686#ifdef DEBUG
687 void Print() {
688 PrintF("RegExpExecStub\n");
689 }
690#endif
691};
692
693
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000694class RegExpConstructResultStub: public CodeStub {
695 public:
696 RegExpConstructResultStub() { }
697
698 private:
699 Major MajorKey() { return RegExpConstructResult; }
700 int MinorKey() { return 0; }
701
702 void Generate(MacroAssembler* masm);
703
704 const char* GetName() { return "RegExpConstructResultStub"; }
705
706#ifdef DEBUG
707 void Print() {
708 PrintF("RegExpConstructResultStub\n");
709 }
710#endif
711};
712
713
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000714class CallFunctionStub: public CodeStub {
715 public:
716 CallFunctionStub(int argc, InLoopFlag in_loop, CallFunctionFlags flags)
717 : argc_(argc), in_loop_(in_loop), flags_(flags) { }
718
719 void Generate(MacroAssembler* masm);
720
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000721 static int ExtractArgcFromMinorKey(int minor_key) {
722 return ArgcBits::decode(minor_key);
723 }
724
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000725 private:
726 int argc_;
727 InLoopFlag in_loop_;
728 CallFunctionFlags flags_;
729
730#ifdef DEBUG
731 void Print() {
732 PrintF("CallFunctionStub (args %d, in_loop %d, flags %d)\n",
733 argc_,
734 static_cast<int>(in_loop_),
735 static_cast<int>(flags_));
736 }
737#endif
738
739 // Minor key encoding in 32 bits with Bitfield <Type, shift, size>.
740 class InLoopBits: public BitField<InLoopFlag, 0, 1> {};
741 class FlagBits: public BitField<CallFunctionFlags, 1, 1> {};
742 class ArgcBits: public BitField<int, 2, 32 - 2> {};
743
744 Major MajorKey() { return CallFunction; }
745 int MinorKey() {
746 // Encode the parameters in a unique 32 bit value.
747 return InLoopBits::encode(in_loop_)
748 | FlagBits::encode(flags_)
749 | ArgcBits::encode(argc_);
750 }
751
752 InLoopFlag InLoop() { return in_loop_; }
danno@chromium.org40cb8782011-05-25 07:58:50 +0000753
754 bool ReceiverMightBeImplicit() {
755 return (flags_ & RECEIVER_MIGHT_BE_IMPLICIT) != 0;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000756 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000757};
758
759
760enum StringIndexFlags {
761 // Accepts smis or heap numbers.
762 STRING_INDEX_IS_NUMBER,
763
764 // Accepts smis or heap numbers that are valid array indices
765 // (ECMA-262 15.4). Invalid indices are reported as being out of
766 // range.
767 STRING_INDEX_IS_ARRAY_INDEX
768};
769
770
771// Generates code implementing String.prototype.charCodeAt.
772//
773// Only supports the case when the receiver is a string and the index
774// is a number (smi or heap number) that is a valid index into the
775// string. Additional index constraints are specified by the
776// flags. Otherwise, bails out to the provided labels.
777//
778// Register usage: |object| may be changed to another string in a way
779// that doesn't affect charCodeAt/charAt semantics, |index| is
780// preserved, |scratch| and |result| are clobbered.
781class StringCharCodeAtGenerator {
782 public:
783 StringCharCodeAtGenerator(Register object,
784 Register index,
785 Register scratch,
786 Register result,
787 Label* receiver_not_string,
788 Label* index_not_number,
789 Label* index_out_of_range,
790 StringIndexFlags index_flags)
791 : object_(object),
792 index_(index),
793 scratch_(scratch),
794 result_(result),
795 receiver_not_string_(receiver_not_string),
796 index_not_number_(index_not_number),
797 index_out_of_range_(index_out_of_range),
798 index_flags_(index_flags) {
799 ASSERT(!scratch_.is(object_));
800 ASSERT(!scratch_.is(index_));
801 ASSERT(!scratch_.is(result_));
802 ASSERT(!result_.is(object_));
803 ASSERT(!result_.is(index_));
804 }
805
806 // Generates the fast case code. On the fallthrough path |result|
807 // register contains the result.
808 void GenerateFast(MacroAssembler* masm);
809
810 // Generates the slow case code. Must not be naturally
811 // reachable. Expected to be put after a ret instruction (e.g., in
812 // deferred code). Always jumps back to the fast case.
813 void GenerateSlow(MacroAssembler* masm,
814 const RuntimeCallHelper& call_helper);
815
816 private:
817 Register object_;
818 Register index_;
819 Register scratch_;
820 Register result_;
821
822 Label* receiver_not_string_;
823 Label* index_not_number_;
824 Label* index_out_of_range_;
825
826 StringIndexFlags index_flags_;
827
828 Label call_runtime_;
829 Label index_not_smi_;
830 Label got_smi_index_;
831 Label exit_;
832
833 DISALLOW_COPY_AND_ASSIGN(StringCharCodeAtGenerator);
834};
835
836
837// Generates code for creating a one-char string from a char code.
838class StringCharFromCodeGenerator {
839 public:
840 StringCharFromCodeGenerator(Register code,
841 Register result)
842 : code_(code),
843 result_(result) {
844 ASSERT(!code_.is(result_));
845 }
846
847 // Generates the fast case code. On the fallthrough path |result|
848 // register contains the result.
849 void GenerateFast(MacroAssembler* masm);
850
851 // Generates the slow case code. Must not be naturally
852 // reachable. Expected to be put after a ret instruction (e.g., in
853 // deferred code). Always jumps back to the fast case.
854 void GenerateSlow(MacroAssembler* masm,
855 const RuntimeCallHelper& call_helper);
856
857 private:
858 Register code_;
859 Register result_;
860
861 Label slow_case_;
862 Label exit_;
863
864 DISALLOW_COPY_AND_ASSIGN(StringCharFromCodeGenerator);
865};
866
867
868// Generates code implementing String.prototype.charAt.
869//
870// Only supports the case when the receiver is a string and the index
871// is a number (smi or heap number) that is a valid index into the
872// string. Additional index constraints are specified by the
873// flags. Otherwise, bails out to the provided labels.
874//
875// Register usage: |object| may be changed to another string in a way
876// that doesn't affect charCodeAt/charAt semantics, |index| is
877// preserved, |scratch1|, |scratch2|, and |result| are clobbered.
878class StringCharAtGenerator {
879 public:
880 StringCharAtGenerator(Register object,
881 Register index,
882 Register scratch1,
883 Register scratch2,
884 Register result,
885 Label* receiver_not_string,
886 Label* index_not_number,
887 Label* index_out_of_range,
888 StringIndexFlags index_flags)
889 : char_code_at_generator_(object,
890 index,
891 scratch1,
892 scratch2,
893 receiver_not_string,
894 index_not_number,
895 index_out_of_range,
896 index_flags),
897 char_from_code_generator_(scratch2, result) {}
898
899 // Generates the fast case code. On the fallthrough path |result|
900 // register contains the result.
901 void GenerateFast(MacroAssembler* masm);
902
903 // Generates the slow case code. Must not be naturally
904 // reachable. Expected to be put after a ret instruction (e.g., in
905 // deferred code). Always jumps back to the fast case.
906 void GenerateSlow(MacroAssembler* masm,
907 const RuntimeCallHelper& call_helper);
908
909 private:
910 StringCharCodeAtGenerator char_code_at_generator_;
911 StringCharFromCodeGenerator char_from_code_generator_;
912
913 DISALLOW_COPY_AND_ASSIGN(StringCharAtGenerator);
914};
915
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000916
917class AllowStubCallsScope {
918 public:
919 AllowStubCallsScope(MacroAssembler* masm, bool allow)
920 : masm_(masm), previous_allow_(masm->allow_stub_calls()) {
921 masm_->set_allow_stub_calls(allow);
922 }
923 ~AllowStubCallsScope() {
924 masm_->set_allow_stub_calls(previous_allow_);
925 }
926
927 private:
928 MacroAssembler* masm_;
929 bool previous_allow_;
930
931 DISALLOW_COPY_AND_ASSIGN(AllowStubCallsScope);
932};
933
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000934#ifdef DEBUG
935#define DECLARE_ARRAY_STUB_PRINT(name) void Print() { PrintF(#name); }
936#else
937#define DECLARE_ARRAY_STUB_PRINT(name)
938#endif
939
940
941class KeyedLoadFastElementStub : public CodeStub {
942 public:
943 explicit KeyedLoadFastElementStub() {
944 }
945
946 Major MajorKey() { return KeyedLoadFastElement; }
947 int MinorKey() { return 0; }
948
949 void Generate(MacroAssembler* masm);
950
951 const char* GetName() { return "KeyedLoadFastElementStub"; }
952
953 DECLARE_ARRAY_STUB_PRINT(KeyedLoadFastElementStub)
954};
955
956
957class KeyedStoreFastElementStub : public CodeStub {
958 public:
959 explicit KeyedStoreFastElementStub(bool is_js_array)
960 : is_js_array_(is_js_array) { }
961
962 Major MajorKey() { return KeyedStoreFastElement; }
963 int MinorKey() { return is_js_array_ ? 1 : 0; }
964
965 void Generate(MacroAssembler* masm);
966
967 const char* GetName() { return "KeyedStoreFastElementStub"; }
968
969 DECLARE_ARRAY_STUB_PRINT(KeyedStoreFastElementStub)
970
971 private:
972 bool is_js_array_;
973};
974
975
976class KeyedLoadExternalArrayStub : public CodeStub {
977 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000978 explicit KeyedLoadExternalArrayStub(JSObject::ElementsKind elements_kind)
979 : elements_kind_(elements_kind) { }
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000980
981 Major MajorKey() { return KeyedLoadExternalArray; }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000982 int MinorKey() { return elements_kind_; }
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000983
984 void Generate(MacroAssembler* masm);
985
986 const char* GetName() { return "KeyedLoadExternalArrayStub"; }
987
988 DECLARE_ARRAY_STUB_PRINT(KeyedLoadExternalArrayStub)
989
990 protected:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000991 JSObject::ElementsKind elements_kind_;
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000992};
993
994
995class KeyedStoreExternalArrayStub : public CodeStub {
996 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000997 explicit KeyedStoreExternalArrayStub(JSObject::ElementsKind elements_kind)
998 : elements_kind_(elements_kind) { }
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000999
1000 Major MajorKey() { return KeyedStoreExternalArray; }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001001 int MinorKey() { return elements_kind_; }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001002
1003 void Generate(MacroAssembler* masm);
1004
1005 const char* GetName() { return "KeyedStoreExternalArrayStub"; }
1006
1007 DECLARE_ARRAY_STUB_PRINT(KeyedStoreExternalArrayStub)
1008
1009 protected:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001010 JSObject::ElementsKind elements_kind_;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001011};
1012
1013
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001014} } // namespace v8::internal
1015
1016#endif // V8_CODE_STUBS_H_