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