codegen.h revision 7f4d5bd8c03935e2c0cd412e561b8fc5a6a880ae
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 "code-stubs.h" 32#include "runtime.h" 33#include "type-info.h" 34 35// Include the declaration of the architecture defined class CodeGenerator. 36// The contract to the shared code is that the the CodeGenerator is a subclass 37// of Visitor and that the following methods are available publicly: 38// MakeCode 39// MakeCodePrologue 40// MakeCodeEpilogue 41// masm 42// frame 43// script 44// has_valid_frame 45// SetFrame 46// DeleteFrame 47// allocator 48// AddDeferred 49// in_spilled_code 50// set_in_spilled_code 51// RecordPositions 52// 53// These methods are either used privately by the shared code or implemented as 54// shared code: 55// CodeGenerator 56// ~CodeGenerator 57// ProcessDeferred 58// Generate 59// ComputeLazyCompile 60// BuildFunctionInfo 61// ComputeCallInitialize 62// ComputeCallInitializeInLoop 63// ProcessDeclarations 64// DeclareGlobals 65// FindInlineRuntimeLUT 66// CheckForInlineRuntimeCall 67// PatchInlineRuntimeEntry 68// AnalyzeCondition 69// CodeForFunctionPosition 70// CodeForReturnPosition 71// CodeForStatementPosition 72// CodeForDoWhileConditionPosition 73// CodeForSourcePosition 74 75 76// Mode to overwrite BinaryExpression values. 77enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT }; 78 79// Types of uncatchable exceptions. 80enum UncatchableExceptionType { OUT_OF_MEMORY, TERMINATION }; 81 82 83#if V8_TARGET_ARCH_IA32 84#include "ia32/codegen-ia32.h" 85#elif V8_TARGET_ARCH_X64 86#include "x64/codegen-x64.h" 87#elif V8_TARGET_ARCH_ARM 88#include "arm/codegen-arm.h" 89#elif V8_TARGET_ARCH_MIPS 90#include "mips/codegen-mips.h" 91#else 92#error Unsupported target architecture. 93#endif 94 95#include "register-allocator.h" 96 97namespace v8 { 98namespace internal { 99 100 101#define INLINE_RUNTIME_FUNCTION_LIST(F) \ 102 F(IsSmi, 1, 1) \ 103 F(IsNonNegativeSmi, 1, 1) \ 104 F(IsArray, 1, 1) \ 105 F(IsRegExp, 1, 1) \ 106 F(CallFunction, -1 /* receiver + n args + function */, 1) \ 107 F(IsConstructCall, 0, 1) \ 108 F(ArgumentsLength, 0, 1) \ 109 F(Arguments, 1, 1) \ 110 F(ClassOf, 1, 1) \ 111 F(ValueOf, 1, 1) \ 112 F(SetValueOf, 2, 1) \ 113 F(StringCharCodeAt, 2, 1) \ 114 F(StringCharFromCode, 1, 1) \ 115 F(StringCharAt, 2, 1) \ 116 F(ObjectEquals, 2, 1) \ 117 F(Log, 3, 1) \ 118 F(RandomHeapNumber, 0, 1) \ 119 F(IsObject, 1, 1) \ 120 F(IsFunction, 1, 1) \ 121 F(IsUndetectableObject, 1, 1) \ 122 F(StringAdd, 2, 1) \ 123 F(SubString, 3, 1) \ 124 F(StringCompare, 2, 1) \ 125 F(RegExpExec, 4, 1) \ 126 F(RegExpConstructResult, 3, 1) \ 127 F(GetFromCache, 2, 1) \ 128 F(NumberToString, 1, 1) \ 129 F(SwapElements, 3, 1) \ 130 F(MathPow, 2, 1) \ 131 F(MathSin, 1, 1) \ 132 F(MathCos, 1, 1) \ 133 F(MathSqrt, 1, 1) 134 135 136// Support for "structured" code comments. 137#ifdef DEBUG 138 139class Comment BASE_EMBEDDED { 140 public: 141 Comment(MacroAssembler* masm, const char* msg); 142 ~Comment(); 143 144 private: 145 MacroAssembler* masm_; 146 const char* msg_; 147}; 148 149#else 150 151class Comment BASE_EMBEDDED { 152 public: 153 Comment(MacroAssembler*, const char*) {} 154}; 155 156#endif // DEBUG 157 158 159// Code generation can be nested. Code generation scopes form a stack 160// of active code generators. 161class CodeGeneratorScope BASE_EMBEDDED { 162 public: 163 explicit CodeGeneratorScope(CodeGenerator* cgen) { 164 previous_ = top_; 165 top_ = cgen; 166 } 167 168 ~CodeGeneratorScope() { 169 top_ = previous_; 170 } 171 172 static CodeGenerator* Current() { 173 ASSERT(top_ != NULL); 174 return top_; 175 } 176 177 private: 178 static CodeGenerator* top_; 179 CodeGenerator* previous_; 180}; 181 182 183#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64 184 185// State of used registers in a virtual frame. 186class FrameRegisterState { 187 public: 188 // Captures the current state of the given frame. 189 explicit FrameRegisterState(VirtualFrame* frame); 190 191 // Saves the state in the stack. 192 void Save(MacroAssembler* masm) const; 193 194 // Restores the state from the stack. 195 void Restore(MacroAssembler* masm) const; 196 197 private: 198 // Constants indicating special actions. They should not be multiples 199 // of kPointerSize so they will not collide with valid offsets from 200 // the frame pointer. 201 static const int kIgnore = -1; 202 static const int kPush = 1; 203 204 // This flag is ored with a valid offset from the frame pointer, so 205 // it should fit in the low zero bits of a valid offset. 206 static const int kSyncedFlag = 2; 207 208 int registers_[RegisterAllocator::kNumRegisters]; 209}; 210 211#elif V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS 212 213 214class FrameRegisterState { 215 public: 216 inline FrameRegisterState(VirtualFrame frame) : frame_(frame) { } 217 218 inline const VirtualFrame* frame() const { return &frame_; } 219 220 private: 221 VirtualFrame frame_; 222}; 223 224#else 225 226#error Unsupported target architecture. 227 228#endif 229 230 231// Helper interface to prepare to/restore after making runtime calls. 232class RuntimeCallHelper { 233 public: 234 virtual ~RuntimeCallHelper() {} 235 236 virtual void BeforeCall(MacroAssembler* masm) const = 0; 237 238 virtual void AfterCall(MacroAssembler* masm) const = 0; 239 240 protected: 241 RuntimeCallHelper() {} 242 243 private: 244 DISALLOW_COPY_AND_ASSIGN(RuntimeCallHelper); 245}; 246 247 248// RuntimeCallHelper implementation that saves/restores state of a 249// virtual frame. 250class VirtualFrameRuntimeCallHelper : public RuntimeCallHelper { 251 public: 252 // Does not take ownership of |frame_state|. 253 explicit VirtualFrameRuntimeCallHelper(const FrameRegisterState* frame_state) 254 : frame_state_(frame_state) {} 255 256 virtual void BeforeCall(MacroAssembler* masm) const; 257 258 virtual void AfterCall(MacroAssembler* masm) const; 259 260 private: 261 const FrameRegisterState* frame_state_; 262}; 263 264 265// RuntimeCallHelper implementation used in IC stubs: enters/leaves a 266// newly created internal frame before/after the runtime call. 267class ICRuntimeCallHelper : public RuntimeCallHelper { 268 public: 269 ICRuntimeCallHelper() {} 270 271 virtual void BeforeCall(MacroAssembler* masm) const; 272 273 virtual void AfterCall(MacroAssembler* masm) const; 274}; 275 276 277// Trivial RuntimeCallHelper implementation. 278class NopRuntimeCallHelper : public RuntimeCallHelper { 279 public: 280 NopRuntimeCallHelper() {} 281 282 virtual void BeforeCall(MacroAssembler* masm) const {} 283 284 virtual void AfterCall(MacroAssembler* masm) const {} 285}; 286 287 288// Deferred code objects are small pieces of code that are compiled 289// out of line. They are used to defer the compilation of uncommon 290// paths thereby avoiding expensive jumps around uncommon code parts. 291class DeferredCode: public ZoneObject { 292 public: 293 DeferredCode(); 294 virtual ~DeferredCode() { } 295 296 virtual void Generate() = 0; 297 298 MacroAssembler* masm() { return masm_; } 299 300 int statement_position() const { return statement_position_; } 301 int position() const { return position_; } 302 303 Label* entry_label() { return &entry_label_; } 304 Label* exit_label() { return &exit_label_; } 305 306#ifdef DEBUG 307 void set_comment(const char* comment) { comment_ = comment; } 308 const char* comment() const { return comment_; } 309#else 310 void set_comment(const char* comment) { } 311 const char* comment() const { return ""; } 312#endif 313 314 inline void Jump(); 315 inline void Branch(Condition cc); 316 void BindExit() { masm_->bind(&exit_label_); } 317 318 const FrameRegisterState* frame_state() const { return &frame_state_; } 319 320 void SaveRegisters(); 321 void RestoreRegisters(); 322 323 protected: 324 MacroAssembler* masm_; 325 326 private: 327 int statement_position_; 328 int position_; 329 330 Label entry_label_; 331 Label exit_label_; 332 333 FrameRegisterState frame_state_; 334 335#ifdef DEBUG 336 const char* comment_; 337#endif 338 DISALLOW_COPY_AND_ASSIGN(DeferredCode); 339}; 340 341class StackCheckStub : public CodeStub { 342 public: 343 StackCheckStub() { } 344 345 void Generate(MacroAssembler* masm); 346 347 private: 348 349 const char* GetName() { return "StackCheckStub"; } 350 351 Major MajorKey() { return StackCheck; } 352 int MinorKey() { return 0; } 353}; 354 355 356class FastNewClosureStub : public CodeStub { 357 public: 358 void Generate(MacroAssembler* masm); 359 360 private: 361 const char* GetName() { return "FastNewClosureStub"; } 362 Major MajorKey() { return FastNewClosure; } 363 int MinorKey() { return 0; } 364}; 365 366 367class FastNewContextStub : public CodeStub { 368 public: 369 static const int kMaximumSlots = 64; 370 371 explicit FastNewContextStub(int slots) : slots_(slots) { 372 ASSERT(slots_ > 0 && slots <= kMaximumSlots); 373 } 374 375 void Generate(MacroAssembler* masm); 376 377 private: 378 int slots_; 379 380 const char* GetName() { return "FastNewContextStub"; } 381 Major MajorKey() { return FastNewContext; } 382 int MinorKey() { return slots_; } 383}; 384 385 386class FastCloneShallowArrayStub : public CodeStub { 387 public: 388 static const int kMaximumLength = 8; 389 390 explicit FastCloneShallowArrayStub(int length) : length_(length) { 391 ASSERT(length >= 0 && length <= kMaximumLength); 392 } 393 394 void Generate(MacroAssembler* masm); 395 396 private: 397 int length_; 398 399 const char* GetName() { return "FastCloneShallowArrayStub"; } 400 Major MajorKey() { return FastCloneShallowArray; } 401 int MinorKey() { return length_; } 402}; 403 404 405class InstanceofStub: public CodeStub { 406 public: 407 InstanceofStub() { } 408 409 void Generate(MacroAssembler* masm); 410 411 private: 412 Major MajorKey() { return Instanceof; } 413 int MinorKey() { return 0; } 414}; 415 416 417class GenericUnaryOpStub : public CodeStub { 418 public: 419 GenericUnaryOpStub(Token::Value op, bool overwrite) 420 : op_(op), overwrite_(overwrite) { } 421 422 private: 423 Token::Value op_; 424 bool overwrite_; 425 426 class OverwriteField: public BitField<int, 0, 1> {}; 427 class OpField: public BitField<Token::Value, 1, kMinorBits - 1> {}; 428 429 Major MajorKey() { return GenericUnaryOp; } 430 int MinorKey() { 431 return OpField::encode(op_) | OverwriteField::encode(overwrite_); 432 } 433 434 void Generate(MacroAssembler* masm); 435 436 const char* GetName(); 437}; 438 439 440enum NaNInformation { 441 kBothCouldBeNaN, 442 kCantBothBeNaN 443}; 444 445 446class CompareStub: public CodeStub { 447 public: 448 CompareStub(Condition cc, 449 bool strict, 450 NaNInformation nan_info = kBothCouldBeNaN, 451 bool include_number_compare = true) : 452 cc_(cc), 453 strict_(strict), 454 never_nan_nan_(nan_info == kCantBothBeNaN), 455 include_number_compare_(include_number_compare), 456 name_(NULL) { } 457 458 void Generate(MacroAssembler* masm); 459 460 private: 461 Condition cc_; 462 bool strict_; 463 // Only used for 'equal' comparisons. Tells the stub that we already know 464 // that at least one side of the comparison is not NaN. This allows the 465 // stub to use object identity in the positive case. We ignore it when 466 // generating the minor key for other comparisons to avoid creating more 467 // stubs. 468 bool never_nan_nan_; 469 // Do generate the number comparison code in the stub. Stubs without number 470 // comparison code is used when the number comparison has been inlined, and 471 // the stub will be called if one of the operands is not a number. 472 bool include_number_compare_; 473 474 // Encoding of the minor key CCCCCCCCCCCCCCNS. 475 class StrictField: public BitField<bool, 0, 1> {}; 476 class NeverNanNanField: public BitField<bool, 1, 1> {}; 477 class IncludeNumberCompareField: public BitField<bool, 2, 1> {}; 478 class ConditionField: public BitField<int, 3, 13> {}; 479 480 Major MajorKey() { return Compare; } 481 482 int MinorKey(); 483 484 // Branch to the label if the given object isn't a symbol. 485 void BranchIfNonSymbol(MacroAssembler* masm, 486 Label* label, 487 Register object, 488 Register scratch); 489 490 // Unfortunately you have to run without snapshots to see most of these 491 // names in the profile since most compare stubs end up in the snapshot. 492 char* name_; 493 const char* GetName(); 494#ifdef DEBUG 495 void Print() { 496 PrintF("CompareStub (cc %d), (strict %s), " 497 "(never_nan_nan %s), (number_compare %s)\n", 498 static_cast<int>(cc_), 499 strict_ ? "true" : "false", 500 never_nan_nan_ ? "true" : "false", 501 include_number_compare_ ? "included" : "not included"); 502 } 503#endif 504}; 505 506 507class CEntryStub : public CodeStub { 508 public: 509 explicit CEntryStub(int result_size, 510 ExitFrame::Mode mode = ExitFrame::MODE_NORMAL) 511 : result_size_(result_size), mode_(mode) { } 512 513 void Generate(MacroAssembler* masm); 514 515 private: 516 void GenerateCore(MacroAssembler* masm, 517 Label* throw_normal_exception, 518 Label* throw_termination_exception, 519 Label* throw_out_of_memory_exception, 520 bool do_gc, 521 bool always_allocate_scope, 522 int alignment_skew = 0); 523 void GenerateThrowTOS(MacroAssembler* masm); 524 void GenerateThrowUncatchable(MacroAssembler* masm, 525 UncatchableExceptionType type); 526 527 // Number of pointers/values returned. 528 const int result_size_; 529 const ExitFrame::Mode mode_; 530 531 // Minor key encoding 532 class ExitFrameModeBits: public BitField<ExitFrame::Mode, 0, 1> {}; 533 class IndirectResultBits: public BitField<bool, 1, 1> {}; 534 535 Major MajorKey() { return CEntry; } 536 // Minor key must differ if different result_size_ values means different 537 // code is generated. 538 int MinorKey(); 539 540 const char* GetName() { return "CEntryStub"; } 541}; 542 543 544class ApiGetterEntryStub : public CodeStub { 545 public: 546 ApiGetterEntryStub(Handle<AccessorInfo> info, 547 ApiFunction* fun) 548 : info_(info), 549 fun_(fun) { } 550 void Generate(MacroAssembler* masm); 551 virtual bool has_custom_cache() { return true; } 552 virtual bool GetCustomCache(Code** code_out); 553 virtual void SetCustomCache(Code* value); 554 555 static const int kStackSpace = 5; 556 static const int kArgc = 4; 557 private: 558 Handle<AccessorInfo> info() { return info_; } 559 ApiFunction* fun() { return fun_; } 560 Major MajorKey() { return NoCache; } 561 int MinorKey() { return 0; } 562 const char* GetName() { return "ApiEntryStub"; } 563 // The accessor info associated with the function. 564 Handle<AccessorInfo> info_; 565 // The function to be called. 566 ApiFunction* fun_; 567}; 568 569 570class JSEntryStub : public CodeStub { 571 public: 572 JSEntryStub() { } 573 574 void Generate(MacroAssembler* masm) { GenerateBody(masm, false); } 575 576 protected: 577 void GenerateBody(MacroAssembler* masm, bool is_construct); 578 579 private: 580 Major MajorKey() { return JSEntry; } 581 int MinorKey() { return 0; } 582 583 const char* GetName() { return "JSEntryStub"; } 584}; 585 586 587class JSConstructEntryStub : public JSEntryStub { 588 public: 589 JSConstructEntryStub() { } 590 591 void Generate(MacroAssembler* masm) { GenerateBody(masm, true); } 592 593 private: 594 int MinorKey() { return 1; } 595 596 const char* GetName() { return "JSConstructEntryStub"; } 597}; 598 599 600class ArgumentsAccessStub: public CodeStub { 601 public: 602 enum Type { 603 READ_ELEMENT, 604 NEW_OBJECT 605 }; 606 607 explicit ArgumentsAccessStub(Type type) : type_(type) { } 608 609 private: 610 Type type_; 611 612 Major MajorKey() { return ArgumentsAccess; } 613 int MinorKey() { return type_; } 614 615 void Generate(MacroAssembler* masm); 616 void GenerateReadElement(MacroAssembler* masm); 617 void GenerateNewObject(MacroAssembler* masm); 618 619 const char* GetName() { return "ArgumentsAccessStub"; } 620 621#ifdef DEBUG 622 void Print() { 623 PrintF("ArgumentsAccessStub (type %d)\n", type_); 624 } 625#endif 626}; 627 628 629class RegExpExecStub: public CodeStub { 630 public: 631 RegExpExecStub() { } 632 633 private: 634 Major MajorKey() { return RegExpExec; } 635 int MinorKey() { return 0; } 636 637 void Generate(MacroAssembler* masm); 638 639 const char* GetName() { return "RegExpExecStub"; } 640 641#ifdef DEBUG 642 void Print() { 643 PrintF("RegExpExecStub\n"); 644 } 645#endif 646}; 647 648 649class CallFunctionStub: public CodeStub { 650 public: 651 CallFunctionStub(int argc, InLoopFlag in_loop, CallFunctionFlags flags) 652 : argc_(argc), in_loop_(in_loop), flags_(flags) { } 653 654 void Generate(MacroAssembler* masm); 655 656 private: 657 int argc_; 658 InLoopFlag in_loop_; 659 CallFunctionFlags flags_; 660 661#ifdef DEBUG 662 void Print() { 663 PrintF("CallFunctionStub (args %d, in_loop %d, flags %d)\n", 664 argc_, 665 static_cast<int>(in_loop_), 666 static_cast<int>(flags_)); 667 } 668#endif 669 670 // Minor key encoding in 32 bits with Bitfield <Type, shift, size>. 671 class InLoopBits: public BitField<InLoopFlag, 0, 1> {}; 672 class FlagBits: public BitField<CallFunctionFlags, 1, 1> {}; 673 class ArgcBits: public BitField<int, 2, 32 - 2> {}; 674 675 Major MajorKey() { return CallFunction; } 676 int MinorKey() { 677 // Encode the parameters in a unique 32 bit value. 678 return InLoopBits::encode(in_loop_) 679 | FlagBits::encode(flags_) 680 | ArgcBits::encode(argc_); 681 } 682 683 InLoopFlag InLoop() { return in_loop_; } 684 bool ReceiverMightBeValue() { 685 return (flags_ & RECEIVER_MIGHT_BE_VALUE) != 0; 686 } 687 688 public: 689 static int ExtractArgcFromMinorKey(int minor_key) { 690 return ArgcBits::decode(minor_key); 691 } 692}; 693 694 695class ToBooleanStub: public CodeStub { 696 public: 697 ToBooleanStub() { } 698 699 void Generate(MacroAssembler* masm); 700 701 private: 702 Major MajorKey() { return ToBoolean; } 703 int MinorKey() { return 0; } 704}; 705 706 707enum StringIndexFlags { 708 // Accepts smis or heap numbers. 709 STRING_INDEX_IS_NUMBER, 710 711 // Accepts smis or heap numbers that are valid array indices 712 // (ECMA-262 15.4). Invalid indices are reported as being out of 713 // range. 714 STRING_INDEX_IS_ARRAY_INDEX 715}; 716 717 718// Generates code implementing String.prototype.charCodeAt. 719// 720// Only supports the case when the receiver is a string and the index 721// is a number (smi or heap number) that is a valid index into the 722// string. Additional index constraints are specified by the 723// flags. Otherwise, bails out to the provided labels. 724// 725// Register usage: |object| may be changed to another string in a way 726// that doesn't affect charCodeAt/charAt semantics, |index| is 727// preserved, |scratch| and |result| are clobbered. 728class StringCharCodeAtGenerator { 729 public: 730 StringCharCodeAtGenerator(Register object, 731 Register index, 732 Register scratch, 733 Register result, 734 Label* receiver_not_string, 735 Label* index_not_number, 736 Label* index_out_of_range, 737 StringIndexFlags index_flags) 738 : object_(object), 739 index_(index), 740 scratch_(scratch), 741 result_(result), 742 receiver_not_string_(receiver_not_string), 743 index_not_number_(index_not_number), 744 index_out_of_range_(index_out_of_range), 745 index_flags_(index_flags) { 746 ASSERT(!scratch_.is(object_)); 747 ASSERT(!scratch_.is(index_)); 748 ASSERT(!scratch_.is(result_)); 749 ASSERT(!result_.is(object_)); 750 ASSERT(!result_.is(index_)); 751 } 752 753 // Generates the fast case code. On the fallthrough path |result| 754 // register contains the result. 755 void GenerateFast(MacroAssembler* masm); 756 757 // Generates the slow case code. Must not be naturally 758 // reachable. Expected to be put after a ret instruction (e.g., in 759 // deferred code). Always jumps back to the fast case. 760 void GenerateSlow(MacroAssembler* masm, 761 const RuntimeCallHelper& call_helper); 762 763 private: 764 Register object_; 765 Register index_; 766 Register scratch_; 767 Register result_; 768 769 Label* receiver_not_string_; 770 Label* index_not_number_; 771 Label* index_out_of_range_; 772 773 StringIndexFlags index_flags_; 774 775 Label call_runtime_; 776 Label index_not_smi_; 777 Label got_smi_index_; 778 Label exit_; 779 780 DISALLOW_COPY_AND_ASSIGN(StringCharCodeAtGenerator); 781}; 782 783 784// Generates code for creating a one-char string from a char code. 785class StringCharFromCodeGenerator { 786 public: 787 StringCharFromCodeGenerator(Register code, 788 Register result) 789 : code_(code), 790 result_(result) { 791 ASSERT(!code_.is(result_)); 792 } 793 794 // Generates the fast case code. On the fallthrough path |result| 795 // register contains the result. 796 void GenerateFast(MacroAssembler* masm); 797 798 // Generates the slow case code. Must not be naturally 799 // reachable. Expected to be put after a ret instruction (e.g., in 800 // deferred code). Always jumps back to the fast case. 801 void GenerateSlow(MacroAssembler* masm, 802 const RuntimeCallHelper& call_helper); 803 804 private: 805 Register code_; 806 Register result_; 807 808 Label slow_case_; 809 Label exit_; 810 811 DISALLOW_COPY_AND_ASSIGN(StringCharFromCodeGenerator); 812}; 813 814 815// Generates code implementing String.prototype.charAt. 816// 817// Only supports the case when the receiver is a string and the index 818// is a number (smi or heap number) that is a valid index into the 819// string. Additional index constraints are specified by the 820// flags. Otherwise, bails out to the provided labels. 821// 822// Register usage: |object| may be changed to another string in a way 823// that doesn't affect charCodeAt/charAt semantics, |index| is 824// preserved, |scratch1|, |scratch2|, and |result| are clobbered. 825class StringCharAtGenerator { 826 public: 827 StringCharAtGenerator(Register object, 828 Register index, 829 Register scratch1, 830 Register scratch2, 831 Register result, 832 Label* receiver_not_string, 833 Label* index_not_number, 834 Label* index_out_of_range, 835 StringIndexFlags index_flags) 836 : char_code_at_generator_(object, 837 index, 838 scratch1, 839 scratch2, 840 receiver_not_string, 841 index_not_number, 842 index_out_of_range, 843 index_flags), 844 char_from_code_generator_(scratch2, result) {} 845 846 // Generates the fast case code. On the fallthrough path |result| 847 // register contains the result. 848 void GenerateFast(MacroAssembler* masm); 849 850 // Generates the slow case code. Must not be naturally 851 // reachable. Expected to be put after a ret instruction (e.g., in 852 // deferred code). Always jumps back to the fast case. 853 void GenerateSlow(MacroAssembler* masm, 854 const RuntimeCallHelper& call_helper); 855 856 private: 857 StringCharCodeAtGenerator char_code_at_generator_; 858 StringCharFromCodeGenerator char_from_code_generator_; 859 860 DISALLOW_COPY_AND_ASSIGN(StringCharAtGenerator); 861}; 862 863 864} // namespace internal 865} // namespace v8 866 867#endif // V8_CODEGEN_H_ 868