1 // Copyright 2011 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_CODE_STUBS_H_ 29 #define V8_CODE_STUBS_H_ 30 31 #include "globals.h" 32 33 namespace v8 { 34 namespace internal { 35 36 // List of code stubs used on all platforms. The order in this list is important 37 // as only the stubs up to and including Instanceof allows nested stub calls. 38 #define CODE_STUB_LIST_ALL_PLATFORMS(V) \ 39 V(CallFunction) \ 40 V(TypeRecordingBinaryOp) \ 41 V(StringAdd) \ 42 V(SubString) \ 43 V(StringCompare) \ 44 V(SmiOp) \ 45 V(Compare) \ 46 V(CompareIC) \ 47 V(MathPow) \ 48 V(TranscendentalCache) \ 49 V(Instanceof) \ 50 V(ConvertToDouble) \ 51 V(WriteInt32ToHeapNumber) \ 52 V(StackCheck) \ 53 V(FastNewClosure) \ 54 V(FastNewContext) \ 55 V(FastCloneShallowArray) \ 56 V(GenericUnaryOp) \ 57 V(RevertToNumber) \ 58 V(ToBoolean) \ 59 V(ToNumber) \ 60 V(CounterOp) \ 61 V(ArgumentsAccess) \ 62 V(RegExpExec) \ 63 V(RegExpConstructResult) \ 64 V(NumberToString) \ 65 V(CEntry) \ 66 V(JSEntry) \ 67 V(DebuggerStatement) 68 69 // List of code stubs only used on ARM platforms. 70 #ifdef V8_TARGET_ARCH_ARM 71 #define CODE_STUB_LIST_ARM(V) \ 72 V(GetProperty) \ 73 V(SetProperty) \ 74 V(InvokeBuiltin) \ 75 V(RegExpCEntry) \ 76 V(DirectCEntry) 77 #else 78 #define CODE_STUB_LIST_ARM(V) 79 #endif 80 81 // List of code stubs only used on MIPS platforms. 82 #ifdef V8_TARGET_ARCH_MIPS 83 #define CODE_STUB_LIST_MIPS(V) \ 84 V(RegExpCEntry) 85 #else 86 #define CODE_STUB_LIST_MIPS(V) 87 #endif 88 89 // Combined list of code stubs. 90 #define CODE_STUB_LIST(V) \ 91 CODE_STUB_LIST_ALL_PLATFORMS(V) \ 92 CODE_STUB_LIST_ARM(V) \ 93 CODE_STUB_LIST_MIPS(V) 94 95 // Mode to overwrite BinaryExpression values. 96 enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT }; 97 enum UnaryOverwriteMode { UNARY_OVERWRITE, UNARY_NO_OVERWRITE }; 98 99 100 // Stub is base classes of all stubs. 101 class CodeStub BASE_EMBEDDED { 102 public: 103 enum Major { 104 #define DEF_ENUM(name) name, 105 CODE_STUB_LIST(DEF_ENUM) 106 #undef DEF_ENUM 107 NoCache, // marker for stubs that do custom caching 108 NUMBER_OF_IDS 109 }; 110 111 // Retrieve the code for the stub. Generate the code if needed. 112 Handle<Code> GetCode(); 113 114 // Retrieve the code for the stub if already generated. Do not 115 // generate the code if not already generated and instead return a 116 // retry after GC Failure object. 117 MUST_USE_RESULT MaybeObject* TryGetCode(); 118 MajorKeyFromKey(uint32_t key)119 static Major MajorKeyFromKey(uint32_t key) { 120 return static_cast<Major>(MajorKeyBits::decode(key)); 121 } MinorKeyFromKey(uint32_t key)122 static int MinorKeyFromKey(uint32_t key) { 123 return MinorKeyBits::decode(key); 124 } 125 126 // Gets the major key from a code object that is a code stub or binary op IC. GetMajorKey(Code * code_stub)127 static Major GetMajorKey(Code* code_stub) { 128 return static_cast<Major>(code_stub->major_key()); 129 } 130 131 static const char* MajorName(Major major_key, bool allow_unknown_keys); 132 ~CodeStub()133 virtual ~CodeStub() {} 134 135 protected: 136 static const int kMajorBits = 6; 137 static const int kMinorBits = kBitsPerInt - kSmiTagSize - kMajorBits; 138 139 private: 140 // Lookup the code in the (possibly custom) cache. 141 bool FindCodeInCache(Code** code_out); 142 143 // Nonvirtual wrapper around the stub-specific Generate function. Call 144 // this function to set up the macro assembler and generate the code. 145 void GenerateCode(MacroAssembler* masm); 146 147 // Generates the assembler code for the stub. 148 virtual void Generate(MacroAssembler* masm) = 0; 149 150 // Perform bookkeeping required after code generation when stub code is 151 // initially generated. 152 void RecordCodeGeneration(Code* code, MacroAssembler* masm); 153 154 // Finish the code object after it has been generated. FinishCode(Code * code)155 virtual void FinishCode(Code* code) { } 156 157 // Returns information for computing the number key. 158 virtual Major MajorKey() = 0; 159 virtual int MinorKey() = 0; 160 161 // The CallFunctionStub needs to override this so it can encode whether a 162 // lazily generated function should be fully optimized or not. InLoop()163 virtual InLoopFlag InLoop() { return NOT_IN_LOOP; } 164 165 // TypeRecordingBinaryOpStub needs to override this. 166 virtual int GetCodeKind(); 167 168 // TypeRecordingBinaryOpStub needs to override this. GetICState()169 virtual InlineCacheState GetICState() { 170 return UNINITIALIZED; 171 } 172 173 // Returns a name for logging/debugging purposes. GetName()174 virtual const char* GetName() { return MajorName(MajorKey(), false); } 175 176 // Returns whether the code generated for this stub needs to be allocated as 177 // a fixed (non-moveable) code object. NeedsImmovableCode()178 virtual bool NeedsImmovableCode() { return false; } 179 180 #ifdef DEBUG Print()181 virtual void Print() { PrintF("%s\n", GetName()); } 182 #endif 183 184 // Computes the key based on major and minor. GetKey()185 uint32_t GetKey() { 186 ASSERT(static_cast<int>(MajorKey()) < NUMBER_OF_IDS); 187 return MinorKeyBits::encode(MinorKey()) | 188 MajorKeyBits::encode(MajorKey()); 189 } 190 AllowsStubCalls()191 bool AllowsStubCalls() { return MajorKey() <= Instanceof; } 192 193 class MajorKeyBits: public BitField<uint32_t, 0, kMajorBits> {}; 194 class MinorKeyBits: public BitField<uint32_t, kMajorBits, kMinorBits> {}; 195 196 friend class BreakPointIterator; 197 }; 198 199 200 // Helper interface to prepare to/restore after making runtime calls. 201 class RuntimeCallHelper { 202 public: ~RuntimeCallHelper()203 virtual ~RuntimeCallHelper() {} 204 205 virtual void BeforeCall(MacroAssembler* masm) const = 0; 206 207 virtual void AfterCall(MacroAssembler* masm) const = 0; 208 209 protected: RuntimeCallHelper()210 RuntimeCallHelper() {} 211 212 private: 213 DISALLOW_COPY_AND_ASSIGN(RuntimeCallHelper); 214 }; 215 216 } } // namespace v8::internal 217 218 #if V8_TARGET_ARCH_IA32 219 #include "ia32/code-stubs-ia32.h" 220 #elif V8_TARGET_ARCH_X64 221 #include "x64/code-stubs-x64.h" 222 #elif V8_TARGET_ARCH_ARM 223 #include "arm/code-stubs-arm.h" 224 #elif V8_TARGET_ARCH_MIPS 225 #include "mips/code-stubs-mips.h" 226 #else 227 #error Unsupported target architecture. 228 #endif 229 230 namespace v8 { 231 namespace internal { 232 233 234 // RuntimeCallHelper implementation used in stubs: enters/leaves a 235 // newly created internal frame before/after the runtime call. 236 class StubRuntimeCallHelper : public RuntimeCallHelper { 237 public: StubRuntimeCallHelper()238 StubRuntimeCallHelper() {} 239 240 virtual void BeforeCall(MacroAssembler* masm) const; 241 242 virtual void AfterCall(MacroAssembler* masm) const; 243 }; 244 245 246 // Trivial RuntimeCallHelper implementation. 247 class NopRuntimeCallHelper : public RuntimeCallHelper { 248 public: NopRuntimeCallHelper()249 NopRuntimeCallHelper() {} 250 BeforeCall(MacroAssembler * masm)251 virtual void BeforeCall(MacroAssembler* masm) const {} 252 AfterCall(MacroAssembler * masm)253 virtual void AfterCall(MacroAssembler* masm) const {} 254 }; 255 256 257 class StackCheckStub : public CodeStub { 258 public: StackCheckStub()259 StackCheckStub() { } 260 261 void Generate(MacroAssembler* masm); 262 263 private: 264 GetName()265 const char* GetName() { return "StackCheckStub"; } 266 MajorKey()267 Major MajorKey() { return StackCheck; } MinorKey()268 int MinorKey() { return 0; } 269 }; 270 271 272 class ToNumberStub: public CodeStub { 273 public: ToNumberStub()274 ToNumberStub() { } 275 276 void Generate(MacroAssembler* masm); 277 278 private: MajorKey()279 Major MajorKey() { return ToNumber; } MinorKey()280 int MinorKey() { return 0; } GetName()281 const char* GetName() { return "ToNumberStub"; } 282 }; 283 284 285 class FastNewClosureStub : public CodeStub { 286 public: FastNewClosureStub(StrictModeFlag strict_mode)287 explicit FastNewClosureStub(StrictModeFlag strict_mode) 288 : strict_mode_(strict_mode) { } 289 290 void Generate(MacroAssembler* masm); 291 292 private: GetName()293 const char* GetName() { return "FastNewClosureStub"; } MajorKey()294 Major MajorKey() { return FastNewClosure; } MinorKey()295 int MinorKey() { return strict_mode_; } 296 297 StrictModeFlag strict_mode_; 298 }; 299 300 301 class FastNewContextStub : public CodeStub { 302 public: 303 static const int kMaximumSlots = 64; 304 FastNewContextStub(int slots)305 explicit FastNewContextStub(int slots) : slots_(slots) { 306 ASSERT(slots_ > 0 && slots <= kMaximumSlots); 307 } 308 309 void Generate(MacroAssembler* masm); 310 311 private: 312 int slots_; 313 GetName()314 const char* GetName() { return "FastNewContextStub"; } MajorKey()315 Major MajorKey() { return FastNewContext; } MinorKey()316 int MinorKey() { return slots_; } 317 }; 318 319 320 class FastCloneShallowArrayStub : public CodeStub { 321 public: 322 // Maximum length of copied elements array. 323 static const int kMaximumClonedLength = 8; 324 325 enum Mode { 326 CLONE_ELEMENTS, 327 COPY_ON_WRITE_ELEMENTS 328 }; 329 FastCloneShallowArrayStub(Mode mode,int length)330 FastCloneShallowArrayStub(Mode mode, int length) 331 : mode_(mode), 332 length_((mode == COPY_ON_WRITE_ELEMENTS) ? 0 : length) { 333 ASSERT(length_ >= 0); 334 ASSERT(length_ <= kMaximumClonedLength); 335 } 336 337 void Generate(MacroAssembler* masm); 338 339 private: 340 Mode mode_; 341 int length_; 342 GetName()343 const char* GetName() { return "FastCloneShallowArrayStub"; } MajorKey()344 Major MajorKey() { return FastCloneShallowArray; } MinorKey()345 int MinorKey() { 346 ASSERT(mode_ == 0 || mode_ == 1); 347 return (length_ << 1) | mode_; 348 } 349 }; 350 351 352 class InstanceofStub: public CodeStub { 353 public: 354 enum Flags { 355 kNoFlags = 0, 356 kArgsInRegisters = 1 << 0, 357 kCallSiteInlineCheck = 1 << 1, 358 kReturnTrueFalseObject = 1 << 2 359 }; 360 InstanceofStub(Flags flags)361 explicit InstanceofStub(Flags flags) : flags_(flags), name_(NULL) { } 362 363 static Register left(); 364 static Register right(); 365 366 void Generate(MacroAssembler* masm); 367 368 private: MajorKey()369 Major MajorKey() { return Instanceof; } MinorKey()370 int MinorKey() { return static_cast<int>(flags_); } 371 HasArgsInRegisters()372 bool HasArgsInRegisters() const { 373 return (flags_ & kArgsInRegisters) != 0; 374 } 375 HasCallSiteInlineCheck()376 bool HasCallSiteInlineCheck() const { 377 return (flags_ & kCallSiteInlineCheck) != 0; 378 } 379 ReturnTrueFalseObject()380 bool ReturnTrueFalseObject() const { 381 return (flags_ & kReturnTrueFalseObject) != 0; 382 } 383 384 const char* GetName(); 385 386 Flags flags_; 387 char* name_; 388 }; 389 390 391 enum NegativeZeroHandling { 392 kStrictNegativeZero, 393 kIgnoreNegativeZero 394 }; 395 396 397 enum UnaryOpFlags { 398 NO_UNARY_FLAGS = 0, 399 NO_UNARY_SMI_CODE_IN_STUB = 1 << 0 400 }; 401 402 403 class GenericUnaryOpStub : public CodeStub { 404 public: 405 GenericUnaryOpStub(Token::Value op, 406 UnaryOverwriteMode overwrite, 407 UnaryOpFlags flags, 408 NegativeZeroHandling negative_zero = kStrictNegativeZero) op_(op)409 : op_(op), 410 overwrite_(overwrite), 411 include_smi_code_((flags & NO_UNARY_SMI_CODE_IN_STUB) == 0), 412 negative_zero_(negative_zero) { } 413 414 private: 415 Token::Value op_; 416 UnaryOverwriteMode overwrite_; 417 bool include_smi_code_; 418 NegativeZeroHandling negative_zero_; 419 420 class OverwriteField: public BitField<UnaryOverwriteMode, 0, 1> {}; 421 class IncludeSmiCodeField: public BitField<bool, 1, 1> {}; 422 class NegativeZeroField: public BitField<NegativeZeroHandling, 2, 1> {}; 423 class OpField: public BitField<Token::Value, 3, kMinorBits - 3> {}; 424 MajorKey()425 Major MajorKey() { return GenericUnaryOp; } MinorKey()426 int MinorKey() { 427 return OpField::encode(op_) | 428 OverwriteField::encode(overwrite_) | 429 IncludeSmiCodeField::encode(include_smi_code_) | 430 NegativeZeroField::encode(negative_zero_); 431 } 432 433 void Generate(MacroAssembler* masm); 434 435 const char* GetName(); 436 }; 437 438 439 class MathPowStub: public CodeStub { 440 public: MathPowStub()441 MathPowStub() {} 442 virtual void Generate(MacroAssembler* masm); 443 444 private: MajorKey()445 virtual CodeStub::Major MajorKey() { return MathPow; } MinorKey()446 virtual int MinorKey() { return 0; } 447 GetName()448 const char* GetName() { return "MathPowStub"; } 449 }; 450 451 452 class ICCompareStub: public CodeStub { 453 public: ICCompareStub(Token::Value op,CompareIC::State state)454 ICCompareStub(Token::Value op, CompareIC::State state) 455 : op_(op), state_(state) { 456 ASSERT(Token::IsCompareOp(op)); 457 } 458 459 virtual void Generate(MacroAssembler* masm); 460 461 private: 462 class OpField: public BitField<int, 0, 3> { }; 463 class StateField: public BitField<int, 3, 5> { }; 464 FinishCode(Code * code)465 virtual void FinishCode(Code* code) { code->set_compare_state(state_); } 466 MajorKey()467 virtual CodeStub::Major MajorKey() { return CompareIC; } 468 virtual int MinorKey(); 469 GetCodeKind()470 virtual int GetCodeKind() { return Code::COMPARE_IC; } 471 472 void GenerateSmis(MacroAssembler* masm); 473 void GenerateHeapNumbers(MacroAssembler* masm); 474 void GenerateObjects(MacroAssembler* masm); 475 void GenerateMiss(MacroAssembler* masm); 476 strict()477 bool strict() const { return op_ == Token::EQ_STRICT; } GetCondition()478 Condition GetCondition() const { return CompareIC::ComputeCondition(op_); } 479 480 Token::Value op_; 481 CompareIC::State state_; 482 }; 483 484 485 // Flags that control the compare stub code generation. 486 enum CompareFlags { 487 NO_COMPARE_FLAGS = 0, 488 NO_SMI_COMPARE_IN_STUB = 1 << 0, 489 NO_NUMBER_COMPARE_IN_STUB = 1 << 1, 490 CANT_BOTH_BE_NAN = 1 << 2 491 }; 492 493 494 enum NaNInformation { 495 kBothCouldBeNaN, 496 kCantBothBeNaN 497 }; 498 499 500 class CompareStub: public CodeStub { 501 public: CompareStub(Condition cc,bool strict,CompareFlags flags,Register lhs,Register rhs)502 CompareStub(Condition cc, 503 bool strict, 504 CompareFlags flags, 505 Register lhs, 506 Register rhs) : 507 cc_(cc), 508 strict_(strict), 509 never_nan_nan_((flags & CANT_BOTH_BE_NAN) != 0), 510 include_number_compare_((flags & NO_NUMBER_COMPARE_IN_STUB) == 0), 511 include_smi_compare_((flags & NO_SMI_COMPARE_IN_STUB) == 0), 512 lhs_(lhs), 513 rhs_(rhs), 514 name_(NULL) { } 515 CompareStub(Condition cc,bool strict,CompareFlags flags)516 CompareStub(Condition cc, 517 bool strict, 518 CompareFlags flags) : 519 cc_(cc), 520 strict_(strict), 521 never_nan_nan_((flags & CANT_BOTH_BE_NAN) != 0), 522 include_number_compare_((flags & NO_NUMBER_COMPARE_IN_STUB) == 0), 523 include_smi_compare_((flags & NO_SMI_COMPARE_IN_STUB) == 0), 524 lhs_(no_reg), 525 rhs_(no_reg), 526 name_(NULL) { } 527 528 void Generate(MacroAssembler* masm); 529 530 private: 531 Condition cc_; 532 bool strict_; 533 // Only used for 'equal' comparisons. Tells the stub that we already know 534 // that at least one side of the comparison is not NaN. This allows the 535 // stub to use object identity in the positive case. We ignore it when 536 // generating the minor key for other comparisons to avoid creating more 537 // stubs. 538 bool never_nan_nan_; 539 // Do generate the number comparison code in the stub. Stubs without number 540 // comparison code is used when the number comparison has been inlined, and 541 // the stub will be called if one of the operands is not a number. 542 bool include_number_compare_; 543 544 // Generate the comparison code for two smi operands in the stub. 545 bool include_smi_compare_; 546 547 // Register holding the left hand side of the comparison if the stub gives 548 // a choice, no_reg otherwise. 549 550 Register lhs_; 551 // Register holding the right hand side of the comparison if the stub gives 552 // a choice, no_reg otherwise. 553 Register rhs_; 554 555 // Encoding of the minor key in 16 bits. 556 class StrictField: public BitField<bool, 0, 1> {}; 557 class NeverNanNanField: public BitField<bool, 1, 1> {}; 558 class IncludeNumberCompareField: public BitField<bool, 2, 1> {}; 559 class IncludeSmiCompareField: public BitField<bool, 3, 1> {}; 560 class RegisterField: public BitField<bool, 4, 1> {}; 561 class ConditionField: public BitField<int, 5, 11> {}; 562 MajorKey()563 Major MajorKey() { return Compare; } 564 565 int MinorKey(); 566 GetCodeKind()567 virtual int GetCodeKind() { return Code::COMPARE_IC; } FinishCode(Code * code)568 virtual void FinishCode(Code* code) { 569 code->set_compare_state(CompareIC::GENERIC); 570 } 571 572 // Branch to the label if the given object isn't a symbol. 573 void BranchIfNonSymbol(MacroAssembler* masm, 574 Label* label, 575 Register object, 576 Register scratch); 577 578 // Unfortunately you have to run without snapshots to see most of these 579 // names in the profile since most compare stubs end up in the snapshot. 580 char* name_; 581 const char* GetName(); 582 #ifdef DEBUG Print()583 void Print() { 584 PrintF("CompareStub (minor %d) (cc %d), (strict %s), " 585 "(never_nan_nan %s), (smi_compare %s) (number_compare %s) ", 586 MinorKey(), 587 static_cast<int>(cc_), 588 strict_ ? "true" : "false", 589 never_nan_nan_ ? "true" : "false", 590 include_smi_compare_ ? "inluded" : "not included", 591 include_number_compare_ ? "included" : "not included"); 592 593 if (!lhs_.is(no_reg) && !rhs_.is(no_reg)) { 594 PrintF("(lhs r%d), (rhs r%d)\n", lhs_.code(), rhs_.code()); 595 } else { 596 PrintF("\n"); 597 } 598 } 599 #endif 600 }; 601 602 603 class CEntryStub : public CodeStub { 604 public: CEntryStub(int result_size)605 explicit CEntryStub(int result_size) 606 : result_size_(result_size), save_doubles_(false) { } 607 608 void Generate(MacroAssembler* masm); SaveDoubles()609 void SaveDoubles() { save_doubles_ = true; } 610 611 private: 612 void GenerateCore(MacroAssembler* masm, 613 Label* throw_normal_exception, 614 Label* throw_termination_exception, 615 Label* throw_out_of_memory_exception, 616 bool do_gc, 617 bool always_allocate_scope); 618 void GenerateThrowTOS(MacroAssembler* masm); 619 void GenerateThrowUncatchable(MacroAssembler* masm, 620 UncatchableExceptionType type); 621 622 // Number of pointers/values returned. 623 const int result_size_; 624 bool save_doubles_; 625 MajorKey()626 Major MajorKey() { return CEntry; } 627 int MinorKey(); 628 629 bool NeedsImmovableCode(); 630 GetName()631 const char* GetName() { return "CEntryStub"; } 632 }; 633 634 635 class JSEntryStub : public CodeStub { 636 public: JSEntryStub()637 JSEntryStub() { } 638 Generate(MacroAssembler * masm)639 void Generate(MacroAssembler* masm) { GenerateBody(masm, false); } 640 641 protected: 642 void GenerateBody(MacroAssembler* masm, bool is_construct); 643 644 private: MajorKey()645 Major MajorKey() { return JSEntry; } MinorKey()646 int MinorKey() { return 0; } 647 GetName()648 const char* GetName() { return "JSEntryStub"; } 649 }; 650 651 652 class JSConstructEntryStub : public JSEntryStub { 653 public: JSConstructEntryStub()654 JSConstructEntryStub() { } 655 Generate(MacroAssembler * masm)656 void Generate(MacroAssembler* masm) { GenerateBody(masm, true); } 657 658 private: MinorKey()659 int MinorKey() { return 1; } 660 GetName()661 const char* GetName() { return "JSConstructEntryStub"; } 662 }; 663 664 665 class ArgumentsAccessStub: public CodeStub { 666 public: 667 enum Type { 668 READ_ELEMENT, 669 NEW_NON_STRICT, 670 NEW_STRICT 671 }; 672 ArgumentsAccessStub(Type type)673 explicit ArgumentsAccessStub(Type type) : type_(type) { } 674 675 private: 676 Type type_; 677 MajorKey()678 Major MajorKey() { return ArgumentsAccess; } MinorKey()679 int MinorKey() { return type_; } 680 681 void Generate(MacroAssembler* masm); 682 void GenerateReadElement(MacroAssembler* masm); 683 void GenerateNewObject(MacroAssembler* masm); 684 GetArgumentsBoilerplateIndex()685 int GetArgumentsBoilerplateIndex() const { 686 return (type_ == NEW_STRICT) 687 ? Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX 688 : Context::ARGUMENTS_BOILERPLATE_INDEX; 689 } 690 GetArgumentsObjectSize()691 int GetArgumentsObjectSize() const { 692 if (type_ == NEW_STRICT) 693 return Heap::kArgumentsObjectSizeStrict; 694 else 695 return Heap::kArgumentsObjectSize; 696 } 697 GetName()698 const char* GetName() { return "ArgumentsAccessStub"; } 699 700 #ifdef DEBUG Print()701 void Print() { 702 PrintF("ArgumentsAccessStub (type %d)\n", type_); 703 } 704 #endif 705 }; 706 707 708 class RegExpExecStub: public CodeStub { 709 public: RegExpExecStub()710 RegExpExecStub() { } 711 712 private: MajorKey()713 Major MajorKey() { return RegExpExec; } MinorKey()714 int MinorKey() { return 0; } 715 716 void Generate(MacroAssembler* masm); 717 GetName()718 const char* GetName() { return "RegExpExecStub"; } 719 720 #ifdef DEBUG Print()721 void Print() { 722 PrintF("RegExpExecStub\n"); 723 } 724 #endif 725 }; 726 727 728 class RegExpConstructResultStub: public CodeStub { 729 public: RegExpConstructResultStub()730 RegExpConstructResultStub() { } 731 732 private: MajorKey()733 Major MajorKey() { return RegExpConstructResult; } MinorKey()734 int MinorKey() { return 0; } 735 736 void Generate(MacroAssembler* masm); 737 GetName()738 const char* GetName() { return "RegExpConstructResultStub"; } 739 740 #ifdef DEBUG Print()741 void Print() { 742 PrintF("RegExpConstructResultStub\n"); 743 } 744 #endif 745 }; 746 747 748 class CallFunctionStub: public CodeStub { 749 public: CallFunctionStub(int argc,InLoopFlag in_loop,CallFunctionFlags flags)750 CallFunctionStub(int argc, InLoopFlag in_loop, CallFunctionFlags flags) 751 : argc_(argc), in_loop_(in_loop), flags_(flags) { } 752 753 void Generate(MacroAssembler* masm); 754 ExtractArgcFromMinorKey(int minor_key)755 static int ExtractArgcFromMinorKey(int minor_key) { 756 return ArgcBits::decode(minor_key); 757 } 758 759 private: 760 int argc_; 761 InLoopFlag in_loop_; 762 CallFunctionFlags flags_; 763 764 #ifdef DEBUG Print()765 void Print() { 766 PrintF("CallFunctionStub (args %d, in_loop %d, flags %d)\n", 767 argc_, 768 static_cast<int>(in_loop_), 769 static_cast<int>(flags_)); 770 } 771 #endif 772 773 // Minor key encoding in 32 bits with Bitfield <Type, shift, size>. 774 class InLoopBits: public BitField<InLoopFlag, 0, 1> {}; 775 class FlagBits: public BitField<CallFunctionFlags, 1, 1> {}; 776 class ArgcBits: public BitField<int, 2, 32 - 2> {}; 777 MajorKey()778 Major MajorKey() { return CallFunction; } MinorKey()779 int MinorKey() { 780 // Encode the parameters in a unique 32 bit value. 781 return InLoopBits::encode(in_loop_) 782 | FlagBits::encode(flags_) 783 | ArgcBits::encode(argc_); 784 } 785 InLoop()786 InLoopFlag InLoop() { return in_loop_; } ReceiverMightBeValue()787 bool ReceiverMightBeValue() { 788 return (flags_ & RECEIVER_MIGHT_BE_VALUE) != 0; 789 } 790 }; 791 792 793 enum StringIndexFlags { 794 // Accepts smis or heap numbers. 795 STRING_INDEX_IS_NUMBER, 796 797 // Accepts smis or heap numbers that are valid array indices 798 // (ECMA-262 15.4). Invalid indices are reported as being out of 799 // range. 800 STRING_INDEX_IS_ARRAY_INDEX 801 }; 802 803 804 // Generates code implementing String.prototype.charCodeAt. 805 // 806 // Only supports the case when the receiver is a string and the index 807 // is a number (smi or heap number) that is a valid index into the 808 // string. Additional index constraints are specified by the 809 // flags. Otherwise, bails out to the provided labels. 810 // 811 // Register usage: |object| may be changed to another string in a way 812 // that doesn't affect charCodeAt/charAt semantics, |index| is 813 // preserved, |scratch| and |result| are clobbered. 814 class StringCharCodeAtGenerator { 815 public: StringCharCodeAtGenerator(Register object,Register index,Register scratch,Register result,Label * receiver_not_string,Label * index_not_number,Label * index_out_of_range,StringIndexFlags index_flags)816 StringCharCodeAtGenerator(Register object, 817 Register index, 818 Register scratch, 819 Register result, 820 Label* receiver_not_string, 821 Label* index_not_number, 822 Label* index_out_of_range, 823 StringIndexFlags index_flags) 824 : object_(object), 825 index_(index), 826 scratch_(scratch), 827 result_(result), 828 receiver_not_string_(receiver_not_string), 829 index_not_number_(index_not_number), 830 index_out_of_range_(index_out_of_range), 831 index_flags_(index_flags) { 832 ASSERT(!scratch_.is(object_)); 833 ASSERT(!scratch_.is(index_)); 834 ASSERT(!scratch_.is(result_)); 835 ASSERT(!result_.is(object_)); 836 ASSERT(!result_.is(index_)); 837 } 838 839 // Generates the fast case code. On the fallthrough path |result| 840 // register contains the result. 841 void GenerateFast(MacroAssembler* masm); 842 843 // Generates the slow case code. Must not be naturally 844 // reachable. Expected to be put after a ret instruction (e.g., in 845 // deferred code). Always jumps back to the fast case. 846 void GenerateSlow(MacroAssembler* masm, 847 const RuntimeCallHelper& call_helper); 848 849 private: 850 Register object_; 851 Register index_; 852 Register scratch_; 853 Register result_; 854 855 Label* receiver_not_string_; 856 Label* index_not_number_; 857 Label* index_out_of_range_; 858 859 StringIndexFlags index_flags_; 860 861 Label call_runtime_; 862 Label index_not_smi_; 863 Label got_smi_index_; 864 Label exit_; 865 866 DISALLOW_COPY_AND_ASSIGN(StringCharCodeAtGenerator); 867 }; 868 869 870 // Generates code for creating a one-char string from a char code. 871 class StringCharFromCodeGenerator { 872 public: StringCharFromCodeGenerator(Register code,Register result)873 StringCharFromCodeGenerator(Register code, 874 Register result) 875 : code_(code), 876 result_(result) { 877 ASSERT(!code_.is(result_)); 878 } 879 880 // Generates the fast case code. On the fallthrough path |result| 881 // register contains the result. 882 void GenerateFast(MacroAssembler* masm); 883 884 // Generates the slow case code. Must not be naturally 885 // reachable. Expected to be put after a ret instruction (e.g., in 886 // deferred code). Always jumps back to the fast case. 887 void GenerateSlow(MacroAssembler* masm, 888 const RuntimeCallHelper& call_helper); 889 890 private: 891 Register code_; 892 Register result_; 893 894 Label slow_case_; 895 Label exit_; 896 897 DISALLOW_COPY_AND_ASSIGN(StringCharFromCodeGenerator); 898 }; 899 900 901 // Generates code implementing String.prototype.charAt. 902 // 903 // Only supports the case when the receiver is a string and the index 904 // is a number (smi or heap number) that is a valid index into the 905 // string. Additional index constraints are specified by the 906 // flags. Otherwise, bails out to the provided labels. 907 // 908 // Register usage: |object| may be changed to another string in a way 909 // that doesn't affect charCodeAt/charAt semantics, |index| is 910 // preserved, |scratch1|, |scratch2|, and |result| are clobbered. 911 class StringCharAtGenerator { 912 public: StringCharAtGenerator(Register object,Register index,Register scratch1,Register scratch2,Register result,Label * receiver_not_string,Label * index_not_number,Label * index_out_of_range,StringIndexFlags index_flags)913 StringCharAtGenerator(Register object, 914 Register index, 915 Register scratch1, 916 Register scratch2, 917 Register result, 918 Label* receiver_not_string, 919 Label* index_not_number, 920 Label* index_out_of_range, 921 StringIndexFlags index_flags) 922 : char_code_at_generator_(object, 923 index, 924 scratch1, 925 scratch2, 926 receiver_not_string, 927 index_not_number, 928 index_out_of_range, 929 index_flags), 930 char_from_code_generator_(scratch2, result) {} 931 932 // Generates the fast case code. On the fallthrough path |result| 933 // register contains the result. 934 void GenerateFast(MacroAssembler* masm); 935 936 // Generates the slow case code. Must not be naturally 937 // reachable. Expected to be put after a ret instruction (e.g., in 938 // deferred code). Always jumps back to the fast case. 939 void GenerateSlow(MacroAssembler* masm, 940 const RuntimeCallHelper& call_helper); 941 942 private: 943 StringCharCodeAtGenerator char_code_at_generator_; 944 StringCharFromCodeGenerator char_from_code_generator_; 945 946 DISALLOW_COPY_AND_ASSIGN(StringCharAtGenerator); 947 }; 948 949 950 class AllowStubCallsScope { 951 public: AllowStubCallsScope(MacroAssembler * masm,bool allow)952 AllowStubCallsScope(MacroAssembler* masm, bool allow) 953 : masm_(masm), previous_allow_(masm->allow_stub_calls()) { 954 masm_->set_allow_stub_calls(allow); 955 } ~AllowStubCallsScope()956 ~AllowStubCallsScope() { 957 masm_->set_allow_stub_calls(previous_allow_); 958 } 959 960 private: 961 MacroAssembler* masm_; 962 bool previous_allow_; 963 964 DISALLOW_COPY_AND_ASSIGN(AllowStubCallsScope); 965 }; 966 967 } } // namespace v8::internal 968 969 #endif // V8_CODE_STUBS_H_ 970