• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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 #include "number-info.h"
35 
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
40 //   MakeCodePrologue
41 //   MakeCodeEpilogue
42 //   masm
43 //   frame
44 //   script
45 //   has_valid_frame
46 //   SetFrame
47 //   DeleteFrame
48 //   allocator
49 //   AddDeferred
50 //   in_spilled_code
51 //   set_in_spilled_code
52 //   RecordPositions
53 //
54 // These methods are either used privately by the shared code or implemented as
55 // shared code:
56 //   CodeGenerator
57 //   ~CodeGenerator
58 //   ProcessDeferred
59 //   Generate
60 //   ComputeLazyCompile
61 //   BuildBoilerplate
62 //   ComputeCallInitialize
63 //   ComputeCallInitializeInLoop
64 //   ProcessDeclarations
65 //   DeclareGlobals
66 //   FindInlineRuntimeLUT
67 //   CheckForInlineRuntimeCall
68 //   PatchInlineRuntimeEntry
69 //   AnalyzeCondition
70 //   CodeForFunctionPosition
71 //   CodeForReturnPosition
72 //   CodeForStatementPosition
73 //   CodeForDoWhileConditionPosition
74 //   CodeForSourcePosition
75 
76 
77 // Mode to overwrite BinaryExpression values.
78 enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
79 
80 // Types of uncatchable exceptions.
81 enum 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"
90 #elif V8_TARGET_ARCH_MIPS
91 #include "mips/codegen-mips.h"
92 #else
93 #error Unsupported target architecture.
94 #endif
95 
96 #include "register-allocator.h"
97 
98 namespace v8 {
99 namespace internal {
100 
101 
102 // Support for "structured" code comments.
103 #ifdef DEBUG
104 
105 class 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 
117 class Comment BASE_EMBEDDED {
118  public:
119   Comment(MacroAssembler*, const char*)  {}
120 };
121 
122 #endif  // DEBUG
123 
124 
125 // Code generation can be nested.  Code generation scopes form a stack
126 // of active code generators.
127 class CodeGeneratorScope BASE_EMBEDDED {
128  public:
CodeGeneratorScope(CodeGenerator * cgen)129   explicit CodeGeneratorScope(CodeGenerator* cgen) {
130     previous_ = top_;
131     top_ = cgen;
132   }
133 
~CodeGeneratorScope()134   ~CodeGeneratorScope() {
135     top_ = previous_;
136   }
137 
Current()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.
152 class DeferredCode: public ZoneObject {
153  public:
154   DeferredCode();
~DeferredCode()155   virtual ~DeferredCode() { }
156 
157   virtual void Generate() = 0;
158 
masm()159   MacroAssembler* masm() { return masm_; }
160 
statement_position()161   int statement_position() const { return statement_position_; }
position()162   int position() const { return position_; }
163 
entry_label()164   Label* entry_label() { return &entry_label_; }
exit_label()165   Label* exit_label() { return &exit_label_; }
166 
167 #ifdef DEBUG
set_comment(const char * comment)168   void set_comment(const char* comment) { comment_ = comment; }
comment()169   const char* comment() const { return comment_; }
170 #else
set_comment(const char * comment)171   void set_comment(const char* comment) { }
comment()172   const char* comment() const { return ""; }
173 #endif
174 
175   inline void Jump();
176   inline void Branch(Condition cc);
BindExit()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 
210 class StackCheckStub : public CodeStub {
211  public:
StackCheckStub()212   StackCheckStub() { }
213 
214   void Generate(MacroAssembler* masm);
215 
216  private:
217 
GetName()218   const char* GetName() { return "StackCheckStub"; }
219 
MajorKey()220   Major MajorKey() { return StackCheck; }
MinorKey()221   int MinorKey() { return 0; }
222 };
223 
224 
225 class FastNewClosureStub : public CodeStub {
226  public:
227   void Generate(MacroAssembler* masm);
228 
229  private:
GetName()230   const char* GetName() { return "FastNewClosureStub"; }
MajorKey()231   Major MajorKey() { return FastNewClosure; }
MinorKey()232   int MinorKey() { return 0; }
233 };
234 
235 
236 class FastNewContextStub : public CodeStub {
237  public:
238   static const int kMaximumSlots = 64;
239 
FastNewContextStub(int slots)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 
GetName()249   const char* GetName() { return "FastNewContextStub"; }
MajorKey()250   Major MajorKey() { return FastNewContext; }
MinorKey()251   int MinorKey() { return slots_; }
252 };
253 
254 
255 class FastCloneShallowArrayStub : public CodeStub {
256  public:
257   static const int kMaximumLength = 8;
258 
FastCloneShallowArrayStub(int length)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 
GetName()268   const char* GetName() { return "FastCloneShallowArrayStub"; }
MajorKey()269   Major MajorKey() { return FastCloneShallowArray; }
MinorKey()270   int MinorKey() { return length_; }
271 };
272 
273 
274 class InstanceofStub: public CodeStub {
275  public:
InstanceofStub()276   InstanceofStub() { }
277 
278   void Generate(MacroAssembler* masm);
279 
280  private:
MajorKey()281   Major MajorKey() { return Instanceof; }
MinorKey()282   int MinorKey() { return 0; }
283 };
284 
285 
286 class GenericUnaryOpStub : public CodeStub {
287  public:
GenericUnaryOpStub(Token::Value op,bool overwrite)288   GenericUnaryOpStub(Token::Value op, bool overwrite)
289       : op_(op), overwrite_(overwrite) { }
290 
291  private:
292   Token::Value op_;
293   bool overwrite_;
294 
295   class OverwriteField: public BitField<int, 0, 1> {};
296   class OpField: public BitField<Token::Value, 1, kMinorBits - 1> {};
297 
MajorKey()298   Major MajorKey() { return GenericUnaryOp; }
MinorKey()299   int MinorKey() {
300     return OpField::encode(op_) | OverwriteField::encode(overwrite_);
301   }
302 
303   void Generate(MacroAssembler* masm);
304 
305   const char* GetName();
306 };
307 
308 
309 enum NaNInformation {
310   kBothCouldBeNaN,
311   kCantBothBeNaN
312 };
313 
314 
315 class CompareStub: public CodeStub {
316  public:
317   CompareStub(Condition cc,
318               bool strict,
319               NaNInformation nan_info = kBothCouldBeNaN) :
cc_(cc)320       cc_(cc), strict_(strict), never_nan_nan_(nan_info == kCantBothBeNaN) { }
321 
322   void Generate(MacroAssembler* masm);
323 
324  private:
325   Condition cc_;
326   bool strict_;
327   // 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_;
333 
MajorKey()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 
344   // 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();
347 #ifdef DEBUG
Print()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 
357 class CEntryStub : public CodeStub {
358  public:
359   explicit CEntryStub(int result_size,
360                       ExitFrame::Mode mode = ExitFrame::MODE_NORMAL)
result_size_(result_size)361       : result_size_(result_size), mode_(mode) { }
362 
363   void Generate(MacroAssembler* masm);
364 
365  private:
366   void GenerateCore(MacroAssembler* masm,
367                     Label* throw_normal_exception,
368                     Label* throw_termination_exception,
369                     Label* throw_out_of_memory_exception,
370                     bool do_gc,
371                     bool always_allocate_scope);
372   void GenerateThrowTOS(MacroAssembler* masm);
373   void GenerateThrowUncatchable(MacroAssembler* masm,
374                                 UncatchableExceptionType type);
375 
376   // Number of pointers/values returned.
377   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> {};
383 
MajorKey()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 
GetName()389   const char* GetName() { return "CEntryStub"; }
390 };
391 
392 
393 class ApiGetterEntryStub : public CodeStub {
394  public:
ApiGetterEntryStub(Handle<AccessorInfo> info,ApiFunction * fun)395   ApiGetterEntryStub(Handle<AccessorInfo> info,
396                      ApiFunction* fun)
397       : info_(info),
398         fun_(fun) { }
399   void Generate(MacroAssembler* masm);
has_custom_cache()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:
info()407   Handle<AccessorInfo> info() { return info_; }
fun()408   ApiFunction* fun() { return fun_; }
MajorKey()409   Major MajorKey() { return NoCache; }
MinorKey()410   int MinorKey() { return 0; }
GetName()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 
419 class JSEntryStub : public CodeStub {
420  public:
JSEntryStub()421   JSEntryStub() { }
422 
Generate(MacroAssembler * masm)423   void Generate(MacroAssembler* masm) { GenerateBody(masm, false); }
424 
425  protected:
426   void GenerateBody(MacroAssembler* masm, bool is_construct);
427 
428  private:
MajorKey()429   Major MajorKey() { return JSEntry; }
MinorKey()430   int MinorKey() { return 0; }
431 
GetName()432   const char* GetName() { return "JSEntryStub"; }
433 };
434 
435 
436 class JSConstructEntryStub : public JSEntryStub {
437  public:
JSConstructEntryStub()438   JSConstructEntryStub() { }
439 
Generate(MacroAssembler * masm)440   void Generate(MacroAssembler* masm) { GenerateBody(masm, true); }
441 
442  private:
MinorKey()443   int MinorKey() { return 1; }
444 
GetName()445   const char* GetName() { return "JSConstructEntryStub"; }
446 };
447 
448 
449 class ArgumentsAccessStub: public CodeStub {
450  public:
451   enum Type {
452     READ_LENGTH,
453     READ_ELEMENT,
454     NEW_OBJECT
455   };
456 
ArgumentsAccessStub(Type type)457   explicit ArgumentsAccessStub(Type type) : type_(type) { }
458 
459  private:
460   Type type_;
461 
MajorKey()462   Major MajorKey() { return ArgumentsAccess; }
MinorKey()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 
GetName()470   const char* GetName() { return "ArgumentsAccessStub"; }
471 
472 #ifdef DEBUG
Print()473   void Print() {
474     PrintF("ArgumentsAccessStub (type %d)\n", type_);
475   }
476 #endif
477 };
478 
479 
480 class RegExpExecStub: public CodeStub {
481  public:
RegExpExecStub()482   RegExpExecStub() { }
483 
484  private:
MajorKey()485   Major MajorKey() { return RegExpExec; }
MinorKey()486   int MinorKey() { return 0; }
487 
488   void Generate(MacroAssembler* masm);
489 
GetName()490   const char* GetName() { return "RegExpExecStub"; }
491 
492 #ifdef DEBUG
Print()493   void Print() {
494     PrintF("RegExpExecStub\n");
495   }
496 #endif
497 };
498 
499 
500 class CallFunctionStub: public CodeStub {
501  public:
CallFunctionStub(int argc,InLoopFlag in_loop,CallFunctionFlags flags)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
Print()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 
521   // Minor key encoding in 32 bits with Bitfield <Type, shift, size>.
522   class InLoopBits: public BitField<InLoopFlag, 0, 1> {};
523   class FlagBits: public BitField<CallFunctionFlags, 1, 1> {};
524   class ArgcBits: public BitField<int, 2, 32 - 2> {};
525 
MajorKey()526   Major MajorKey() { return CallFunction; }
MinorKey()527   int MinorKey() {
528     // Encode the parameters in a unique 32 bit value.
529     return InLoopBits::encode(in_loop_)
530            | FlagBits::encode(flags_)
531            | ArgcBits::encode(argc_);
532   }
533 
InLoop()534   InLoopFlag InLoop() { return in_loop_; }
ReceiverMightBeValue()535   bool ReceiverMightBeValue() {
536     return (flags_ & RECEIVER_MIGHT_BE_VALUE) != 0;
537   }
538 
539  public:
ExtractArgcFromMinorKey(int minor_key)540   static int ExtractArgcFromMinorKey(int minor_key) {
541     return ArgcBits::decode(minor_key);
542   }
543 };
544 
545 
546 class ToBooleanStub: public CodeStub {
547  public:
ToBooleanStub()548   ToBooleanStub() { }
549 
550   void Generate(MacroAssembler* masm);
551 
552  private:
MajorKey()553   Major MajorKey() { return ToBoolean; }
MinorKey()554   int MinorKey() { return 0; }
555 };
556 
557 
558 }  // namespace internal
559 }  // namespace v8
560 
561 #endif  // V8_CODEGEN_H_
562