| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 66 // CheckForInlineRuntimeCall | 66 // CheckForInlineRuntimeCall |
| 67 // PatchInlineRuntimeEntry | 67 // PatchInlineRuntimeEntry |
| 68 // AnalyzeCondition | 68 // AnalyzeCondition |
| 69 // CodeForFunctionPosition | 69 // CodeForFunctionPosition |
| 70 // CodeForReturnPosition | 70 // CodeForReturnPosition |
| 71 // CodeForStatementPosition | 71 // CodeForStatementPosition |
| 72 // CodeForDoWhileConditionPosition | 72 // CodeForDoWhileConditionPosition |
| 73 // CodeForSourcePosition | 73 // CodeForSourcePosition |
| 74 | 74 |
| 75 | 75 |
| 76 // Mode to overwrite BinaryExpression values. | |
| 77 enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT }; | |
| 78 enum UnaryOverwriteMode { UNARY_OVERWRITE, UNARY_NO_OVERWRITE }; | |
| 79 | |
| 80 // Types of uncatchable exceptions. | |
| 81 enum UncatchableExceptionType { OUT_OF_MEMORY, TERMINATION }; | |
| 82 | |
| 83 #define INLINE_RUNTIME_FUNCTION_LIST(F) \ | 76 #define INLINE_RUNTIME_FUNCTION_LIST(F) \ |
| 84 F(IsSmi, 1, 1) \ | 77 F(IsSmi, 1, 1) \ |
| 85 F(IsNonNegativeSmi, 1, 1) \ | 78 F(IsNonNegativeSmi, 1, 1) \ |
| 86 F(IsArray, 1, 1) \ | 79 F(IsArray, 1, 1) \ |
| 87 F(IsRegExp, 1, 1) \ | 80 F(IsRegExp, 1, 1) \ |
| 88 F(CallFunction, -1 /* receiver + n args + function */, 1) \ | 81 F(CallFunction, -1 /* receiver + n args + function */, 1) \ |
| 89 F(IsConstructCall, 0, 1) \ | 82 F(IsConstructCall, 0, 1) \ |
| 90 F(ArgumentsLength, 0, 1) \ | 83 F(ArgumentsLength, 0, 1) \ |
| 91 F(Arguments, 1, 1) \ | 84 F(Arguments, 1, 1) \ |
| 92 F(ClassOf, 1, 1) \ | 85 F(ClassOf, 1, 1) \ |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 131 #include "mips/codegen-mips.h" | 124 #include "mips/codegen-mips.h" |
| 132 #else | 125 #else |
| 133 #error Unsupported target architecture. | 126 #error Unsupported target architecture. |
| 134 #endif | 127 #endif |
| 135 | 128 |
| 136 #include "register-allocator.h" | 129 #include "register-allocator.h" |
| 137 | 130 |
| 138 namespace v8 { | 131 namespace v8 { |
| 139 namespace internal { | 132 namespace internal { |
| 140 | 133 |
| 141 // Support for "structured" code comments. | |
| 142 #ifdef DEBUG | |
| 143 | |
| 144 class Comment BASE_EMBEDDED { | |
| 145 public: | |
| 146 Comment(MacroAssembler* masm, const char* msg); | |
| 147 ~Comment(); | |
| 148 | |
| 149 private: | |
| 150 MacroAssembler* masm_; | |
| 151 const char* msg_; | |
| 152 }; | |
| 153 | |
| 154 #else | |
| 155 | |
| 156 class Comment BASE_EMBEDDED { | |
| 157 public: | |
| 158 Comment(MacroAssembler*, const char*) {} | |
| 159 }; | |
| 160 | |
| 161 #endif // DEBUG | |
| 162 | |
| 163 | |
| 164 // Code generation can be nested. Code generation scopes form a stack | 134 // Code generation can be nested. Code generation scopes form a stack |
| 165 // of active code generators. | 135 // of active code generators. |
| 166 class CodeGeneratorScope BASE_EMBEDDED { | 136 class CodeGeneratorScope BASE_EMBEDDED { |
| 167 public: | 137 public: |
| 168 explicit CodeGeneratorScope(CodeGenerator* cgen) { | 138 explicit CodeGeneratorScope(CodeGenerator* cgen) { |
| 169 previous_ = top_; | 139 previous_ = top_; |
| 170 top_ = cgen; | 140 top_ = cgen; |
| 171 } | 141 } |
| 172 | 142 |
| 173 ~CodeGeneratorScope() { | 143 ~CodeGeneratorScope() { |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 226 VirtualFrame frame_; | 196 VirtualFrame frame_; |
| 227 }; | 197 }; |
| 228 | 198 |
| 229 #else | 199 #else |
| 230 | 200 |
| 231 #error Unsupported target architecture. | 201 #error Unsupported target architecture. |
| 232 | 202 |
| 233 #endif | 203 #endif |
| 234 | 204 |
| 235 | 205 |
| 236 // Helper interface to prepare to/restore after making runtime calls. | |
| 237 class RuntimeCallHelper { | |
| 238 public: | |
| 239 virtual ~RuntimeCallHelper() {} | |
| 240 | |
| 241 virtual void BeforeCall(MacroAssembler* masm) const = 0; | |
| 242 | |
| 243 virtual void AfterCall(MacroAssembler* masm) const = 0; | |
| 244 | |
| 245 protected: | |
| 246 RuntimeCallHelper() {} | |
| 247 | |
| 248 private: | |
| 249 DISALLOW_COPY_AND_ASSIGN(RuntimeCallHelper); | |
| 250 }; | |
| 251 | |
| 252 | |
| 253 // RuntimeCallHelper implementation that saves/restores state of a | 206 // RuntimeCallHelper implementation that saves/restores state of a |
| 254 // virtual frame. | 207 // virtual frame. |
| 255 class VirtualFrameRuntimeCallHelper : public RuntimeCallHelper { | 208 class VirtualFrameRuntimeCallHelper : public RuntimeCallHelper { |
| 256 public: | 209 public: |
| 257 // Does not take ownership of |frame_state|. | 210 // Does not take ownership of |frame_state|. |
| 258 explicit VirtualFrameRuntimeCallHelper(const FrameRegisterState* frame_state) | 211 explicit VirtualFrameRuntimeCallHelper(const FrameRegisterState* frame_state) |
| 259 : frame_state_(frame_state) {} | 212 : frame_state_(frame_state) {} |
| 260 | 213 |
| 261 virtual void BeforeCall(MacroAssembler* masm) const; | 214 virtual void BeforeCall(MacroAssembler* masm) const; |
| 262 | 215 |
| 263 virtual void AfterCall(MacroAssembler* masm) const; | 216 virtual void AfterCall(MacroAssembler* masm) const; |
| 264 | 217 |
| 265 private: | 218 private: |
| 266 const FrameRegisterState* frame_state_; | 219 const FrameRegisterState* frame_state_; |
| 267 }; | 220 }; |
| 268 | 221 |
| 269 | 222 |
| 270 // RuntimeCallHelper implementation used in IC stubs: enters/leaves a | |
| 271 // newly created internal frame before/after the runtime call. | |
| 272 class ICRuntimeCallHelper : public RuntimeCallHelper { | |
| 273 public: | |
| 274 ICRuntimeCallHelper() {} | |
| 275 | |
| 276 virtual void BeforeCall(MacroAssembler* masm) const; | |
| 277 | |
| 278 virtual void AfterCall(MacroAssembler* masm) const; | |
| 279 }; | |
| 280 | |
| 281 | |
| 282 // Trivial RuntimeCallHelper implementation. | |
| 283 class NopRuntimeCallHelper : public RuntimeCallHelper { | |
| 284 public: | |
| 285 NopRuntimeCallHelper() {} | |
| 286 | |
| 287 virtual void BeforeCall(MacroAssembler* masm) const {} | |
| 288 | |
| 289 virtual void AfterCall(MacroAssembler* masm) const {} | |
| 290 }; | |
| 291 | |
| 292 | |
| 293 // Deferred code objects are small pieces of code that are compiled | 223 // Deferred code objects are small pieces of code that are compiled |
| 294 // out of line. They are used to defer the compilation of uncommon | 224 // out of line. They are used to defer the compilation of uncommon |
| 295 // paths thereby avoiding expensive jumps around uncommon code parts. | 225 // paths thereby avoiding expensive jumps around uncommon code parts. |
| 296 class DeferredCode: public ZoneObject { | 226 class DeferredCode: public ZoneObject { |
| 297 public: | 227 public: |
| 298 DeferredCode(); | 228 DeferredCode(); |
| 299 virtual ~DeferredCode() { } | 229 virtual ~DeferredCode() { } |
| 300 | 230 |
| 301 virtual void Generate() = 0; | 231 virtual void Generate() = 0; |
| 302 | 232 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 345 Label exit_label_; | 275 Label exit_label_; |
| 346 | 276 |
| 347 FrameRegisterState frame_state_; | 277 FrameRegisterState frame_state_; |
| 348 | 278 |
| 349 #ifdef DEBUG | 279 #ifdef DEBUG |
| 350 const char* comment_; | 280 const char* comment_; |
| 351 #endif | 281 #endif |
| 352 DISALLOW_COPY_AND_ASSIGN(DeferredCode); | 282 DISALLOW_COPY_AND_ASSIGN(DeferredCode); |
| 353 }; | 283 }; |
| 354 | 284 |
| 355 class StackCheckStub : public CodeStub { | |
| 356 public: | |
| 357 StackCheckStub() { } | |
| 358 | 285 |
| 359 void Generate(MacroAssembler* masm); | 286 } } // namespace v8::internal |
| 360 | |
| 361 private: | |
| 362 | |
| 363 const char* GetName() { return "StackCheckStub"; } | |
| 364 | |
| 365 Major MajorKey() { return StackCheck; } | |
| 366 int MinorKey() { return 0; } | |
| 367 }; | |
| 368 | |
| 369 | |
| 370 class FastNewClosureStub : public CodeStub { | |
| 371 public: | |
| 372 void Generate(MacroAssembler* masm); | |
| 373 | |
| 374 private: | |
| 375 const char* GetName() { return "FastNewClosureStub"; } | |
| 376 Major MajorKey() { return FastNewClosure; } | |
| 377 int MinorKey() { return 0; } | |
| 378 }; | |
| 379 | |
| 380 | |
| 381 class FastNewContextStub : public CodeStub { | |
| 382 public: | |
| 383 static const int kMaximumSlots = 64; | |
| 384 | |
| 385 explicit FastNewContextStub(int slots) : slots_(slots) { | |
| 386 ASSERT(slots_ > 0 && slots <= kMaximumSlots); | |
| 387 } | |
| 388 | |
| 389 void Generate(MacroAssembler* masm); | |
| 390 | |
| 391 private: | |
| 392 int slots_; | |
| 393 | |
| 394 const char* GetName() { return "FastNewContextStub"; } | |
| 395 Major MajorKey() { return FastNewContext; } | |
| 396 int MinorKey() { return slots_; } | |
| 397 }; | |
| 398 | |
| 399 | |
| 400 class FastCloneShallowArrayStub : public CodeStub { | |
| 401 public: | |
| 402 // Maximum length of copied elements array. | |
| 403 static const int kMaximumClonedLength = 8; | |
| 404 | |
| 405 enum Mode { | |
| 406 CLONE_ELEMENTS, | |
| 407 COPY_ON_WRITE_ELEMENTS | |
| 408 }; | |
| 409 | |
| 410 FastCloneShallowArrayStub(Mode mode, int length) | |
| 411 : mode_(mode), | |
| 412 length_((mode == COPY_ON_WRITE_ELEMENTS) ? 0 : length) { | |
| 413 ASSERT(length_ >= 0); | |
| 414 ASSERT(length_ <= kMaximumClonedLength); | |
| 415 } | |
| 416 | |
| 417 void Generate(MacroAssembler* masm); | |
| 418 | |
| 419 private: | |
| 420 Mode mode_; | |
| 421 int length_; | |
| 422 | |
| 423 const char* GetName() { return "FastCloneShallowArrayStub"; } | |
| 424 Major MajorKey() { return FastCloneShallowArray; } | |
| 425 int MinorKey() { | |
| 426 ASSERT(mode_ == 0 || mode_ == 1); | |
| 427 return (length_ << 1) | mode_; | |
| 428 } | |
| 429 }; | |
| 430 | |
| 431 | |
| 432 class InstanceofStub: public CodeStub { | |
| 433 public: | |
| 434 InstanceofStub() { } | |
| 435 | |
| 436 void Generate(MacroAssembler* masm); | |
| 437 | |
| 438 private: | |
| 439 Major MajorKey() { return Instanceof; } | |
| 440 int MinorKey() { return 0; } | |
| 441 }; | |
| 442 | |
| 443 | |
| 444 enum NegativeZeroHandling { | |
| 445 kStrictNegativeZero, | |
| 446 kIgnoreNegativeZero | |
| 447 }; | |
| 448 | |
| 449 | |
| 450 class GenericUnaryOpStub : public CodeStub { | |
| 451 public: | |
| 452 GenericUnaryOpStub(Token::Value op, | |
| 453 UnaryOverwriteMode overwrite, | |
| 454 NegativeZeroHandling negative_zero = kStrictNegativeZero) | |
| 455 : op_(op), overwrite_(overwrite), negative_zero_(negative_zero) { } | |
| 456 | |
| 457 private: | |
| 458 Token::Value op_; | |
| 459 UnaryOverwriteMode overwrite_; | |
| 460 NegativeZeroHandling negative_zero_; | |
| 461 | |
| 462 class OverwriteField: public BitField<UnaryOverwriteMode, 0, 1> {}; | |
| 463 class NegativeZeroField: public BitField<NegativeZeroHandling, 1, 1> {}; | |
| 464 class OpField: public BitField<Token::Value, 2, kMinorBits - 2> {}; | |
| 465 | |
| 466 Major MajorKey() { return GenericUnaryOp; } | |
| 467 int MinorKey() { | |
| 468 return OpField::encode(op_) | | |
| 469 OverwriteField::encode(overwrite_) | | |
| 470 NegativeZeroField::encode(negative_zero_); | |
| 471 } | |
| 472 | |
| 473 void Generate(MacroAssembler* masm); | |
| 474 | |
| 475 const char* GetName(); | |
| 476 }; | |
| 477 | |
| 478 | |
| 479 enum NaNInformation { | |
| 480 kBothCouldBeNaN, | |
| 481 kCantBothBeNaN | |
| 482 }; | |
| 483 | |
| 484 | |
| 485 class CompareStub: public CodeStub { | |
| 486 public: | |
| 487 CompareStub(Condition cc, | |
| 488 bool strict, | |
| 489 NaNInformation nan_info = kBothCouldBeNaN, | |
| 490 bool include_number_compare = true, | |
| 491 Register lhs = no_reg, | |
| 492 Register rhs = no_reg) : | |
| 493 cc_(cc), | |
| 494 strict_(strict), | |
| 495 never_nan_nan_(nan_info == kCantBothBeNaN), | |
| 496 include_number_compare_(include_number_compare), | |
| 497 lhs_(lhs), | |
| 498 rhs_(rhs), | |
| 499 name_(NULL) { } | |
| 500 | |
| 501 void Generate(MacroAssembler* masm); | |
| 502 | |
| 503 private: | |
| 504 Condition cc_; | |
| 505 bool strict_; | |
| 506 // Only used for 'equal' comparisons. Tells the stub that we already know | |
| 507 // that at least one side of the comparison is not NaN. This allows the | |
| 508 // stub to use object identity in the positive case. We ignore it when | |
| 509 // generating the minor key for other comparisons to avoid creating more | |
| 510 // stubs. | |
| 511 bool never_nan_nan_; | |
| 512 // Do generate the number comparison code in the stub. Stubs without number | |
| 513 // comparison code is used when the number comparison has been inlined, and | |
| 514 // the stub will be called if one of the operands is not a number. | |
| 515 bool include_number_compare_; | |
| 516 // Register holding the left hand side of the comparison if the stub gives | |
| 517 // a choice, no_reg otherwise. | |
| 518 Register lhs_; | |
| 519 // Register holding the right hand side of the comparison if the stub gives | |
| 520 // a choice, no_reg otherwise. | |
| 521 Register rhs_; | |
| 522 | |
| 523 // Encoding of the minor key CCCCCCCCCCCCRCNS. | |
| 524 class StrictField: public BitField<bool, 0, 1> {}; | |
| 525 class NeverNanNanField: public BitField<bool, 1, 1> {}; | |
| 526 class IncludeNumberCompareField: public BitField<bool, 2, 1> {}; | |
| 527 class RegisterField: public BitField<bool, 3, 1> {}; | |
| 528 class ConditionField: public BitField<int, 4, 12> {}; | |
| 529 | |
| 530 Major MajorKey() { return Compare; } | |
| 531 | |
| 532 int MinorKey(); | |
| 533 | |
| 534 // Branch to the label if the given object isn't a symbol. | |
| 535 void BranchIfNonSymbol(MacroAssembler* masm, | |
| 536 Label* label, | |
| 537 Register object, | |
| 538 Register scratch); | |
| 539 | |
| 540 // Unfortunately you have to run without snapshots to see most of these | |
| 541 // names in the profile since most compare stubs end up in the snapshot. | |
| 542 char* name_; | |
| 543 const char* GetName(); | |
| 544 #ifdef DEBUG | |
| 545 void Print() { | |
| 546 PrintF("CompareStub (cc %d), (strict %s), " | |
| 547 "(never_nan_nan %s), (number_compare %s) ", | |
| 548 static_cast<int>(cc_), | |
| 549 strict_ ? "true" : "false", | |
| 550 never_nan_nan_ ? "true" : "false", | |
| 551 include_number_compare_ ? "included" : "not included"); | |
| 552 | |
| 553 if (!lhs_.is(no_reg) && !rhs_.is(no_reg)) { | |
| 554 PrintF("(lhs r%d), (rhs r%d)\n", lhs_.code(), rhs_.code()); | |
| 555 } else { | |
| 556 PrintF("\n"); | |
| 557 } | |
| 558 } | |
| 559 #endif | |
| 560 }; | |
| 561 | |
| 562 | |
| 563 class CEntryStub : public CodeStub { | |
| 564 public: | |
| 565 explicit CEntryStub(int result_size) : result_size_(result_size) { } | |
| 566 | |
| 567 void Generate(MacroAssembler* masm); | |
| 568 | |
| 569 private: | |
| 570 void GenerateCore(MacroAssembler* masm, | |
| 571 Label* throw_normal_exception, | |
| 572 Label* throw_termination_exception, | |
| 573 Label* throw_out_of_memory_exception, | |
| 574 bool do_gc, | |
| 575 bool always_allocate_scope, | |
| 576 int alignment_skew = 0); | |
| 577 void GenerateThrowTOS(MacroAssembler* masm); | |
| 578 void GenerateThrowUncatchable(MacroAssembler* masm, | |
| 579 UncatchableExceptionType type); | |
| 580 | |
| 581 // Number of pointers/values returned. | |
| 582 const int result_size_; | |
| 583 | |
| 584 // Minor key encoding | |
| 585 class IndirectResultBits: public BitField<bool, 1, 1> {}; | |
| 586 | |
| 587 Major MajorKey() { return CEntry; } | |
| 588 // Minor key must differ if different result_size_ values means different | |
| 589 // code is generated. | |
| 590 int MinorKey(); | |
| 591 | |
| 592 const char* GetName() { return "CEntryStub"; } | |
| 593 }; | |
| 594 | |
| 595 | |
| 596 class ApiGetterEntryStub : public CodeStub { | |
| 597 public: | |
| 598 ApiGetterEntryStub(Handle<AccessorInfo> info, | |
| 599 ApiFunction* fun) | |
| 600 : info_(info), | |
| 601 fun_(fun) { } | |
| 602 void Generate(MacroAssembler* masm); | |
| 603 virtual bool has_custom_cache() { return true; } | |
| 604 virtual bool GetCustomCache(Code** code_out); | |
| 605 virtual void SetCustomCache(Code* value); | |
| 606 | |
| 607 static const int kStackSpace = 5; | |
| 608 static const int kArgc = 4; | |
| 609 private: | |
| 610 Handle<AccessorInfo> info() { return info_; } | |
| 611 ApiFunction* fun() { return fun_; } | |
| 612 Major MajorKey() { return NoCache; } | |
| 613 int MinorKey() { return 0; } | |
| 614 const char* GetName() { return "ApiEntryStub"; } | |
| 615 // The accessor info associated with the function. | |
| 616 Handle<AccessorInfo> info_; | |
| 617 // The function to be called. | |
| 618 ApiFunction* fun_; | |
| 619 }; | |
| 620 | |
| 621 | |
| 622 class JSEntryStub : public CodeStub { | |
| 623 public: | |
| 624 JSEntryStub() { } | |
| 625 | |
| 626 void Generate(MacroAssembler* masm) { GenerateBody(masm, false); } | |
| 627 | |
| 628 protected: | |
| 629 void GenerateBody(MacroAssembler* masm, bool is_construct); | |
| 630 | |
| 631 private: | |
| 632 Major MajorKey() { return JSEntry; } | |
| 633 int MinorKey() { return 0; } | |
| 634 | |
| 635 const char* GetName() { return "JSEntryStub"; } | |
| 636 }; | |
| 637 | |
| 638 | |
| 639 class JSConstructEntryStub : public JSEntryStub { | |
| 640 public: | |
| 641 JSConstructEntryStub() { } | |
| 642 | |
| 643 void Generate(MacroAssembler* masm) { GenerateBody(masm, true); } | |
| 644 | |
| 645 private: | |
| 646 int MinorKey() { return 1; } | |
| 647 | |
| 648 const char* GetName() { return "JSConstructEntryStub"; } | |
| 649 }; | |
| 650 | |
| 651 | |
| 652 class ArgumentsAccessStub: public CodeStub { | |
| 653 public: | |
| 654 enum Type { | |
| 655 READ_ELEMENT, | |
| 656 NEW_OBJECT | |
| 657 }; | |
| 658 | |
| 659 explicit ArgumentsAccessStub(Type type) : type_(type) { } | |
| 660 | |
| 661 private: | |
| 662 Type type_; | |
| 663 | |
| 664 Major MajorKey() { return ArgumentsAccess; } | |
| 665 int MinorKey() { return type_; } | |
| 666 | |
| 667 void Generate(MacroAssembler* masm); | |
| 668 void GenerateReadElement(MacroAssembler* masm); | |
| 669 void GenerateNewObject(MacroAssembler* masm); | |
| 670 | |
| 671 const char* GetName() { return "ArgumentsAccessStub"; } | |
| 672 | |
| 673 #ifdef DEBUG | |
| 674 void Print() { | |
| 675 PrintF("ArgumentsAccessStub (type %d)\n", type_); | |
| 676 } | |
| 677 #endif | |
| 678 }; | |
| 679 | |
| 680 | |
| 681 class RegExpExecStub: public CodeStub { | |
| 682 public: | |
| 683 RegExpExecStub() { } | |
| 684 | |
| 685 private: | |
| 686 Major MajorKey() { return RegExpExec; } | |
| 687 int MinorKey() { return 0; } | |
| 688 | |
| 689 void Generate(MacroAssembler* masm); | |
| 690 | |
| 691 const char* GetName() { return "RegExpExecStub"; } | |
| 692 | |
| 693 #ifdef DEBUG | |
| 694 void Print() { | |
| 695 PrintF("RegExpExecStub\n"); | |
| 696 } | |
| 697 #endif | |
| 698 }; | |
| 699 | |
| 700 | |
| 701 class CallFunctionStub: public CodeStub { | |
| 702 public: | |
| 703 CallFunctionStub(int argc, InLoopFlag in_loop, CallFunctionFlags flags) | |
| 704 : argc_(argc), in_loop_(in_loop), flags_(flags) { } | |
| 705 | |
| 706 void Generate(MacroAssembler* masm); | |
| 707 | |
| 708 private: | |
| 709 int argc_; | |
| 710 InLoopFlag in_loop_; | |
| 711 CallFunctionFlags flags_; | |
| 712 | |
| 713 #ifdef DEBUG | |
| 714 void Print() { | |
| 715 PrintF("CallFunctionStub (args %d, in_loop %d, flags %d)\n", | |
| 716 argc_, | |
| 717 static_cast<int>(in_loop_), | |
| 718 static_cast<int>(flags_)); | |
| 719 } | |
| 720 #endif | |
| 721 | |
| 722 // Minor key encoding in 32 bits with Bitfield <Type, shift, size>. | |
| 723 class InLoopBits: public BitField<InLoopFlag, 0, 1> {}; | |
| 724 class FlagBits: public BitField<CallFunctionFlags, 1, 1> {}; | |
| 725 class ArgcBits: public BitField<int, 2, 32 - 2> {}; | |
| 726 | |
| 727 Major MajorKey() { return CallFunction; } | |
| 728 int MinorKey() { | |
| 729 // Encode the parameters in a unique 32 bit value. | |
| 730 return InLoopBits::encode(in_loop_) | |
| 731 | FlagBits::encode(flags_) | |
| 732 | ArgcBits::encode(argc_); | |
| 733 } | |
| 734 | |
| 735 InLoopFlag InLoop() { return in_loop_; } | |
| 736 bool ReceiverMightBeValue() { | |
| 737 return (flags_ & RECEIVER_MIGHT_BE_VALUE) != 0; | |
| 738 } | |
| 739 | |
| 740 public: | |
| 741 static int ExtractArgcFromMinorKey(int minor_key) { | |
| 742 return ArgcBits::decode(minor_key); | |
| 743 } | |
| 744 }; | |
| 745 | |
| 746 | |
| 747 enum StringIndexFlags { | |
| 748 // Accepts smis or heap numbers. | |
| 749 STRING_INDEX_IS_NUMBER, | |
| 750 | |
| 751 // Accepts smis or heap numbers that are valid array indices | |
| 752 // (ECMA-262 15.4). Invalid indices are reported as being out of | |
| 753 // range. | |
| 754 STRING_INDEX_IS_ARRAY_INDEX | |
| 755 }; | |
| 756 | |
| 757 | |
| 758 // Generates code implementing String.prototype.charCodeAt. | |
| 759 // | |
| 760 // Only supports the case when the receiver is a string and the index | |
| 761 // is a number (smi or heap number) that is a valid index into the | |
| 762 // string. Additional index constraints are specified by the | |
| 763 // flags. Otherwise, bails out to the provided labels. | |
| 764 // | |
| 765 // Register usage: |object| may be changed to another string in a way | |
| 766 // that doesn't affect charCodeAt/charAt semantics, |index| is | |
| 767 // preserved, |scratch| and |result| are clobbered. | |
| 768 class StringCharCodeAtGenerator { | |
| 769 public: | |
| 770 StringCharCodeAtGenerator(Register object, | |
| 771 Register index, | |
| 772 Register scratch, | |
| 773 Register result, | |
| 774 Label* receiver_not_string, | |
| 775 Label* index_not_number, | |
| 776 Label* index_out_of_range, | |
| 777 StringIndexFlags index_flags) | |
| 778 : object_(object), | |
| 779 index_(index), | |
| 780 scratch_(scratch), | |
| 781 result_(result), | |
| 782 receiver_not_string_(receiver_not_string), | |
| 783 index_not_number_(index_not_number), | |
| 784 index_out_of_range_(index_out_of_range), | |
| 785 index_flags_(index_flags) { | |
| 786 ASSERT(!scratch_.is(object_)); | |
| 787 ASSERT(!scratch_.is(index_)); | |
| 788 ASSERT(!scratch_.is(result_)); | |
| 789 ASSERT(!result_.is(object_)); | |
| 790 ASSERT(!result_.is(index_)); | |
| 791 } | |
| 792 | |
| 793 // Generates the fast case code. On the fallthrough path |result| | |
| 794 // register contains the result. | |
| 795 void GenerateFast(MacroAssembler* masm); | |
| 796 | |
| 797 // Generates the slow case code. Must not be naturally | |
| 798 // reachable. Expected to be put after a ret instruction (e.g., in | |
| 799 // deferred code). Always jumps back to the fast case. | |
| 800 void GenerateSlow(MacroAssembler* masm, | |
| 801 const RuntimeCallHelper& call_helper); | |
| 802 | |
| 803 private: | |
| 804 Register object_; | |
| 805 Register index_; | |
| 806 Register scratch_; | |
| 807 Register result_; | |
| 808 | |
| 809 Label* receiver_not_string_; | |
| 810 Label* index_not_number_; | |
| 811 Label* index_out_of_range_; | |
| 812 | |
| 813 StringIndexFlags index_flags_; | |
| 814 | |
| 815 Label call_runtime_; | |
| 816 Label index_not_smi_; | |
| 817 Label got_smi_index_; | |
| 818 Label exit_; | |
| 819 | |
| 820 DISALLOW_COPY_AND_ASSIGN(StringCharCodeAtGenerator); | |
| 821 }; | |
| 822 | |
| 823 | |
| 824 // Generates code for creating a one-char string from a char code. | |
| 825 class StringCharFromCodeGenerator { | |
| 826 public: | |
| 827 StringCharFromCodeGenerator(Register code, | |
| 828 Register result) | |
| 829 : code_(code), | |
| 830 result_(result) { | |
| 831 ASSERT(!code_.is(result_)); | |
| 832 } | |
| 833 | |
| 834 // Generates the fast case code. On the fallthrough path |result| | |
| 835 // register contains the result. | |
| 836 void GenerateFast(MacroAssembler* masm); | |
| 837 | |
| 838 // Generates the slow case code. Must not be naturally | |
| 839 // reachable. Expected to be put after a ret instruction (e.g., in | |
| 840 // deferred code). Always jumps back to the fast case. | |
| 841 void GenerateSlow(MacroAssembler* masm, | |
| 842 const RuntimeCallHelper& call_helper); | |
| 843 | |
| 844 private: | |
| 845 Register code_; | |
| 846 Register result_; | |
| 847 | |
| 848 Label slow_case_; | |
| 849 Label exit_; | |
| 850 | |
| 851 DISALLOW_COPY_AND_ASSIGN(StringCharFromCodeGenerator); | |
| 852 }; | |
| 853 | |
| 854 | |
| 855 // Generates code implementing String.prototype.charAt. | |
| 856 // | |
| 857 // Only supports the case when the receiver is a string and the index | |
| 858 // is a number (smi or heap number) that is a valid index into the | |
| 859 // string. Additional index constraints are specified by the | |
| 860 // flags. Otherwise, bails out to the provided labels. | |
| 861 // | |
| 862 // Register usage: |object| may be changed to another string in a way | |
| 863 // that doesn't affect charCodeAt/charAt semantics, |index| is | |
| 864 // preserved, |scratch1|, |scratch2|, and |result| are clobbered. | |
| 865 class StringCharAtGenerator { | |
| 866 public: | |
| 867 StringCharAtGenerator(Register object, | |
| 868 Register index, | |
| 869 Register scratch1, | |
| 870 Register scratch2, | |
| 871 Register result, | |
| 872 Label* receiver_not_string, | |
| 873 Label* index_not_number, | |
| 874 Label* index_out_of_range, | |
| 875 StringIndexFlags index_flags) | |
| 876 : char_code_at_generator_(object, | |
| 877 index, | |
| 878 scratch1, | |
| 879 scratch2, | |
| 880 receiver_not_string, | |
| 881 index_not_number, | |
| 882 index_out_of_range, | |
| 883 index_flags), | |
| 884 char_from_code_generator_(scratch2, result) {} | |
| 885 | |
| 886 // Generates the fast case code. On the fallthrough path |result| | |
| 887 // register contains the result. | |
| 888 void GenerateFast(MacroAssembler* masm); | |
| 889 | |
| 890 // Generates the slow case code. Must not be naturally | |
| 891 // reachable. Expected to be put after a ret instruction (e.g., in | |
| 892 // deferred code). Always jumps back to the fast case. | |
| 893 void GenerateSlow(MacroAssembler* masm, | |
| 894 const RuntimeCallHelper& call_helper); | |
| 895 | |
| 896 private: | |
| 897 StringCharCodeAtGenerator char_code_at_generator_; | |
| 898 StringCharFromCodeGenerator char_from_code_generator_; | |
| 899 | |
| 900 DISALLOW_COPY_AND_ASSIGN(StringCharAtGenerator); | |
| 901 }; | |
| 902 | |
| 903 | |
| 904 } // namespace internal | |
| 905 } // namespace v8 | |
| 906 | 287 |
| 907 #endif // V8_CODEGEN_H_ | 288 #endif // V8_CODEGEN_H_ |
| OLD | NEW |