blob: 2a6ad6435b55ef372d319b0583bb241040fffed1 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#ifndef V8_CODEGEN_H_
29#define V8_CODEGEN_H_
30
Steve Blocka7e24c12009-10-30 11:49:00 +000031#include "code-stubs.h"
32#include "runtime.h"
Steve Block6ded16b2010-05-10 14:33:55 +010033#include "type-info.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000034
35// Include the declaration of the architecture defined class CodeGenerator.
36// The contract to the shared code is that the the CodeGenerator is a subclass
37// of Visitor and that the following methods are available publicly:
38// MakeCode
Steve Block3ce2e202009-11-05 08:53:23 +000039// MakeCodePrologue
40// MakeCodeEpilogue
Steve Blocka7e24c12009-10-30 11:49:00 +000041// masm
42// frame
Steve Blockd0582a62009-12-15 09:54:21 +000043// script
Steve Blocka7e24c12009-10-30 11:49:00 +000044// has_valid_frame
45// SetFrame
46// DeleteFrame
47// allocator
48// AddDeferred
49// in_spilled_code
50// set_in_spilled_code
Steve Block3ce2e202009-11-05 08:53:23 +000051// RecordPositions
Steve Blocka7e24c12009-10-30 11:49:00 +000052//
53// These methods are either used privately by the shared code or implemented as
54// shared code:
55// CodeGenerator
56// ~CodeGenerator
57// ProcessDeferred
Leon Clarke4515c472010-02-03 11:58:03 +000058// Generate
Steve Block3ce2e202009-11-05 08:53:23 +000059// ComputeLazyCompile
Steve Block6ded16b2010-05-10 14:33:55 +010060// BuildFunctionInfo
Steve Blocka7e24c12009-10-30 11:49:00 +000061// ComputeCallInitialize
62// ComputeCallInitializeInLoop
63// ProcessDeclarations
64// DeclareGlobals
65// FindInlineRuntimeLUT
66// CheckForInlineRuntimeCall
67// PatchInlineRuntimeEntry
Steve Block3ce2e202009-11-05 08:53:23 +000068// AnalyzeCondition
Steve Blocka7e24c12009-10-30 11:49:00 +000069// CodeForFunctionPosition
70// CodeForReturnPosition
71// CodeForStatementPosition
Steve Blockd0582a62009-12-15 09:54:21 +000072// CodeForDoWhileConditionPosition
Steve Blocka7e24c12009-10-30 11:49:00 +000073// CodeForSourcePosition
74
75
76// Mode to overwrite BinaryExpression values.
77enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
Leon Clarkeac952652010-07-15 11:15:24 +010078enum UnaryOverwriteMode { UNARY_OVERWRITE, UNARY_NO_OVERWRITE };
Steve Blocka7e24c12009-10-30 11:49:00 +000079
80// Types of uncatchable exceptions.
81enum UncatchableExceptionType { OUT_OF_MEMORY, TERMINATION };
82
Steve Block6ded16b2010-05-10 14:33:55 +010083#define INLINE_RUNTIME_FUNCTION_LIST(F) \
84 F(IsSmi, 1, 1) \
85 F(IsNonNegativeSmi, 1, 1) \
86 F(IsArray, 1, 1) \
87 F(IsRegExp, 1, 1) \
88 F(CallFunction, -1 /* receiver + n args + function */, 1) \
89 F(IsConstructCall, 0, 1) \
90 F(ArgumentsLength, 0, 1) \
91 F(Arguments, 1, 1) \
92 F(ClassOf, 1, 1) \
93 F(ValueOf, 1, 1) \
94 F(SetValueOf, 2, 1) \
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010095 F(StringCharCodeAt, 2, 1) \
96 F(StringCharFromCode, 1, 1) \
97 F(StringCharAt, 2, 1) \
Steve Block6ded16b2010-05-10 14:33:55 +010098 F(ObjectEquals, 2, 1) \
99 F(Log, 3, 1) \
Leon Clarkef7060e22010-06-03 12:02:55 +0100100 F(RandomHeapNumber, 0, 1) \
Steve Block6ded16b2010-05-10 14:33:55 +0100101 F(IsObject, 1, 1) \
102 F(IsFunction, 1, 1) \
103 F(IsUndetectableObject, 1, 1) \
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100104 F(IsSpecObject, 1, 1) \
Steve Block6ded16b2010-05-10 14:33:55 +0100105 F(StringAdd, 2, 1) \
106 F(SubString, 3, 1) \
107 F(StringCompare, 2, 1) \
108 F(RegExpExec, 4, 1) \
109 F(RegExpConstructResult, 3, 1) \
110 F(GetFromCache, 2, 1) \
111 F(NumberToString, 1, 1) \
112 F(SwapElements, 3, 1) \
113 F(MathPow, 2, 1) \
114 F(MathSin, 1, 1) \
115 F(MathCos, 1, 1) \
Ben Murdochbb769b22010-08-11 14:56:33 +0100116 F(MathSqrt, 1, 1) \
117 F(IsRegExpEquivalent, 2, 1)
Steve Block6ded16b2010-05-10 14:33:55 +0100118
119
Ben Murdochbb769b22010-08-11 14:56:33 +0100120#if V8_TARGET_ARCH_IA32
121#include "ia32/codegen-ia32.h"
122#elif V8_TARGET_ARCH_X64
123#include "x64/codegen-x64.h"
124#elif V8_TARGET_ARCH_ARM
125#include "arm/codegen-arm.h"
126#elif V8_TARGET_ARCH_MIPS
127#include "mips/codegen-mips.h"
128#else
129#error Unsupported target architecture.
130#endif
131
132#include "register-allocator.h"
133
134namespace v8 {
135namespace internal {
136
Andrei Popescu31002712010-02-23 13:46:05 +0000137// Support for "structured" code comments.
138#ifdef DEBUG
139
140class Comment BASE_EMBEDDED {
141 public:
142 Comment(MacroAssembler* masm, const char* msg);
143 ~Comment();
144
145 private:
146 MacroAssembler* masm_;
147 const char* msg_;
148};
149
150#else
151
152class Comment BASE_EMBEDDED {
153 public:
154 Comment(MacroAssembler*, const char*) {}
155};
156
157#endif // DEBUG
158
159
Steve Blocka7e24c12009-10-30 11:49:00 +0000160// Code generation can be nested. Code generation scopes form a stack
161// of active code generators.
162class CodeGeneratorScope BASE_EMBEDDED {
163 public:
164 explicit CodeGeneratorScope(CodeGenerator* cgen) {
165 previous_ = top_;
166 top_ = cgen;
167 }
168
169 ~CodeGeneratorScope() {
170 top_ = previous_;
171 }
172
173 static CodeGenerator* Current() {
174 ASSERT(top_ != NULL);
175 return top_;
176 }
177
178 private:
179 static CodeGenerator* top_;
180 CodeGenerator* previous_;
181};
182
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100183#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64
184
185// State of used registers in a virtual frame.
186class FrameRegisterState {
187 public:
188 // Captures the current state of the given frame.
189 explicit FrameRegisterState(VirtualFrame* frame);
190
191 // Saves the state in the stack.
192 void Save(MacroAssembler* masm) const;
193
194 // Restores the state from the stack.
195 void Restore(MacroAssembler* masm) const;
196
197 private:
198 // Constants indicating special actions. They should not be multiples
199 // of kPointerSize so they will not collide with valid offsets from
200 // the frame pointer.
201 static const int kIgnore = -1;
202 static const int kPush = 1;
203
204 // This flag is ored with a valid offset from the frame pointer, so
205 // it should fit in the low zero bits of a valid offset.
206 static const int kSyncedFlag = 2;
207
208 int registers_[RegisterAllocator::kNumRegisters];
209};
210
211#elif V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
212
213
214class FrameRegisterState {
215 public:
216 inline FrameRegisterState(VirtualFrame frame) : frame_(frame) { }
217
218 inline const VirtualFrame* frame() const { return &frame_; }
219
220 private:
221 VirtualFrame frame_;
222};
223
224#else
225
226#error Unsupported target architecture.
227
228#endif
229
230
231// Helper interface to prepare to/restore after making runtime calls.
232class RuntimeCallHelper {
233 public:
234 virtual ~RuntimeCallHelper() {}
235
236 virtual void BeforeCall(MacroAssembler* masm) const = 0;
237
238 virtual void AfterCall(MacroAssembler* masm) const = 0;
239
240 protected:
241 RuntimeCallHelper() {}
242
243 private:
244 DISALLOW_COPY_AND_ASSIGN(RuntimeCallHelper);
245};
246
247
248// RuntimeCallHelper implementation that saves/restores state of a
249// virtual frame.
250class VirtualFrameRuntimeCallHelper : public RuntimeCallHelper {
251 public:
252 // Does not take ownership of |frame_state|.
253 explicit VirtualFrameRuntimeCallHelper(const FrameRegisterState* frame_state)
254 : frame_state_(frame_state) {}
255
256 virtual void BeforeCall(MacroAssembler* masm) const;
257
258 virtual void AfterCall(MacroAssembler* masm) const;
259
260 private:
261 const FrameRegisterState* frame_state_;
262};
263
264
265// RuntimeCallHelper implementation used in IC stubs: enters/leaves a
266// newly created internal frame before/after the runtime call.
267class ICRuntimeCallHelper : public RuntimeCallHelper {
268 public:
269 ICRuntimeCallHelper() {}
270
271 virtual void BeforeCall(MacroAssembler* masm) const;
272
273 virtual void AfterCall(MacroAssembler* masm) const;
274};
275
276
277// Trivial RuntimeCallHelper implementation.
278class NopRuntimeCallHelper : public RuntimeCallHelper {
279 public:
280 NopRuntimeCallHelper() {}
281
282 virtual void BeforeCall(MacroAssembler* masm) const {}
283
284 virtual void AfterCall(MacroAssembler* masm) const {}
285};
286
287
Steve Blocka7e24c12009-10-30 11:49:00 +0000288// Deferred code objects are small pieces of code that are compiled
289// out of line. They are used to defer the compilation of uncommon
290// paths thereby avoiding expensive jumps around uncommon code parts.
291class DeferredCode: public ZoneObject {
292 public:
293 DeferredCode();
294 virtual ~DeferredCode() { }
295
296 virtual void Generate() = 0;
297
298 MacroAssembler* masm() { return masm_; }
299
300 int statement_position() const { return statement_position_; }
301 int position() const { return position_; }
302
303 Label* entry_label() { return &entry_label_; }
304 Label* exit_label() { return &exit_label_; }
305
306#ifdef DEBUG
307 void set_comment(const char* comment) { comment_ = comment; }
308 const char* comment() const { return comment_; }
309#else
310 void set_comment(const char* comment) { }
311 const char* comment() const { return ""; }
312#endif
313
314 inline void Jump();
315 inline void Branch(Condition cc);
316 void BindExit() { masm_->bind(&exit_label_); }
317
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100318 const FrameRegisterState* frame_state() const { return &frame_state_; }
319
Steve Blocka7e24c12009-10-30 11:49:00 +0000320 void SaveRegisters();
321 void RestoreRegisters();
322
323 protected:
324 MacroAssembler* masm_;
325
326 private:
Steve Blocka7e24c12009-10-30 11:49:00 +0000327 int statement_position_;
328 int position_;
329
330 Label entry_label_;
331 Label exit_label_;
332
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100333 FrameRegisterState frame_state_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000334
335#ifdef DEBUG
336 const char* comment_;
337#endif
338 DISALLOW_COPY_AND_ASSIGN(DeferredCode);
339};
340
Steve Blocka7e24c12009-10-30 11:49:00 +0000341class StackCheckStub : public CodeStub {
342 public:
343 StackCheckStub() { }
344
345 void Generate(MacroAssembler* masm);
346
347 private:
348
349 const char* GetName() { return "StackCheckStub"; }
350
351 Major MajorKey() { return StackCheck; }
352 int MinorKey() { return 0; }
353};
354
355
Leon Clarkee46be812010-01-19 14:06:41 +0000356class FastNewClosureStub : public CodeStub {
357 public:
358 void Generate(MacroAssembler* masm);
359
360 private:
361 const char* GetName() { return "FastNewClosureStub"; }
362 Major MajorKey() { return FastNewClosure; }
363 int MinorKey() { return 0; }
364};
365
366
367class FastNewContextStub : public CodeStub {
368 public:
369 static const int kMaximumSlots = 64;
370
371 explicit FastNewContextStub(int slots) : slots_(slots) {
372 ASSERT(slots_ > 0 && slots <= kMaximumSlots);
373 }
374
375 void Generate(MacroAssembler* masm);
376
377 private:
378 int slots_;
379
380 const char* GetName() { return "FastNewContextStub"; }
381 Major MajorKey() { return FastNewContext; }
382 int MinorKey() { return slots_; }
383};
384
385
386class FastCloneShallowArrayStub : public CodeStub {
387 public:
388 static const int kMaximumLength = 8;
389
390 explicit FastCloneShallowArrayStub(int length) : length_(length) {
391 ASSERT(length >= 0 && length <= kMaximumLength);
392 }
393
394 void Generate(MacroAssembler* masm);
395
396 private:
397 int length_;
398
399 const char* GetName() { return "FastCloneShallowArrayStub"; }
400 Major MajorKey() { return FastCloneShallowArray; }
401 int MinorKey() { return length_; }
402};
403
404
Steve Blocka7e24c12009-10-30 11:49:00 +0000405class InstanceofStub: public CodeStub {
406 public:
407 InstanceofStub() { }
408
409 void Generate(MacroAssembler* masm);
410
411 private:
412 Major MajorKey() { return Instanceof; }
413 int MinorKey() { return 0; }
414};
415
416
Leon Clarkeac952652010-07-15 11:15:24 +0100417enum NegativeZeroHandling {
418 kStrictNegativeZero,
419 kIgnoreNegativeZero
420};
421
422
Leon Clarkee46be812010-01-19 14:06:41 +0000423class GenericUnaryOpStub : public CodeStub {
Steve Blocka7e24c12009-10-30 11:49:00 +0000424 public:
Leon Clarkeac952652010-07-15 11:15:24 +0100425 GenericUnaryOpStub(Token::Value op,
426 UnaryOverwriteMode overwrite,
427 NegativeZeroHandling negative_zero = kStrictNegativeZero)
428 : op_(op), overwrite_(overwrite), negative_zero_(negative_zero) { }
Steve Blocka7e24c12009-10-30 11:49:00 +0000429
430 private:
Leon Clarkee46be812010-01-19 14:06:41 +0000431 Token::Value op_;
Leon Clarkeac952652010-07-15 11:15:24 +0100432 UnaryOverwriteMode overwrite_;
433 NegativeZeroHandling negative_zero_;
Leon Clarkee46be812010-01-19 14:06:41 +0000434
Leon Clarkeac952652010-07-15 11:15:24 +0100435 class OverwriteField: public BitField<UnaryOverwriteMode, 0, 1> {};
436 class NegativeZeroField: public BitField<NegativeZeroHandling, 1, 1> {};
437 class OpField: public BitField<Token::Value, 2, kMinorBits - 2> {};
Leon Clarkee46be812010-01-19 14:06:41 +0000438
439 Major MajorKey() { return GenericUnaryOp; }
440 int MinorKey() {
Leon Clarkeac952652010-07-15 11:15:24 +0100441 return OpField::encode(op_) |
442 OverwriteField::encode(overwrite_) |
443 NegativeZeroField::encode(negative_zero_);
Leon Clarkee46be812010-01-19 14:06:41 +0000444 }
445
Steve Blocka7e24c12009-10-30 11:49:00 +0000446 void Generate(MacroAssembler* masm);
447
Leon Clarkee46be812010-01-19 14:06:41 +0000448 const char* GetName();
449};
450
451
452enum NaNInformation {
453 kBothCouldBeNaN,
454 kCantBothBeNaN
Steve Blocka7e24c12009-10-30 11:49:00 +0000455};
456
457
458class CompareStub: public CodeStub {
459 public:
Leon Clarkee46be812010-01-19 14:06:41 +0000460 CompareStub(Condition cc,
461 bool strict,
Steve Block6ded16b2010-05-10 14:33:55 +0100462 NaNInformation nan_info = kBothCouldBeNaN,
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100463 bool include_number_compare = true,
464 Register lhs = no_reg,
465 Register rhs = no_reg) :
Steve Block6ded16b2010-05-10 14:33:55 +0100466 cc_(cc),
467 strict_(strict),
468 never_nan_nan_(nan_info == kCantBothBeNaN),
469 include_number_compare_(include_number_compare),
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100470 lhs_(lhs),
471 rhs_(rhs),
Steve Block6ded16b2010-05-10 14:33:55 +0100472 name_(NULL) { }
Steve Blocka7e24c12009-10-30 11:49:00 +0000473
474 void Generate(MacroAssembler* masm);
475
476 private:
477 Condition cc_;
478 bool strict_;
Leon Clarkee46be812010-01-19 14:06:41 +0000479 // Only used for 'equal' comparisons. Tells the stub that we already know
480 // that at least one side of the comparison is not NaN. This allows the
481 // stub to use object identity in the positive case. We ignore it when
482 // generating the minor key for other comparisons to avoid creating more
483 // stubs.
484 bool never_nan_nan_;
Steve Block6ded16b2010-05-10 14:33:55 +0100485 // Do generate the number comparison code in the stub. Stubs without number
486 // comparison code is used when the number comparison has been inlined, and
487 // the stub will be called if one of the operands is not a number.
488 bool include_number_compare_;
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100489 // Register holding the left hand side of the comparison if the stub gives
490 // a choice, no_reg otherwise.
491 Register lhs_;
492 // Register holding the right hand side of the comparison if the stub gives
493 // a choice, no_reg otherwise.
494 Register rhs_;
Steve Block6ded16b2010-05-10 14:33:55 +0100495
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100496 // Encoding of the minor key CCCCCCCCCCCCRCNS.
Steve Block6ded16b2010-05-10 14:33:55 +0100497 class StrictField: public BitField<bool, 0, 1> {};
498 class NeverNanNanField: public BitField<bool, 1, 1> {};
499 class IncludeNumberCompareField: public BitField<bool, 2, 1> {};
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100500 class RegisterField: public BitField<bool, 3, 1> {};
501 class ConditionField: public BitField<int, 4, 12> {};
Steve Blocka7e24c12009-10-30 11:49:00 +0000502
503 Major MajorKey() { return Compare; }
504
505 int MinorKey();
506
507 // Branch to the label if the given object isn't a symbol.
508 void BranchIfNonSymbol(MacroAssembler* masm,
509 Label* label,
510 Register object,
511 Register scratch);
512
Leon Clarkee46be812010-01-19 14:06:41 +0000513 // Unfortunately you have to run without snapshots to see most of these
514 // names in the profile since most compare stubs end up in the snapshot.
Steve Block6ded16b2010-05-10 14:33:55 +0100515 char* name_;
Leon Clarkee46be812010-01-19 14:06:41 +0000516 const char* GetName();
Steve Blocka7e24c12009-10-30 11:49:00 +0000517#ifdef DEBUG
518 void Print() {
Steve Block6ded16b2010-05-10 14:33:55 +0100519 PrintF("CompareStub (cc %d), (strict %s), "
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100520 "(never_nan_nan %s), (number_compare %s) ",
Steve Blocka7e24c12009-10-30 11:49:00 +0000521 static_cast<int>(cc_),
Steve Block6ded16b2010-05-10 14:33:55 +0100522 strict_ ? "true" : "false",
523 never_nan_nan_ ? "true" : "false",
524 include_number_compare_ ? "included" : "not included");
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100525
526 if (!lhs_.is(no_reg) && !rhs_.is(no_reg)) {
527 PrintF("(lhs r%d), (rhs r%d)\n", lhs_.code(), rhs_.code());
528 } else {
529 PrintF("\n");
530 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000531 }
532#endif
533};
534
535
536class CEntryStub : public CodeStub {
537 public:
Leon Clarke4515c472010-02-03 11:58:03 +0000538 explicit CEntryStub(int result_size,
539 ExitFrame::Mode mode = ExitFrame::MODE_NORMAL)
540 : result_size_(result_size), mode_(mode) { }
Steve Blocka7e24c12009-10-30 11:49:00 +0000541
Leon Clarke4515c472010-02-03 11:58:03 +0000542 void Generate(MacroAssembler* masm);
Steve Blocka7e24c12009-10-30 11:49:00 +0000543
Leon Clarke4515c472010-02-03 11:58:03 +0000544 private:
Steve Blocka7e24c12009-10-30 11:49:00 +0000545 void GenerateCore(MacroAssembler* masm,
546 Label* throw_normal_exception,
547 Label* throw_termination_exception,
548 Label* throw_out_of_memory_exception,
Steve Blocka7e24c12009-10-30 11:49:00 +0000549 bool do_gc,
Steve Block6ded16b2010-05-10 14:33:55 +0100550 bool always_allocate_scope,
551 int alignment_skew = 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000552 void GenerateThrowTOS(MacroAssembler* masm);
553 void GenerateThrowUncatchable(MacroAssembler* masm,
554 UncatchableExceptionType type);
Leon Clarke4515c472010-02-03 11:58:03 +0000555
Steve Blocka7e24c12009-10-30 11:49:00 +0000556 // Number of pointers/values returned.
Leon Clarke4515c472010-02-03 11:58:03 +0000557 const int result_size_;
558 const ExitFrame::Mode mode_;
559
560 // Minor key encoding
561 class ExitFrameModeBits: public BitField<ExitFrame::Mode, 0, 1> {};
562 class IndirectResultBits: public BitField<bool, 1, 1> {};
Steve Blocka7e24c12009-10-30 11:49:00 +0000563
564 Major MajorKey() { return CEntry; }
565 // Minor key must differ if different result_size_ values means different
566 // code is generated.
567 int MinorKey();
568
569 const char* GetName() { return "CEntryStub"; }
570};
571
572
Steve Blockd0582a62009-12-15 09:54:21 +0000573class ApiGetterEntryStub : public CodeStub {
574 public:
575 ApiGetterEntryStub(Handle<AccessorInfo> info,
576 ApiFunction* fun)
577 : info_(info),
578 fun_(fun) { }
579 void Generate(MacroAssembler* masm);
580 virtual bool has_custom_cache() { return true; }
581 virtual bool GetCustomCache(Code** code_out);
582 virtual void SetCustomCache(Code* value);
583
Steve Block6ded16b2010-05-10 14:33:55 +0100584 static const int kStackSpace = 5;
Steve Blockd0582a62009-12-15 09:54:21 +0000585 static const int kArgc = 4;
586 private:
587 Handle<AccessorInfo> info() { return info_; }
588 ApiFunction* fun() { return fun_; }
589 Major MajorKey() { return NoCache; }
590 int MinorKey() { return 0; }
591 const char* GetName() { return "ApiEntryStub"; }
592 // The accessor info associated with the function.
593 Handle<AccessorInfo> info_;
594 // The function to be called.
595 ApiFunction* fun_;
596};
597
598
Steve Blocka7e24c12009-10-30 11:49:00 +0000599class JSEntryStub : public CodeStub {
600 public:
601 JSEntryStub() { }
602
603 void Generate(MacroAssembler* masm) { GenerateBody(masm, false); }
604
605 protected:
606 void GenerateBody(MacroAssembler* masm, bool is_construct);
607
608 private:
609 Major MajorKey() { return JSEntry; }
610 int MinorKey() { return 0; }
611
612 const char* GetName() { return "JSEntryStub"; }
613};
614
615
616class JSConstructEntryStub : public JSEntryStub {
617 public:
618 JSConstructEntryStub() { }
619
620 void Generate(MacroAssembler* masm) { GenerateBody(masm, true); }
621
622 private:
623 int MinorKey() { return 1; }
624
625 const char* GetName() { return "JSConstructEntryStub"; }
626};
627
628
629class ArgumentsAccessStub: public CodeStub {
630 public:
631 enum Type {
Steve Blocka7e24c12009-10-30 11:49:00 +0000632 READ_ELEMENT,
633 NEW_OBJECT
634 };
635
636 explicit ArgumentsAccessStub(Type type) : type_(type) { }
637
638 private:
639 Type type_;
640
641 Major MajorKey() { return ArgumentsAccess; }
642 int MinorKey() { return type_; }
643
644 void Generate(MacroAssembler* masm);
Steve Blocka7e24c12009-10-30 11:49:00 +0000645 void GenerateReadElement(MacroAssembler* masm);
646 void GenerateNewObject(MacroAssembler* masm);
647
648 const char* GetName() { return "ArgumentsAccessStub"; }
649
650#ifdef DEBUG
651 void Print() {
652 PrintF("ArgumentsAccessStub (type %d)\n", type_);
653 }
654#endif
655};
656
657
Leon Clarkee46be812010-01-19 14:06:41 +0000658class RegExpExecStub: public CodeStub {
659 public:
660 RegExpExecStub() { }
661
662 private:
663 Major MajorKey() { return RegExpExec; }
664 int MinorKey() { return 0; }
665
666 void Generate(MacroAssembler* masm);
667
668 const char* GetName() { return "RegExpExecStub"; }
669
670#ifdef DEBUG
671 void Print() {
672 PrintF("RegExpExecStub\n");
673 }
674#endif
675};
676
677
678class CallFunctionStub: public CodeStub {
679 public:
680 CallFunctionStub(int argc, InLoopFlag in_loop, CallFunctionFlags flags)
681 : argc_(argc), in_loop_(in_loop), flags_(flags) { }
682
683 void Generate(MacroAssembler* masm);
684
685 private:
686 int argc_;
687 InLoopFlag in_loop_;
688 CallFunctionFlags flags_;
689
690#ifdef DEBUG
691 void Print() {
692 PrintF("CallFunctionStub (args %d, in_loop %d, flags %d)\n",
693 argc_,
694 static_cast<int>(in_loop_),
695 static_cast<int>(flags_));
696 }
697#endif
698
Andrei Popescu402d9372010-02-26 13:31:12 +0000699 // Minor key encoding in 32 bits with Bitfield <Type, shift, size>.
Leon Clarkee46be812010-01-19 14:06:41 +0000700 class InLoopBits: public BitField<InLoopFlag, 0, 1> {};
701 class FlagBits: public BitField<CallFunctionFlags, 1, 1> {};
Andrei Popescu402d9372010-02-26 13:31:12 +0000702 class ArgcBits: public BitField<int, 2, 32 - 2> {};
Leon Clarkee46be812010-01-19 14:06:41 +0000703
704 Major MajorKey() { return CallFunction; }
705 int MinorKey() {
Andrei Popescu402d9372010-02-26 13:31:12 +0000706 // Encode the parameters in a unique 32 bit value.
Leon Clarkee46be812010-01-19 14:06:41 +0000707 return InLoopBits::encode(in_loop_)
708 | FlagBits::encode(flags_)
709 | ArgcBits::encode(argc_);
710 }
711
712 InLoopFlag InLoop() { return in_loop_; }
713 bool ReceiverMightBeValue() {
714 return (flags_ & RECEIVER_MIGHT_BE_VALUE) != 0;
715 }
716
717 public:
718 static int ExtractArgcFromMinorKey(int minor_key) {
719 return ArgcBits::decode(minor_key);
720 }
721};
722
723
724class ToBooleanStub: public CodeStub {
725 public:
726 ToBooleanStub() { }
727
728 void Generate(MacroAssembler* masm);
729
730 private:
731 Major MajorKey() { return ToBoolean; }
732 int MinorKey() { return 0; }
733};
734
735
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100736enum StringIndexFlags {
737 // Accepts smis or heap numbers.
738 STRING_INDEX_IS_NUMBER,
739
740 // Accepts smis or heap numbers that are valid array indices
741 // (ECMA-262 15.4). Invalid indices are reported as being out of
742 // range.
743 STRING_INDEX_IS_ARRAY_INDEX
744};
745
746
747// Generates code implementing String.prototype.charCodeAt.
748//
749// Only supports the case when the receiver is a string and the index
750// is a number (smi or heap number) that is a valid index into the
751// string. Additional index constraints are specified by the
752// flags. Otherwise, bails out to the provided labels.
753//
754// Register usage: |object| may be changed to another string in a way
755// that doesn't affect charCodeAt/charAt semantics, |index| is
756// preserved, |scratch| and |result| are clobbered.
757class StringCharCodeAtGenerator {
758 public:
759 StringCharCodeAtGenerator(Register object,
760 Register index,
761 Register scratch,
762 Register result,
763 Label* receiver_not_string,
764 Label* index_not_number,
765 Label* index_out_of_range,
766 StringIndexFlags index_flags)
767 : object_(object),
768 index_(index),
769 scratch_(scratch),
770 result_(result),
771 receiver_not_string_(receiver_not_string),
772 index_not_number_(index_not_number),
773 index_out_of_range_(index_out_of_range),
774 index_flags_(index_flags) {
775 ASSERT(!scratch_.is(object_));
776 ASSERT(!scratch_.is(index_));
777 ASSERT(!scratch_.is(result_));
778 ASSERT(!result_.is(object_));
779 ASSERT(!result_.is(index_));
780 }
781
782 // Generates the fast case code. On the fallthrough path |result|
783 // register contains the result.
784 void GenerateFast(MacroAssembler* masm);
785
786 // Generates the slow case code. Must not be naturally
787 // reachable. Expected to be put after a ret instruction (e.g., in
788 // deferred code). Always jumps back to the fast case.
789 void GenerateSlow(MacroAssembler* masm,
790 const RuntimeCallHelper& call_helper);
791
792 private:
793 Register object_;
794 Register index_;
795 Register scratch_;
796 Register result_;
797
798 Label* receiver_not_string_;
799 Label* index_not_number_;
800 Label* index_out_of_range_;
801
802 StringIndexFlags index_flags_;
803
804 Label call_runtime_;
805 Label index_not_smi_;
806 Label got_smi_index_;
807 Label exit_;
808
809 DISALLOW_COPY_AND_ASSIGN(StringCharCodeAtGenerator);
810};
811
812
813// Generates code for creating a one-char string from a char code.
814class StringCharFromCodeGenerator {
815 public:
816 StringCharFromCodeGenerator(Register code,
817 Register result)
818 : code_(code),
819 result_(result) {
820 ASSERT(!code_.is(result_));
821 }
822
823 // Generates the fast case code. On the fallthrough path |result|
824 // register contains the result.
825 void GenerateFast(MacroAssembler* masm);
826
827 // Generates the slow case code. Must not be naturally
828 // reachable. Expected to be put after a ret instruction (e.g., in
829 // deferred code). Always jumps back to the fast case.
830 void GenerateSlow(MacroAssembler* masm,
831 const RuntimeCallHelper& call_helper);
832
833 private:
834 Register code_;
835 Register result_;
836
837 Label slow_case_;
838 Label exit_;
839
840 DISALLOW_COPY_AND_ASSIGN(StringCharFromCodeGenerator);
841};
842
843
844// Generates code implementing String.prototype.charAt.
845//
846// Only supports the case when the receiver is a string and the index
847// is a number (smi or heap number) that is a valid index into the
848// string. Additional index constraints are specified by the
849// flags. Otherwise, bails out to the provided labels.
850//
851// Register usage: |object| may be changed to another string in a way
852// that doesn't affect charCodeAt/charAt semantics, |index| is
853// preserved, |scratch1|, |scratch2|, and |result| are clobbered.
854class StringCharAtGenerator {
855 public:
856 StringCharAtGenerator(Register object,
857 Register index,
858 Register scratch1,
859 Register scratch2,
860 Register result,
861 Label* receiver_not_string,
862 Label* index_not_number,
863 Label* index_out_of_range,
864 StringIndexFlags index_flags)
865 : char_code_at_generator_(object,
866 index,
867 scratch1,
868 scratch2,
869 receiver_not_string,
870 index_not_number,
871 index_out_of_range,
872 index_flags),
873 char_from_code_generator_(scratch2, result) {}
874
875 // Generates the fast case code. On the fallthrough path |result|
876 // register contains the result.
877 void GenerateFast(MacroAssembler* masm);
878
879 // Generates the slow case code. Must not be naturally
880 // reachable. Expected to be put after a ret instruction (e.g., in
881 // deferred code). Always jumps back to the fast case.
882 void GenerateSlow(MacroAssembler* masm,
883 const RuntimeCallHelper& call_helper);
884
885 private:
886 StringCharCodeAtGenerator char_code_at_generator_;
887 StringCharFromCodeGenerator char_from_code_generator_;
888
889 DISALLOW_COPY_AND_ASSIGN(StringCharAtGenerator);
890};
891
892
Steve Blocka7e24c12009-10-30 11:49:00 +0000893} // namespace internal
894} // namespace v8
895
896#endif // V8_CODEGEN_H_