blob: 3afa04146c887a8d335c76d28172592fad3e4973 [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"
Andrei Popescu31002712010-02-23 13:46:05 +000089#elif V8_TARGET_ARCH_MIPS
90#include "mips/codegen-mips.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000091#else
92#error Unsupported target architecture.
93#endif
94
95#include "register-allocator.h"
96
97namespace v8 {
98namespace internal {
99
100
Andrei Popescu31002712010-02-23 13:46:05 +0000101// Support for "structured" code comments.
102#ifdef DEBUG
103
104class Comment BASE_EMBEDDED {
105 public:
106 Comment(MacroAssembler* masm, const char* msg);
107 ~Comment();
108
109 private:
110 MacroAssembler* masm_;
111 const char* msg_;
112};
113
114#else
115
116class Comment BASE_EMBEDDED {
117 public:
118 Comment(MacroAssembler*, const char*) {}
119};
120
121#endif // DEBUG
122
123
Steve Blocka7e24c12009-10-30 11:49:00 +0000124// Code generation can be nested. Code generation scopes form a stack
125// of active code generators.
126class CodeGeneratorScope BASE_EMBEDDED {
127 public:
128 explicit CodeGeneratorScope(CodeGenerator* cgen) {
129 previous_ = top_;
130 top_ = cgen;
131 }
132
133 ~CodeGeneratorScope() {
134 top_ = previous_;
135 }
136
137 static CodeGenerator* Current() {
138 ASSERT(top_ != NULL);
139 return top_;
140 }
141
142 private:
143 static CodeGenerator* top_;
144 CodeGenerator* previous_;
145};
146
147
148// Deferred code objects are small pieces of code that are compiled
149// out of line. They are used to defer the compilation of uncommon
150// paths thereby avoiding expensive jumps around uncommon code parts.
151class DeferredCode: public ZoneObject {
152 public:
153 DeferredCode();
154 virtual ~DeferredCode() { }
155
156 virtual void Generate() = 0;
157
158 MacroAssembler* masm() { return masm_; }
159
160 int statement_position() const { return statement_position_; }
161 int position() const { return position_; }
162
163 Label* entry_label() { return &entry_label_; }
164 Label* exit_label() { return &exit_label_; }
165
166#ifdef DEBUG
167 void set_comment(const char* comment) { comment_ = comment; }
168 const char* comment() const { return comment_; }
169#else
170 void set_comment(const char* comment) { }
171 const char* comment() const { return ""; }
172#endif
173
174 inline void Jump();
175 inline void Branch(Condition cc);
176 void BindExit() { masm_->bind(&exit_label_); }
177
178 void SaveRegisters();
179 void RestoreRegisters();
180
181 protected:
182 MacroAssembler* masm_;
183
184 private:
185 // Constants indicating special actions. They should not be multiples
186 // of kPointerSize so they will not collide with valid offsets from
187 // the frame pointer.
188 static const int kIgnore = -1;
189 static const int kPush = 1;
190
191 // This flag is ored with a valid offset from the frame pointer, so
192 // it should fit in the low zero bits of a valid offset.
193 static const int kSyncedFlag = 2;
194
195 int statement_position_;
196 int position_;
197
198 Label entry_label_;
199 Label exit_label_;
200
201 int registers_[RegisterAllocator::kNumRegisters];
202
203#ifdef DEBUG
204 const char* comment_;
205#endif
206 DISALLOW_COPY_AND_ASSIGN(DeferredCode);
207};
208
Steve Blocka7e24c12009-10-30 11:49:00 +0000209class StackCheckStub : public CodeStub {
210 public:
211 StackCheckStub() { }
212
213 void Generate(MacroAssembler* masm);
214
215 private:
216
217 const char* GetName() { return "StackCheckStub"; }
218
219 Major MajorKey() { return StackCheck; }
220 int MinorKey() { return 0; }
221};
222
223
Leon Clarkee46be812010-01-19 14:06:41 +0000224class FastNewClosureStub : public CodeStub {
225 public:
226 void Generate(MacroAssembler* masm);
227
228 private:
229 const char* GetName() { return "FastNewClosureStub"; }
230 Major MajorKey() { return FastNewClosure; }
231 int MinorKey() { return 0; }
232};
233
234
235class FastNewContextStub : public CodeStub {
236 public:
237 static const int kMaximumSlots = 64;
238
239 explicit FastNewContextStub(int slots) : slots_(slots) {
240 ASSERT(slots_ > 0 && slots <= kMaximumSlots);
241 }
242
243 void Generate(MacroAssembler* masm);
244
245 private:
246 int slots_;
247
248 const char* GetName() { return "FastNewContextStub"; }
249 Major MajorKey() { return FastNewContext; }
250 int MinorKey() { return slots_; }
251};
252
253
254class FastCloneShallowArrayStub : public CodeStub {
255 public:
256 static const int kMaximumLength = 8;
257
258 explicit FastCloneShallowArrayStub(int length) : length_(length) {
259 ASSERT(length >= 0 && length <= kMaximumLength);
260 }
261
262 void Generate(MacroAssembler* masm);
263
264 private:
265 int length_;
266
267 const char* GetName() { return "FastCloneShallowArrayStub"; }
268 Major MajorKey() { return FastCloneShallowArray; }
269 int MinorKey() { return length_; }
270};
271
272
Steve Blocka7e24c12009-10-30 11:49:00 +0000273class InstanceofStub: public CodeStub {
274 public:
275 InstanceofStub() { }
276
277 void Generate(MacroAssembler* masm);
278
279 private:
280 Major MajorKey() { return Instanceof; }
281 int MinorKey() { return 0; }
282};
283
284
Leon Clarkee46be812010-01-19 14:06:41 +0000285class GenericUnaryOpStub : public CodeStub {
Steve Blocka7e24c12009-10-30 11:49:00 +0000286 public:
Leon Clarkee46be812010-01-19 14:06:41 +0000287 GenericUnaryOpStub(Token::Value op, bool overwrite)
288 : op_(op), overwrite_(overwrite) { }
Steve Blocka7e24c12009-10-30 11:49:00 +0000289
290 private:
Leon Clarkee46be812010-01-19 14:06:41 +0000291 Token::Value op_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000292 bool overwrite_;
Leon Clarkee46be812010-01-19 14:06:41 +0000293
294 class OverwriteField: public BitField<int, 0, 1> {};
295 class OpField: public BitField<Token::Value, 1, kMinorBits - 1> {};
296
297 Major MajorKey() { return GenericUnaryOp; }
298 int MinorKey() {
299 return OpField::encode(op_) | OverwriteField::encode(overwrite_);
300 }
301
Steve Blocka7e24c12009-10-30 11:49:00 +0000302 void Generate(MacroAssembler* masm);
303
Leon Clarkee46be812010-01-19 14:06:41 +0000304 const char* GetName();
305};
306
307
308enum NaNInformation {
309 kBothCouldBeNaN,
310 kCantBothBeNaN
Steve Blocka7e24c12009-10-30 11:49:00 +0000311};
312
313
314class CompareStub: public CodeStub {
315 public:
Leon Clarkee46be812010-01-19 14:06:41 +0000316 CompareStub(Condition cc,
317 bool strict,
318 NaNInformation nan_info = kBothCouldBeNaN) :
319 cc_(cc), strict_(strict), never_nan_nan_(nan_info == kCantBothBeNaN) { }
Steve Blocka7e24c12009-10-30 11:49:00 +0000320
321 void Generate(MacroAssembler* masm);
322
323 private:
324 Condition cc_;
325 bool strict_;
Leon Clarkee46be812010-01-19 14:06:41 +0000326 // Only used for 'equal' comparisons. Tells the stub that we already know
327 // that at least one side of the comparison is not NaN. This allows the
328 // stub to use object identity in the positive case. We ignore it when
329 // generating the minor key for other comparisons to avoid creating more
330 // stubs.
331 bool never_nan_nan_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000332
333 Major MajorKey() { return Compare; }
334
335 int MinorKey();
336
337 // Branch to the label if the given object isn't a symbol.
338 void BranchIfNonSymbol(MacroAssembler* masm,
339 Label* label,
340 Register object,
341 Register scratch);
342
Leon Clarkee46be812010-01-19 14:06:41 +0000343 // Unfortunately you have to run without snapshots to see most of these
344 // names in the profile since most compare stubs end up in the snapshot.
345 const char* GetName();
Steve Blocka7e24c12009-10-30 11:49:00 +0000346#ifdef DEBUG
347 void Print() {
348 PrintF("CompareStub (cc %d), (strict %s)\n",
349 static_cast<int>(cc_),
350 strict_ ? "true" : "false");
351 }
352#endif
353};
354
355
356class CEntryStub : public CodeStub {
357 public:
Leon Clarke4515c472010-02-03 11:58:03 +0000358 explicit CEntryStub(int result_size,
359 ExitFrame::Mode mode = ExitFrame::MODE_NORMAL)
360 : result_size_(result_size), mode_(mode) { }
Steve Blocka7e24c12009-10-30 11:49:00 +0000361
Leon Clarke4515c472010-02-03 11:58:03 +0000362 void Generate(MacroAssembler* masm);
Steve Blocka7e24c12009-10-30 11:49:00 +0000363
Leon Clarke4515c472010-02-03 11:58:03 +0000364 private:
Steve Blocka7e24c12009-10-30 11:49:00 +0000365 void GenerateCore(MacroAssembler* masm,
366 Label* throw_normal_exception,
367 Label* throw_termination_exception,
368 Label* throw_out_of_memory_exception,
Steve Blocka7e24c12009-10-30 11:49:00 +0000369 bool do_gc,
370 bool always_allocate_scope);
371 void GenerateThrowTOS(MacroAssembler* masm);
372 void GenerateThrowUncatchable(MacroAssembler* masm,
373 UncatchableExceptionType type);
Leon Clarke4515c472010-02-03 11:58:03 +0000374
Steve Blocka7e24c12009-10-30 11:49:00 +0000375 // Number of pointers/values returned.
Leon Clarke4515c472010-02-03 11:58:03 +0000376 const int result_size_;
377 const ExitFrame::Mode mode_;
378
379 // Minor key encoding
380 class ExitFrameModeBits: public BitField<ExitFrame::Mode, 0, 1> {};
381 class IndirectResultBits: public BitField<bool, 1, 1> {};
Steve Blocka7e24c12009-10-30 11:49:00 +0000382
383 Major MajorKey() { return CEntry; }
384 // Minor key must differ if different result_size_ values means different
385 // code is generated.
386 int MinorKey();
387
388 const char* GetName() { return "CEntryStub"; }
389};
390
391
Steve Blockd0582a62009-12-15 09:54:21 +0000392class ApiGetterEntryStub : public CodeStub {
393 public:
394 ApiGetterEntryStub(Handle<AccessorInfo> info,
395 ApiFunction* fun)
396 : info_(info),
397 fun_(fun) { }
398 void Generate(MacroAssembler* masm);
399 virtual bool has_custom_cache() { return true; }
400 virtual bool GetCustomCache(Code** code_out);
401 virtual void SetCustomCache(Code* value);
402
403 static const int kStackSpace = 6;
404 static const int kArgc = 4;
405 private:
406 Handle<AccessorInfo> info() { return info_; }
407 ApiFunction* fun() { return fun_; }
408 Major MajorKey() { return NoCache; }
409 int MinorKey() { return 0; }
410 const char* GetName() { return "ApiEntryStub"; }
411 // The accessor info associated with the function.
412 Handle<AccessorInfo> info_;
413 // The function to be called.
414 ApiFunction* fun_;
415};
416
417
Leon Clarke4515c472010-02-03 11:58:03 +0000418// Mark the debugger statement to be recognized by debugger (by the MajorKey)
419class DebuggerStatementStub : public CodeStub {
Steve Blocka7e24c12009-10-30 11:49:00 +0000420 public:
Leon Clarke4515c472010-02-03 11:58:03 +0000421 DebuggerStatementStub() { }
Steve Blocka7e24c12009-10-30 11:49:00 +0000422
Leon Clarke4515c472010-02-03 11:58:03 +0000423 void Generate(MacroAssembler* masm);
Steve Blocka7e24c12009-10-30 11:49:00 +0000424
425 private:
Leon Clarke4515c472010-02-03 11:58:03 +0000426 Major MajorKey() { return DebuggerStatement; }
427 int MinorKey() { return 0; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000428
Leon Clarke4515c472010-02-03 11:58:03 +0000429 const char* GetName() { return "DebuggerStatementStub"; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000430};
431
432
433class JSEntryStub : public CodeStub {
434 public:
435 JSEntryStub() { }
436
437 void Generate(MacroAssembler* masm) { GenerateBody(masm, false); }
438
439 protected:
440 void GenerateBody(MacroAssembler* masm, bool is_construct);
441
442 private:
443 Major MajorKey() { return JSEntry; }
444 int MinorKey() { return 0; }
445
446 const char* GetName() { return "JSEntryStub"; }
447};
448
449
450class JSConstructEntryStub : public JSEntryStub {
451 public:
452 JSConstructEntryStub() { }
453
454 void Generate(MacroAssembler* masm) { GenerateBody(masm, true); }
455
456 private:
457 int MinorKey() { return 1; }
458
459 const char* GetName() { return "JSConstructEntryStub"; }
460};
461
462
463class ArgumentsAccessStub: public CodeStub {
464 public:
465 enum Type {
466 READ_LENGTH,
467 READ_ELEMENT,
468 NEW_OBJECT
469 };
470
471 explicit ArgumentsAccessStub(Type type) : type_(type) { }
472
473 private:
474 Type type_;
475
476 Major MajorKey() { return ArgumentsAccess; }
477 int MinorKey() { return type_; }
478
479 void Generate(MacroAssembler* masm);
480 void GenerateReadLength(MacroAssembler* masm);
481 void GenerateReadElement(MacroAssembler* masm);
482 void GenerateNewObject(MacroAssembler* masm);
483
484 const char* GetName() { return "ArgumentsAccessStub"; }
485
486#ifdef DEBUG
487 void Print() {
488 PrintF("ArgumentsAccessStub (type %d)\n", type_);
489 }
490#endif
491};
492
493
Leon Clarkee46be812010-01-19 14:06:41 +0000494class RegExpExecStub: public CodeStub {
495 public:
496 RegExpExecStub() { }
497
498 private:
499 Major MajorKey() { return RegExpExec; }
500 int MinorKey() { return 0; }
501
502 void Generate(MacroAssembler* masm);
503
504 const char* GetName() { return "RegExpExecStub"; }
505
506#ifdef DEBUG
507 void Print() {
508 PrintF("RegExpExecStub\n");
509 }
510#endif
511};
512
513
514class CallFunctionStub: public CodeStub {
515 public:
516 CallFunctionStub(int argc, InLoopFlag in_loop, CallFunctionFlags flags)
517 : argc_(argc), in_loop_(in_loop), flags_(flags) { }
518
519 void Generate(MacroAssembler* masm);
520
521 private:
522 int argc_;
523 InLoopFlag in_loop_;
524 CallFunctionFlags flags_;
525
526#ifdef DEBUG
527 void Print() {
528 PrintF("CallFunctionStub (args %d, in_loop %d, flags %d)\n",
529 argc_,
530 static_cast<int>(in_loop_),
531 static_cast<int>(flags_));
532 }
533#endif
534
535 // Minor key encoding in 31 bits AAAAAAAAAAAAAAAAAAAAAFI A(rgs)F(lag)I(nloop).
536 class InLoopBits: public BitField<InLoopFlag, 0, 1> {};
537 class FlagBits: public BitField<CallFunctionFlags, 1, 1> {};
538 class ArgcBits: public BitField<int, 2, 29> {};
539
540 Major MajorKey() { return CallFunction; }
541 int MinorKey() {
542 // Encode the parameters in a unique 31 bit value.
543 return InLoopBits::encode(in_loop_)
544 | FlagBits::encode(flags_)
545 | ArgcBits::encode(argc_);
546 }
547
548 InLoopFlag InLoop() { return in_loop_; }
549 bool ReceiverMightBeValue() {
550 return (flags_ & RECEIVER_MIGHT_BE_VALUE) != 0;
551 }
552
553 public:
554 static int ExtractArgcFromMinorKey(int minor_key) {
555 return ArgcBits::decode(minor_key);
556 }
557};
558
559
560class ToBooleanStub: public CodeStub {
561 public:
562 ToBooleanStub() { }
563
564 void Generate(MacroAssembler* masm);
565
566 private:
567 Major MajorKey() { return ToBoolean; }
568 int MinorKey() { return 0; }
569};
570
571
Steve Blocka7e24c12009-10-30 11:49:00 +0000572} // namespace internal
573} // namespace v8
574
575#endif // V8_CODEGEN_H_