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 |