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