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