blob: 76cc4914e7bd028323463611c4a98d8fa02ac010 [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
58// GenCode
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
184
185// RuntimeStub models code stubs calling entry points in the Runtime class.
186class RuntimeStub : public CodeStub {
187 public:
188 explicit RuntimeStub(Runtime::FunctionId id, int num_arguments)
189 : id_(id), num_arguments_(num_arguments) { }
190
191 void Generate(MacroAssembler* masm);
192
193 // Disassembler support. It is useful to be able to print the name
194 // of the runtime function called through this stub.
195 static const char* GetNameFromMinorKey(int minor_key) {
196 return Runtime::FunctionForId(IdField::decode(minor_key))->stub_name;
197 }
198
199 private:
200 Runtime::FunctionId id_;
201 int num_arguments_;
202
203 class ArgumentField: public BitField<int, 0, 16> {};
204 class IdField: public BitField<Runtime::FunctionId, 16, kMinorBits - 16> {};
205
206 Major MajorKey() { return Runtime; }
207 int MinorKey() {
208 return IdField::encode(id_) | ArgumentField::encode(num_arguments_);
209 }
210
211 const char* GetName();
212
213#ifdef DEBUG
214 void Print() {
215 PrintF("RuntimeStub (id %s)\n", Runtime::FunctionForId(id_)->name);
216 }
217#endif
218};
219
220
221class StackCheckStub : public CodeStub {
222 public:
223 StackCheckStub() { }
224
225 void Generate(MacroAssembler* masm);
226
227 private:
228
229 const char* GetName() { return "StackCheckStub"; }
230
231 Major MajorKey() { return StackCheck; }
232 int MinorKey() { return 0; }
233};
234
235
Leon Clarkee46be812010-01-19 14:06:41 +0000236class FastNewClosureStub : public CodeStub {
237 public:
238 void Generate(MacroAssembler* masm);
239
240 private:
241 const char* GetName() { return "FastNewClosureStub"; }
242 Major MajorKey() { return FastNewClosure; }
243 int MinorKey() { return 0; }
244};
245
246
247class FastNewContextStub : public CodeStub {
248 public:
249 static const int kMaximumSlots = 64;
250
251 explicit FastNewContextStub(int slots) : slots_(slots) {
252 ASSERT(slots_ > 0 && slots <= kMaximumSlots);
253 }
254
255 void Generate(MacroAssembler* masm);
256
257 private:
258 int slots_;
259
260 const char* GetName() { return "FastNewContextStub"; }
261 Major MajorKey() { return FastNewContext; }
262 int MinorKey() { return slots_; }
263};
264
265
266class FastCloneShallowArrayStub : public CodeStub {
267 public:
268 static const int kMaximumLength = 8;
269
270 explicit FastCloneShallowArrayStub(int length) : length_(length) {
271 ASSERT(length >= 0 && length <= kMaximumLength);
272 }
273
274 void Generate(MacroAssembler* masm);
275
276 private:
277 int length_;
278
279 const char* GetName() { return "FastCloneShallowArrayStub"; }
280 Major MajorKey() { return FastCloneShallowArray; }
281 int MinorKey() { return length_; }
282};
283
284
Steve Blocka7e24c12009-10-30 11:49:00 +0000285class InstanceofStub: public CodeStub {
286 public:
287 InstanceofStub() { }
288
289 void Generate(MacroAssembler* masm);
290
291 private:
292 Major MajorKey() { return Instanceof; }
293 int MinorKey() { return 0; }
294};
295
296
Leon Clarkee46be812010-01-19 14:06:41 +0000297class GenericUnaryOpStub : public CodeStub {
Steve Blocka7e24c12009-10-30 11:49:00 +0000298 public:
Leon Clarkee46be812010-01-19 14:06:41 +0000299 GenericUnaryOpStub(Token::Value op, bool overwrite)
300 : op_(op), overwrite_(overwrite) { }
Steve Blocka7e24c12009-10-30 11:49:00 +0000301
302 private:
Leon Clarkee46be812010-01-19 14:06:41 +0000303 Token::Value op_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000304 bool overwrite_;
Leon Clarkee46be812010-01-19 14:06:41 +0000305
306 class OverwriteField: public BitField<int, 0, 1> {};
307 class OpField: public BitField<Token::Value, 1, kMinorBits - 1> {};
308
309 Major MajorKey() { return GenericUnaryOp; }
310 int MinorKey() {
311 return OpField::encode(op_) | OverwriteField::encode(overwrite_);
312 }
313
Steve Blocka7e24c12009-10-30 11:49:00 +0000314 void Generate(MacroAssembler* masm);
315
Leon Clarkee46be812010-01-19 14:06:41 +0000316 const char* GetName();
317};
318
319
320enum NaNInformation {
321 kBothCouldBeNaN,
322 kCantBothBeNaN
Steve Blocka7e24c12009-10-30 11:49:00 +0000323};
324
325
326class CompareStub: public CodeStub {
327 public:
Leon Clarkee46be812010-01-19 14:06:41 +0000328 CompareStub(Condition cc,
329 bool strict,
330 NaNInformation nan_info = kBothCouldBeNaN) :
331 cc_(cc), strict_(strict), never_nan_nan_(nan_info == kCantBothBeNaN) { }
Steve Blocka7e24c12009-10-30 11:49:00 +0000332
333 void Generate(MacroAssembler* masm);
334
335 private:
336 Condition cc_;
337 bool strict_;
Leon Clarkee46be812010-01-19 14:06:41 +0000338 // Only used for 'equal' comparisons. Tells the stub that we already know
339 // that at least one side of the comparison is not NaN. This allows the
340 // stub to use object identity in the positive case. We ignore it when
341 // generating the minor key for other comparisons to avoid creating more
342 // stubs.
343 bool never_nan_nan_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000344
345 Major MajorKey() { return Compare; }
346
347 int MinorKey();
348
349 // Branch to the label if the given object isn't a symbol.
350 void BranchIfNonSymbol(MacroAssembler* masm,
351 Label* label,
352 Register object,
353 Register scratch);
354
Leon Clarkee46be812010-01-19 14:06:41 +0000355 // Unfortunately you have to run without snapshots to see most of these
356 // names in the profile since most compare stubs end up in the snapshot.
357 const char* GetName();
Steve Blocka7e24c12009-10-30 11:49:00 +0000358#ifdef DEBUG
359 void Print() {
360 PrintF("CompareStub (cc %d), (strict %s)\n",
361 static_cast<int>(cc_),
362 strict_ ? "true" : "false");
363 }
364#endif
365};
366
367
368class CEntryStub : public CodeStub {
369 public:
370 explicit CEntryStub(int result_size) : result_size_(result_size) { }
371
372 void Generate(MacroAssembler* masm) { GenerateBody(masm, false); }
373
374 protected:
375 void GenerateBody(MacroAssembler* masm, bool is_debug_break);
376 void GenerateCore(MacroAssembler* masm,
377 Label* throw_normal_exception,
378 Label* throw_termination_exception,
379 Label* throw_out_of_memory_exception,
Steve Blockd0582a62009-12-15 09:54:21 +0000380 ExitFrame::Mode mode,
Steve Blocka7e24c12009-10-30 11:49:00 +0000381 bool do_gc,
382 bool always_allocate_scope);
383 void GenerateThrowTOS(MacroAssembler* masm);
384 void GenerateThrowUncatchable(MacroAssembler* masm,
385 UncatchableExceptionType type);
386 private:
387 // Number of pointers/values returned.
388 int result_size_;
389
390 Major MajorKey() { return CEntry; }
391 // Minor key must differ if different result_size_ values means different
392 // code is generated.
393 int MinorKey();
394
395 const char* GetName() { return "CEntryStub"; }
396};
397
398
Steve Blockd0582a62009-12-15 09:54:21 +0000399class ApiGetterEntryStub : public CodeStub {
400 public:
401 ApiGetterEntryStub(Handle<AccessorInfo> info,
402 ApiFunction* fun)
403 : info_(info),
404 fun_(fun) { }
405 void Generate(MacroAssembler* masm);
406 virtual bool has_custom_cache() { return true; }
407 virtual bool GetCustomCache(Code** code_out);
408 virtual void SetCustomCache(Code* value);
409
410 static const int kStackSpace = 6;
411 static const int kArgc = 4;
412 private:
413 Handle<AccessorInfo> info() { return info_; }
414 ApiFunction* fun() { return fun_; }
415 Major MajorKey() { return NoCache; }
416 int MinorKey() { return 0; }
417 const char* GetName() { return "ApiEntryStub"; }
418 // The accessor info associated with the function.
419 Handle<AccessorInfo> info_;
420 // The function to be called.
421 ApiFunction* fun_;
422};
423
424
Steve Blocka7e24c12009-10-30 11:49:00 +0000425class CEntryDebugBreakStub : public CEntryStub {
426 public:
427 CEntryDebugBreakStub() : CEntryStub(1) { }
428
429 void Generate(MacroAssembler* masm) { GenerateBody(masm, true); }
430
431 private:
432 int MinorKey() { return 1; }
433
434 const char* GetName() { return "CEntryDebugBreakStub"; }
435};
436
437
438class JSEntryStub : public CodeStub {
439 public:
440 JSEntryStub() { }
441
442 void Generate(MacroAssembler* masm) { GenerateBody(masm, false); }
443
444 protected:
445 void GenerateBody(MacroAssembler* masm, bool is_construct);
446
447 private:
448 Major MajorKey() { return JSEntry; }
449 int MinorKey() { return 0; }
450
451 const char* GetName() { return "JSEntryStub"; }
452};
453
454
455class JSConstructEntryStub : public JSEntryStub {
456 public:
457 JSConstructEntryStub() { }
458
459 void Generate(MacroAssembler* masm) { GenerateBody(masm, true); }
460
461 private:
462 int MinorKey() { return 1; }
463
464 const char* GetName() { return "JSConstructEntryStub"; }
465};
466
467
468class ArgumentsAccessStub: public CodeStub {
469 public:
470 enum Type {
471 READ_LENGTH,
472 READ_ELEMENT,
473 NEW_OBJECT
474 };
475
476 explicit ArgumentsAccessStub(Type type) : type_(type) { }
477
478 private:
479 Type type_;
480
481 Major MajorKey() { return ArgumentsAccess; }
482 int MinorKey() { return type_; }
483
484 void Generate(MacroAssembler* masm);
485 void GenerateReadLength(MacroAssembler* masm);
486 void GenerateReadElement(MacroAssembler* masm);
487 void GenerateNewObject(MacroAssembler* masm);
488
489 const char* GetName() { return "ArgumentsAccessStub"; }
490
491#ifdef DEBUG
492 void Print() {
493 PrintF("ArgumentsAccessStub (type %d)\n", type_);
494 }
495#endif
496};
497
498
Leon Clarkee46be812010-01-19 14:06:41 +0000499class RegExpExecStub: public CodeStub {
500 public:
501 RegExpExecStub() { }
502
503 private:
504 Major MajorKey() { return RegExpExec; }
505 int MinorKey() { return 0; }
506
507 void Generate(MacroAssembler* masm);
508
509 const char* GetName() { return "RegExpExecStub"; }
510
511#ifdef DEBUG
512 void Print() {
513 PrintF("RegExpExecStub\n");
514 }
515#endif
516};
517
518
519class CallFunctionStub: public CodeStub {
520 public:
521 CallFunctionStub(int argc, InLoopFlag in_loop, CallFunctionFlags flags)
522 : argc_(argc), in_loop_(in_loop), flags_(flags) { }
523
524 void Generate(MacroAssembler* masm);
525
526 private:
527 int argc_;
528 InLoopFlag in_loop_;
529 CallFunctionFlags flags_;
530
531#ifdef DEBUG
532 void Print() {
533 PrintF("CallFunctionStub (args %d, in_loop %d, flags %d)\n",
534 argc_,
535 static_cast<int>(in_loop_),
536 static_cast<int>(flags_));
537 }
538#endif
539
540 // Minor key encoding in 31 bits AAAAAAAAAAAAAAAAAAAAAFI A(rgs)F(lag)I(nloop).
541 class InLoopBits: public BitField<InLoopFlag, 0, 1> {};
542 class FlagBits: public BitField<CallFunctionFlags, 1, 1> {};
543 class ArgcBits: public BitField<int, 2, 29> {};
544
545 Major MajorKey() { return CallFunction; }
546 int MinorKey() {
547 // Encode the parameters in a unique 31 bit value.
548 return InLoopBits::encode(in_loop_)
549 | FlagBits::encode(flags_)
550 | ArgcBits::encode(argc_);
551 }
552
553 InLoopFlag InLoop() { return in_loop_; }
554 bool ReceiverMightBeValue() {
555 return (flags_ & RECEIVER_MIGHT_BE_VALUE) != 0;
556 }
557
558 public:
559 static int ExtractArgcFromMinorKey(int minor_key) {
560 return ArgcBits::decode(minor_key);
561 }
562};
563
564
565class ToBooleanStub: public CodeStub {
566 public:
567 ToBooleanStub() { }
568
569 void Generate(MacroAssembler* masm);
570
571 private:
572 Major MajorKey() { return ToBoolean; }
573 int MinorKey() { return 0; }
574};
575
576
Steve Blocka7e24c12009-10-30 11:49:00 +0000577} // namespace internal
578} // namespace v8
579
580#endif // V8_CODEGEN_H_