blob: d0be5f1b1cb378ad636ba815d586503e6054e157 [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
31#include "ast.h"
32#include "code-stubs.h"
33#include "runtime.h"
34
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 Blocka7e24c12009-10-30 11:49:00 +000060// BuildBoilerplate
61// 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 };
78
79// Types of uncatchable exceptions.
80enum UncatchableExceptionType { OUT_OF_MEMORY, TERMINATION };
81
82
83#if V8_TARGET_ARCH_IA32
84#include "ia32/codegen-ia32.h"
85#elif V8_TARGET_ARCH_X64
86#include "x64/codegen-x64.h"
87#elif V8_TARGET_ARCH_ARM
88#include "arm/codegen-arm.h"
89#else
90#error Unsupported target architecture.
91#endif
92
93#include "register-allocator.h"
94
95namespace v8 {
96namespace internal {
97
98
99// Code generation can be nested. Code generation scopes form a stack
100// of active code generators.
101class CodeGeneratorScope BASE_EMBEDDED {
102 public:
103 explicit CodeGeneratorScope(CodeGenerator* cgen) {
104 previous_ = top_;
105 top_ = cgen;
106 }
107
108 ~CodeGeneratorScope() {
109 top_ = previous_;
110 }
111
112 static CodeGenerator* Current() {
113 ASSERT(top_ != NULL);
114 return top_;
115 }
116
117 private:
118 static CodeGenerator* top_;
119 CodeGenerator* previous_;
120};
121
122
123// Deferred code objects are small pieces of code that are compiled
124// out of line. They are used to defer the compilation of uncommon
125// paths thereby avoiding expensive jumps around uncommon code parts.
126class DeferredCode: public ZoneObject {
127 public:
128 DeferredCode();
129 virtual ~DeferredCode() { }
130
131 virtual void Generate() = 0;
132
133 MacroAssembler* masm() { return masm_; }
134
135 int statement_position() const { return statement_position_; }
136 int position() const { return position_; }
137
138 Label* entry_label() { return &entry_label_; }
139 Label* exit_label() { return &exit_label_; }
140
141#ifdef DEBUG
142 void set_comment(const char* comment) { comment_ = comment; }
143 const char* comment() const { return comment_; }
144#else
145 void set_comment(const char* comment) { }
146 const char* comment() const { return ""; }
147#endif
148
149 inline void Jump();
150 inline void Branch(Condition cc);
151 void BindExit() { masm_->bind(&exit_label_); }
152
153 void SaveRegisters();
154 void RestoreRegisters();
155
156 protected:
157 MacroAssembler* masm_;
158
159 private:
160 // Constants indicating special actions. They should not be multiples
161 // of kPointerSize so they will not collide with valid offsets from
162 // the frame pointer.
163 static const int kIgnore = -1;
164 static const int kPush = 1;
165
166 // This flag is ored with a valid offset from the frame pointer, so
167 // it should fit in the low zero bits of a valid offset.
168 static const int kSyncedFlag = 2;
169
170 int statement_position_;
171 int position_;
172
173 Label entry_label_;
174 Label exit_label_;
175
176 int registers_[RegisterAllocator::kNumRegisters];
177
178#ifdef DEBUG
179 const char* comment_;
180#endif
181 DISALLOW_COPY_AND_ASSIGN(DeferredCode);
182};
183
Steve Blocka7e24c12009-10-30 11:49:00 +0000184class StackCheckStub : public CodeStub {
185 public:
186 StackCheckStub() { }
187
188 void Generate(MacroAssembler* masm);
189
190 private:
191
192 const char* GetName() { return "StackCheckStub"; }
193
194 Major MajorKey() { return StackCheck; }
195 int MinorKey() { return 0; }
196};
197
198
Leon Clarkee46be812010-01-19 14:06:41 +0000199class FastNewClosureStub : public CodeStub {
200 public:
201 void Generate(MacroAssembler* masm);
202
203 private:
204 const char* GetName() { return "FastNewClosureStub"; }
205 Major MajorKey() { return FastNewClosure; }
206 int MinorKey() { return 0; }
207};
208
209
210class FastNewContextStub : public CodeStub {
211 public:
212 static const int kMaximumSlots = 64;
213
214 explicit FastNewContextStub(int slots) : slots_(slots) {
215 ASSERT(slots_ > 0 && slots <= kMaximumSlots);
216 }
217
218 void Generate(MacroAssembler* masm);
219
220 private:
221 int slots_;
222
223 const char* GetName() { return "FastNewContextStub"; }
224 Major MajorKey() { return FastNewContext; }
225 int MinorKey() { return slots_; }
226};
227
228
229class FastCloneShallowArrayStub : public CodeStub {
230 public:
231 static const int kMaximumLength = 8;
232
233 explicit FastCloneShallowArrayStub(int length) : length_(length) {
234 ASSERT(length >= 0 && length <= kMaximumLength);
235 }
236
237 void Generate(MacroAssembler* masm);
238
239 private:
240 int length_;
241
242 const char* GetName() { return "FastCloneShallowArrayStub"; }
243 Major MajorKey() { return FastCloneShallowArray; }
244 int MinorKey() { return length_; }
245};
246
247
Steve Blocka7e24c12009-10-30 11:49:00 +0000248class InstanceofStub: public CodeStub {
249 public:
250 InstanceofStub() { }
251
252 void Generate(MacroAssembler* masm);
253
254 private:
255 Major MajorKey() { return Instanceof; }
256 int MinorKey() { return 0; }
257};
258
259
Leon Clarkee46be812010-01-19 14:06:41 +0000260class GenericUnaryOpStub : public CodeStub {
Steve Blocka7e24c12009-10-30 11:49:00 +0000261 public:
Leon Clarkee46be812010-01-19 14:06:41 +0000262 GenericUnaryOpStub(Token::Value op, bool overwrite)
263 : op_(op), overwrite_(overwrite) { }
Steve Blocka7e24c12009-10-30 11:49:00 +0000264
265 private:
Leon Clarkee46be812010-01-19 14:06:41 +0000266 Token::Value op_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000267 bool overwrite_;
Leon Clarkee46be812010-01-19 14:06:41 +0000268
269 class OverwriteField: public BitField<int, 0, 1> {};
270 class OpField: public BitField<Token::Value, 1, kMinorBits - 1> {};
271
272 Major MajorKey() { return GenericUnaryOp; }
273 int MinorKey() {
274 return OpField::encode(op_) | OverwriteField::encode(overwrite_);
275 }
276
Steve Blocka7e24c12009-10-30 11:49:00 +0000277 void Generate(MacroAssembler* masm);
278
Leon Clarkee46be812010-01-19 14:06:41 +0000279 const char* GetName();
280};
281
282
283enum NaNInformation {
284 kBothCouldBeNaN,
285 kCantBothBeNaN
Steve Blocka7e24c12009-10-30 11:49:00 +0000286};
287
288
289class CompareStub: public CodeStub {
290 public:
Leon Clarkee46be812010-01-19 14:06:41 +0000291 CompareStub(Condition cc,
292 bool strict,
293 NaNInformation nan_info = kBothCouldBeNaN) :
294 cc_(cc), strict_(strict), never_nan_nan_(nan_info == kCantBothBeNaN) { }
Steve Blocka7e24c12009-10-30 11:49:00 +0000295
296 void Generate(MacroAssembler* masm);
297
298 private:
299 Condition cc_;
300 bool strict_;
Leon Clarkee46be812010-01-19 14:06:41 +0000301 // Only used for 'equal' comparisons. Tells the stub that we already know
302 // that at least one side of the comparison is not NaN. This allows the
303 // stub to use object identity in the positive case. We ignore it when
304 // generating the minor key for other comparisons to avoid creating more
305 // stubs.
306 bool never_nan_nan_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000307
308 Major MajorKey() { return Compare; }
309
310 int MinorKey();
311
312 // Branch to the label if the given object isn't a symbol.
313 void BranchIfNonSymbol(MacroAssembler* masm,
314 Label* label,
315 Register object,
316 Register scratch);
317
Leon Clarkee46be812010-01-19 14:06:41 +0000318 // Unfortunately you have to run without snapshots to see most of these
319 // names in the profile since most compare stubs end up in the snapshot.
320 const char* GetName();
Steve Blocka7e24c12009-10-30 11:49:00 +0000321#ifdef DEBUG
322 void Print() {
323 PrintF("CompareStub (cc %d), (strict %s)\n",
324 static_cast<int>(cc_),
325 strict_ ? "true" : "false");
326 }
327#endif
328};
329
330
331class CEntryStub : public CodeStub {
332 public:
Leon Clarke4515c472010-02-03 11:58:03 +0000333 explicit CEntryStub(int result_size,
334 ExitFrame::Mode mode = ExitFrame::MODE_NORMAL)
335 : result_size_(result_size), mode_(mode) { }
Steve Blocka7e24c12009-10-30 11:49:00 +0000336
Leon Clarke4515c472010-02-03 11:58:03 +0000337 void Generate(MacroAssembler* masm);
Steve Blocka7e24c12009-10-30 11:49:00 +0000338
Leon Clarke4515c472010-02-03 11:58:03 +0000339 private:
Steve Blocka7e24c12009-10-30 11:49:00 +0000340 void GenerateCore(MacroAssembler* masm,
341 Label* throw_normal_exception,
342 Label* throw_termination_exception,
343 Label* throw_out_of_memory_exception,
Steve Blocka7e24c12009-10-30 11:49:00 +0000344 bool do_gc,
345 bool always_allocate_scope);
346 void GenerateThrowTOS(MacroAssembler* masm);
347 void GenerateThrowUncatchable(MacroAssembler* masm,
348 UncatchableExceptionType type);
Leon Clarke4515c472010-02-03 11:58:03 +0000349
Steve Blocka7e24c12009-10-30 11:49:00 +0000350 // Number of pointers/values returned.
Leon Clarke4515c472010-02-03 11:58:03 +0000351 const int result_size_;
352 const ExitFrame::Mode mode_;
353
354 // Minor key encoding
355 class ExitFrameModeBits: public BitField<ExitFrame::Mode, 0, 1> {};
356 class IndirectResultBits: public BitField<bool, 1, 1> {};
Steve Blocka7e24c12009-10-30 11:49:00 +0000357
358 Major MajorKey() { return CEntry; }
359 // Minor key must differ if different result_size_ values means different
360 // code is generated.
361 int MinorKey();
362
363 const char* GetName() { return "CEntryStub"; }
364};
365
366
Steve Blockd0582a62009-12-15 09:54:21 +0000367class ApiGetterEntryStub : public CodeStub {
368 public:
369 ApiGetterEntryStub(Handle<AccessorInfo> info,
370 ApiFunction* fun)
371 : info_(info),
372 fun_(fun) { }
373 void Generate(MacroAssembler* masm);
374 virtual bool has_custom_cache() { return true; }
375 virtual bool GetCustomCache(Code** code_out);
376 virtual void SetCustomCache(Code* value);
377
378 static const int kStackSpace = 6;
379 static const int kArgc = 4;
380 private:
381 Handle<AccessorInfo> info() { return info_; }
382 ApiFunction* fun() { return fun_; }
383 Major MajorKey() { return NoCache; }
384 int MinorKey() { return 0; }
385 const char* GetName() { return "ApiEntryStub"; }
386 // The accessor info associated with the function.
387 Handle<AccessorInfo> info_;
388 // The function to be called.
389 ApiFunction* fun_;
390};
391
392
Leon Clarke4515c472010-02-03 11:58:03 +0000393// Mark the debugger statement to be recognized by debugger (by the MajorKey)
394class DebuggerStatementStub : public CodeStub {
Steve Blocka7e24c12009-10-30 11:49:00 +0000395 public:
Leon Clarke4515c472010-02-03 11:58:03 +0000396 DebuggerStatementStub() { }
Steve Blocka7e24c12009-10-30 11:49:00 +0000397
Leon Clarke4515c472010-02-03 11:58:03 +0000398 void Generate(MacroAssembler* masm);
Steve Blocka7e24c12009-10-30 11:49:00 +0000399
400 private:
Leon Clarke4515c472010-02-03 11:58:03 +0000401 Major MajorKey() { return DebuggerStatement; }
402 int MinorKey() { return 0; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000403
Leon Clarke4515c472010-02-03 11:58:03 +0000404 const char* GetName() { return "DebuggerStatementStub"; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000405};
406
407
408class JSEntryStub : public CodeStub {
409 public:
410 JSEntryStub() { }
411
412 void Generate(MacroAssembler* masm) { GenerateBody(masm, false); }
413
414 protected:
415 void GenerateBody(MacroAssembler* masm, bool is_construct);
416
417 private:
418 Major MajorKey() { return JSEntry; }
419 int MinorKey() { return 0; }
420
421 const char* GetName() { return "JSEntryStub"; }
422};
423
424
425class JSConstructEntryStub : public JSEntryStub {
426 public:
427 JSConstructEntryStub() { }
428
429 void Generate(MacroAssembler* masm) { GenerateBody(masm, true); }
430
431 private:
432 int MinorKey() { return 1; }
433
434 const char* GetName() { return "JSConstructEntryStub"; }
435};
436
437
438class ArgumentsAccessStub: public CodeStub {
439 public:
440 enum Type {
441 READ_LENGTH,
442 READ_ELEMENT,
443 NEW_OBJECT
444 };
445
446 explicit ArgumentsAccessStub(Type type) : type_(type) { }
447
448 private:
449 Type type_;
450
451 Major MajorKey() { return ArgumentsAccess; }
452 int MinorKey() { return type_; }
453
454 void Generate(MacroAssembler* masm);
455 void GenerateReadLength(MacroAssembler* masm);
456 void GenerateReadElement(MacroAssembler* masm);
457 void GenerateNewObject(MacroAssembler* masm);
458
459 const char* GetName() { return "ArgumentsAccessStub"; }
460
461#ifdef DEBUG
462 void Print() {
463 PrintF("ArgumentsAccessStub (type %d)\n", type_);
464 }
465#endif
466};
467
468
Leon Clarkee46be812010-01-19 14:06:41 +0000469class RegExpExecStub: public CodeStub {
470 public:
471 RegExpExecStub() { }
472
473 private:
474 Major MajorKey() { return RegExpExec; }
475 int MinorKey() { return 0; }
476
477 void Generate(MacroAssembler* masm);
478
479 const char* GetName() { return "RegExpExecStub"; }
480
481#ifdef DEBUG
482 void Print() {
483 PrintF("RegExpExecStub\n");
484 }
485#endif
486};
487
488
489class CallFunctionStub: public CodeStub {
490 public:
491 CallFunctionStub(int argc, InLoopFlag in_loop, CallFunctionFlags flags)
492 : argc_(argc), in_loop_(in_loop), flags_(flags) { }
493
494 void Generate(MacroAssembler* masm);
495
496 private:
497 int argc_;
498 InLoopFlag in_loop_;
499 CallFunctionFlags flags_;
500
501#ifdef DEBUG
502 void Print() {
503 PrintF("CallFunctionStub (args %d, in_loop %d, flags %d)\n",
504 argc_,
505 static_cast<int>(in_loop_),
506 static_cast<int>(flags_));
507 }
508#endif
509
510 // Minor key encoding in 31 bits AAAAAAAAAAAAAAAAAAAAAFI A(rgs)F(lag)I(nloop).
511 class InLoopBits: public BitField<InLoopFlag, 0, 1> {};
512 class FlagBits: public BitField<CallFunctionFlags, 1, 1> {};
513 class ArgcBits: public BitField<int, 2, 29> {};
514
515 Major MajorKey() { return CallFunction; }
516 int MinorKey() {
517 // Encode the parameters in a unique 31 bit value.
518 return InLoopBits::encode(in_loop_)
519 | FlagBits::encode(flags_)
520 | ArgcBits::encode(argc_);
521 }
522
523 InLoopFlag InLoop() { return in_loop_; }
524 bool ReceiverMightBeValue() {
525 return (flags_ & RECEIVER_MIGHT_BE_VALUE) != 0;
526 }
527
528 public:
529 static int ExtractArgcFromMinorKey(int minor_key) {
530 return ArgcBits::decode(minor_key);
531 }
532};
533
534
535class ToBooleanStub: public CodeStub {
536 public:
537 ToBooleanStub() { }
538
539 void Generate(MacroAssembler* masm);
540
541 private:
542 Major MajorKey() { return ToBoolean; }
543 int MinorKey() { return 0; }
544};
545
546
Steve Blocka7e24c12009-10-30 11:49:00 +0000547} // namespace internal
548} // namespace v8
549
550#endif // V8_CODEGEN_H_