blob: 8dcde84bbd74c25ee6c07aa7e6290d6c06a6de2f [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"
Andrei Popescu402d9372010-02-26 13:31:12 +000034#include "number-info.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000035
36// Include the declaration of the architecture defined class CodeGenerator.
37// The contract to the shared code is that the the CodeGenerator is a subclass
38// of Visitor and that the following methods are available publicly:
39// MakeCode
Steve Block3ce2e202009-11-05 08:53:23 +000040// MakeCodePrologue
41// MakeCodeEpilogue
Steve Blocka7e24c12009-10-30 11:49:00 +000042// masm
43// frame
Steve Blockd0582a62009-12-15 09:54:21 +000044// script
Steve Blocka7e24c12009-10-30 11:49:00 +000045// has_valid_frame
46// SetFrame
47// DeleteFrame
48// allocator
49// AddDeferred
50// in_spilled_code
51// set_in_spilled_code
Steve Block3ce2e202009-11-05 08:53:23 +000052// RecordPositions
Steve Blocka7e24c12009-10-30 11:49:00 +000053//
54// These methods are either used privately by the shared code or implemented as
55// shared code:
56// CodeGenerator
57// ~CodeGenerator
58// ProcessDeferred
Leon Clarke4515c472010-02-03 11:58:03 +000059// Generate
Steve Block3ce2e202009-11-05 08:53:23 +000060// ComputeLazyCompile
Steve Blocka7e24c12009-10-30 11:49:00 +000061// BuildBoilerplate
62// ComputeCallInitialize
63// ComputeCallInitializeInLoop
64// ProcessDeclarations
65// DeclareGlobals
66// FindInlineRuntimeLUT
67// CheckForInlineRuntimeCall
68// PatchInlineRuntimeEntry
Steve Block3ce2e202009-11-05 08:53:23 +000069// AnalyzeCondition
Steve Blocka7e24c12009-10-30 11:49:00 +000070// CodeForFunctionPosition
71// CodeForReturnPosition
72// CodeForStatementPosition
Steve Blockd0582a62009-12-15 09:54:21 +000073// CodeForDoWhileConditionPosition
Steve Blocka7e24c12009-10-30 11:49:00 +000074// CodeForSourcePosition
75
76
77// Mode to overwrite BinaryExpression values.
78enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
79
80// Types of uncatchable exceptions.
81enum UncatchableExceptionType { OUT_OF_MEMORY, TERMINATION };
82
83
84#if V8_TARGET_ARCH_IA32
85#include "ia32/codegen-ia32.h"
86#elif V8_TARGET_ARCH_X64
87#include "x64/codegen-x64.h"
88#elif V8_TARGET_ARCH_ARM
89#include "arm/codegen-arm.h"
Andrei Popescu31002712010-02-23 13:46:05 +000090#elif V8_TARGET_ARCH_MIPS
91#include "mips/codegen-mips.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000092#else
93#error Unsupported target architecture.
94#endif
95
96#include "register-allocator.h"
97
98namespace v8 {
99namespace internal {
100
101
Andrei Popescu31002712010-02-23 13:46:05 +0000102// Support for "structured" code comments.
103#ifdef DEBUG
104
105class Comment BASE_EMBEDDED {
106 public:
107 Comment(MacroAssembler* masm, const char* msg);
108 ~Comment();
109
110 private:
111 MacroAssembler* masm_;
112 const char* msg_;
113};
114
115#else
116
117class Comment BASE_EMBEDDED {
118 public:
119 Comment(MacroAssembler*, const char*) {}
120};
121
122#endif // DEBUG
123
124
Steve Blocka7e24c12009-10-30 11:49:00 +0000125// Code generation can be nested. Code generation scopes form a stack
126// of active code generators.
127class CodeGeneratorScope BASE_EMBEDDED {
128 public:
129 explicit CodeGeneratorScope(CodeGenerator* cgen) {
130 previous_ = top_;
131 top_ = cgen;
132 }
133
134 ~CodeGeneratorScope() {
135 top_ = previous_;
136 }
137
138 static CodeGenerator* Current() {
139 ASSERT(top_ != NULL);
140 return top_;
141 }
142
143 private:
144 static CodeGenerator* top_;
145 CodeGenerator* previous_;
146};
147
148
149// Deferred code objects are small pieces of code that are compiled
150// out of line. They are used to defer the compilation of uncommon
151// paths thereby avoiding expensive jumps around uncommon code parts.
152class DeferredCode: public ZoneObject {
153 public:
154 DeferredCode();
155 virtual ~DeferredCode() { }
156
157 virtual void Generate() = 0;
158
159 MacroAssembler* masm() { return masm_; }
160
161 int statement_position() const { return statement_position_; }
162 int position() const { return position_; }
163
164 Label* entry_label() { return &entry_label_; }
165 Label* exit_label() { return &exit_label_; }
166
167#ifdef DEBUG
168 void set_comment(const char* comment) { comment_ = comment; }
169 const char* comment() const { return comment_; }
170#else
171 void set_comment(const char* comment) { }
172 const char* comment() const { return ""; }
173#endif
174
175 inline void Jump();
176 inline void Branch(Condition cc);
177 void BindExit() { masm_->bind(&exit_label_); }
178
179 void SaveRegisters();
180 void RestoreRegisters();
181
182 protected:
183 MacroAssembler* masm_;
184
185 private:
186 // Constants indicating special actions. They should not be multiples
187 // of kPointerSize so they will not collide with valid offsets from
188 // the frame pointer.
189 static const int kIgnore = -1;
190 static const int kPush = 1;
191
192 // This flag is ored with a valid offset from the frame pointer, so
193 // it should fit in the low zero bits of a valid offset.
194 static const int kSyncedFlag = 2;
195
196 int statement_position_;
197 int position_;
198
199 Label entry_label_;
200 Label exit_label_;
201
202 int registers_[RegisterAllocator::kNumRegisters];
203
204#ifdef DEBUG
205 const char* comment_;
206#endif
207 DISALLOW_COPY_AND_ASSIGN(DeferredCode);
208};
209
Steve Blocka7e24c12009-10-30 11:49:00 +0000210class StackCheckStub : public CodeStub {
211 public:
212 StackCheckStub() { }
213
214 void Generate(MacroAssembler* masm);
215
216 private:
217
218 const char* GetName() { return "StackCheckStub"; }
219
220 Major MajorKey() { return StackCheck; }
221 int MinorKey() { return 0; }
222};
223
224
Leon Clarkee46be812010-01-19 14:06:41 +0000225class FastNewClosureStub : public CodeStub {
226 public:
227 void Generate(MacroAssembler* masm);
228
229 private:
230 const char* GetName() { return "FastNewClosureStub"; }
231 Major MajorKey() { return FastNewClosure; }
232 int MinorKey() { return 0; }
233};
234
235
236class FastNewContextStub : public CodeStub {
237 public:
238 static const int kMaximumSlots = 64;
239
240 explicit FastNewContextStub(int slots) : slots_(slots) {
241 ASSERT(slots_ > 0 && slots <= kMaximumSlots);
242 }
243
244 void Generate(MacroAssembler* masm);
245
246 private:
247 int slots_;
248
249 const char* GetName() { return "FastNewContextStub"; }
250 Major MajorKey() { return FastNewContext; }
251 int MinorKey() { return slots_; }
252};
253
254
255class FastCloneShallowArrayStub : public CodeStub {
256 public:
257 static const int kMaximumLength = 8;
258
259 explicit FastCloneShallowArrayStub(int length) : length_(length) {
260 ASSERT(length >= 0 && length <= kMaximumLength);
261 }
262
263 void Generate(MacroAssembler* masm);
264
265 private:
266 int length_;
267
268 const char* GetName() { return "FastCloneShallowArrayStub"; }
269 Major MajorKey() { return FastCloneShallowArray; }
270 int MinorKey() { return length_; }
271};
272
273
Steve Blocka7e24c12009-10-30 11:49:00 +0000274class InstanceofStub: public CodeStub {
275 public:
276 InstanceofStub() { }
277
278 void Generate(MacroAssembler* masm);
279
280 private:
281 Major MajorKey() { return Instanceof; }
282 int MinorKey() { return 0; }
283};
284
285
Leon Clarkee46be812010-01-19 14:06:41 +0000286class GenericUnaryOpStub : public CodeStub {
Steve Blocka7e24c12009-10-30 11:49:00 +0000287 public:
Leon Clarkee46be812010-01-19 14:06:41 +0000288 GenericUnaryOpStub(Token::Value op, bool overwrite)
289 : op_(op), overwrite_(overwrite) { }
Steve Blocka7e24c12009-10-30 11:49:00 +0000290
291 private:
Leon Clarkee46be812010-01-19 14:06:41 +0000292 Token::Value op_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000293 bool overwrite_;
Leon Clarkee46be812010-01-19 14:06:41 +0000294
295 class OverwriteField: public BitField<int, 0, 1> {};
296 class OpField: public BitField<Token::Value, 1, kMinorBits - 1> {};
297
298 Major MajorKey() { return GenericUnaryOp; }
299 int MinorKey() {
300 return OpField::encode(op_) | OverwriteField::encode(overwrite_);
301 }
302
Steve Blocka7e24c12009-10-30 11:49:00 +0000303 void Generate(MacroAssembler* masm);
304
Leon Clarkee46be812010-01-19 14:06:41 +0000305 const char* GetName();
306};
307
308
309enum NaNInformation {
310 kBothCouldBeNaN,
311 kCantBothBeNaN
Steve Blocka7e24c12009-10-30 11:49:00 +0000312};
313
314
315class CompareStub: public CodeStub {
316 public:
Leon Clarkee46be812010-01-19 14:06:41 +0000317 CompareStub(Condition cc,
318 bool strict,
319 NaNInformation nan_info = kBothCouldBeNaN) :
320 cc_(cc), strict_(strict), never_nan_nan_(nan_info == kCantBothBeNaN) { }
Steve Blocka7e24c12009-10-30 11:49:00 +0000321
322 void Generate(MacroAssembler* masm);
323
324 private:
325 Condition cc_;
326 bool strict_;
Leon Clarkee46be812010-01-19 14:06:41 +0000327 // Only used for 'equal' comparisons. Tells the stub that we already know
328 // that at least one side of the comparison is not NaN. This allows the
329 // stub to use object identity in the positive case. We ignore it when
330 // generating the minor key for other comparisons to avoid creating more
331 // stubs.
332 bool never_nan_nan_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000333
334 Major MajorKey() { return Compare; }
335
336 int MinorKey();
337
338 // Branch to the label if the given object isn't a symbol.
339 void BranchIfNonSymbol(MacroAssembler* masm,
340 Label* label,
341 Register object,
342 Register scratch);
343
Leon Clarkee46be812010-01-19 14:06:41 +0000344 // Unfortunately you have to run without snapshots to see most of these
345 // names in the profile since most compare stubs end up in the snapshot.
346 const char* GetName();
Steve Blocka7e24c12009-10-30 11:49:00 +0000347#ifdef DEBUG
348 void Print() {
349 PrintF("CompareStub (cc %d), (strict %s)\n",
350 static_cast<int>(cc_),
351 strict_ ? "true" : "false");
352 }
353#endif
354};
355
356
357class CEntryStub : public CodeStub {
358 public:
Leon Clarke4515c472010-02-03 11:58:03 +0000359 explicit CEntryStub(int result_size,
360 ExitFrame::Mode mode = ExitFrame::MODE_NORMAL)
361 : result_size_(result_size), mode_(mode) { }
Steve Blocka7e24c12009-10-30 11:49:00 +0000362
Leon Clarke4515c472010-02-03 11:58:03 +0000363 void Generate(MacroAssembler* masm);
Steve Blocka7e24c12009-10-30 11:49:00 +0000364
Leon Clarke4515c472010-02-03 11:58:03 +0000365 private:
Steve Blocka7e24c12009-10-30 11:49:00 +0000366 void GenerateCore(MacroAssembler* masm,
367 Label* throw_normal_exception,
368 Label* throw_termination_exception,
369 Label* throw_out_of_memory_exception,
Steve Blocka7e24c12009-10-30 11:49:00 +0000370 bool do_gc,
371 bool always_allocate_scope);
372 void GenerateThrowTOS(MacroAssembler* masm);
373 void GenerateThrowUncatchable(MacroAssembler* masm,
374 UncatchableExceptionType type);
Leon Clarke4515c472010-02-03 11:58:03 +0000375
Steve Blocka7e24c12009-10-30 11:49:00 +0000376 // Number of pointers/values returned.
Leon Clarke4515c472010-02-03 11:58:03 +0000377 const int result_size_;
378 const ExitFrame::Mode mode_;
379
380 // Minor key encoding
381 class ExitFrameModeBits: public BitField<ExitFrame::Mode, 0, 1> {};
382 class IndirectResultBits: public BitField<bool, 1, 1> {};
Steve Blocka7e24c12009-10-30 11:49:00 +0000383
384 Major MajorKey() { return CEntry; }
385 // Minor key must differ if different result_size_ values means different
386 // code is generated.
387 int MinorKey();
388
389 const char* GetName() { return "CEntryStub"; }
390};
391
392
Steve Blockd0582a62009-12-15 09:54:21 +0000393class ApiGetterEntryStub : public CodeStub {
394 public:
395 ApiGetterEntryStub(Handle<AccessorInfo> info,
396 ApiFunction* fun)
397 : info_(info),
398 fun_(fun) { }
399 void Generate(MacroAssembler* masm);
400 virtual bool has_custom_cache() { return true; }
401 virtual bool GetCustomCache(Code** code_out);
402 virtual void SetCustomCache(Code* value);
403
404 static const int kStackSpace = 6;
405 static const int kArgc = 4;
406 private:
407 Handle<AccessorInfo> info() { return info_; }
408 ApiFunction* fun() { return fun_; }
409 Major MajorKey() { return NoCache; }
410 int MinorKey() { return 0; }
411 const char* GetName() { return "ApiEntryStub"; }
412 // The accessor info associated with the function.
413 Handle<AccessorInfo> info_;
414 // The function to be called.
415 ApiFunction* fun_;
416};
417
418
Steve Blocka7e24c12009-10-30 11:49:00 +0000419class JSEntryStub : public CodeStub {
420 public:
421 JSEntryStub() { }
422
423 void Generate(MacroAssembler* masm) { GenerateBody(masm, false); }
424
425 protected:
426 void GenerateBody(MacroAssembler* masm, bool is_construct);
427
428 private:
429 Major MajorKey() { return JSEntry; }
430 int MinorKey() { return 0; }
431
432 const char* GetName() { return "JSEntryStub"; }
433};
434
435
436class JSConstructEntryStub : public JSEntryStub {
437 public:
438 JSConstructEntryStub() { }
439
440 void Generate(MacroAssembler* masm) { GenerateBody(masm, true); }
441
442 private:
443 int MinorKey() { return 1; }
444
445 const char* GetName() { return "JSConstructEntryStub"; }
446};
447
448
449class ArgumentsAccessStub: public CodeStub {
450 public:
451 enum Type {
452 READ_LENGTH,
453 READ_ELEMENT,
454 NEW_OBJECT
455 };
456
457 explicit ArgumentsAccessStub(Type type) : type_(type) { }
458
459 private:
460 Type type_;
461
462 Major MajorKey() { return ArgumentsAccess; }
463 int MinorKey() { return type_; }
464
465 void Generate(MacroAssembler* masm);
466 void GenerateReadLength(MacroAssembler* masm);
467 void GenerateReadElement(MacroAssembler* masm);
468 void GenerateNewObject(MacroAssembler* masm);
469
470 const char* GetName() { return "ArgumentsAccessStub"; }
471
472#ifdef DEBUG
473 void Print() {
474 PrintF("ArgumentsAccessStub (type %d)\n", type_);
475 }
476#endif
477};
478
479
Leon Clarkee46be812010-01-19 14:06:41 +0000480class RegExpExecStub: public CodeStub {
481 public:
482 RegExpExecStub() { }
483
484 private:
485 Major MajorKey() { return RegExpExec; }
486 int MinorKey() { return 0; }
487
488 void Generate(MacroAssembler* masm);
489
490 const char* GetName() { return "RegExpExecStub"; }
491
492#ifdef DEBUG
493 void Print() {
494 PrintF("RegExpExecStub\n");
495 }
496#endif
497};
498
499
500class CallFunctionStub: public CodeStub {
501 public:
502 CallFunctionStub(int argc, InLoopFlag in_loop, CallFunctionFlags flags)
503 : argc_(argc), in_loop_(in_loop), flags_(flags) { }
504
505 void Generate(MacroAssembler* masm);
506
507 private:
508 int argc_;
509 InLoopFlag in_loop_;
510 CallFunctionFlags flags_;
511
512#ifdef DEBUG
513 void Print() {
514 PrintF("CallFunctionStub (args %d, in_loop %d, flags %d)\n",
515 argc_,
516 static_cast<int>(in_loop_),
517 static_cast<int>(flags_));
518 }
519#endif
520
Andrei Popescu402d9372010-02-26 13:31:12 +0000521 // Minor key encoding in 32 bits with Bitfield <Type, shift, size>.
Leon Clarkee46be812010-01-19 14:06:41 +0000522 class InLoopBits: public BitField<InLoopFlag, 0, 1> {};
523 class FlagBits: public BitField<CallFunctionFlags, 1, 1> {};
Andrei Popescu402d9372010-02-26 13:31:12 +0000524 class ArgcBits: public BitField<int, 2, 32 - 2> {};
Leon Clarkee46be812010-01-19 14:06:41 +0000525
526 Major MajorKey() { return CallFunction; }
527 int MinorKey() {
Andrei Popescu402d9372010-02-26 13:31:12 +0000528 // Encode the parameters in a unique 32 bit value.
Leon Clarkee46be812010-01-19 14:06:41 +0000529 return InLoopBits::encode(in_loop_)
530 | FlagBits::encode(flags_)
531 | ArgcBits::encode(argc_);
532 }
533
534 InLoopFlag InLoop() { return in_loop_; }
535 bool ReceiverMightBeValue() {
536 return (flags_ & RECEIVER_MIGHT_BE_VALUE) != 0;
537 }
538
539 public:
540 static int ExtractArgcFromMinorKey(int minor_key) {
541 return ArgcBits::decode(minor_key);
542 }
543};
544
545
546class ToBooleanStub: public CodeStub {
547 public:
548 ToBooleanStub() { }
549
550 void Generate(MacroAssembler* masm);
551
552 private:
553 Major MajorKey() { return ToBoolean; }
554 int MinorKey() { return 0; }
555};
556
557
Steve Blocka7e24c12009-10-30 11:49:00 +0000558} // namespace internal
559} // namespace v8
560
561#endif // V8_CODEGEN_H_