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