1// Copyright 2012 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_UTILS_H_
6#define V8_UTILS_H_
7
8#include <limits.h>
9#include <stdlib.h>
10#include <string.h>
11#include <cmath>
12
13#include "include/v8.h"
14#include "src/allocation.h"
15#include "src/base/bits.h"
16#include "src/base/logging.h"
17#include "src/base/macros.h"
18#include "src/base/platform/platform.h"
19#include "src/globals.h"
20#include "src/list.h"
21#include "src/vector.h"
22
23namespace v8 {
24namespace internal {
25
26// ----------------------------------------------------------------------------
27// General helper functions
28
29
30// Same as strcmp, but can handle NULL arguments.
31inline bool CStringEquals(const char* s1, const char* s2) {
32  return (s1 == s2) || (s1 != NULL && s2 != NULL && strcmp(s1, s2) == 0);
33}
34
35
36// X must be a power of 2.  Returns the number of trailing zeros.
37inline int WhichPowerOf2(uint32_t x) {
38  DCHECK(base::bits::IsPowerOfTwo32(x));
39  int bits = 0;
40#ifdef DEBUG
41  int original_x = x;
42#endif
43  if (x >= 0x10000) {
44    bits += 16;
45    x >>= 16;
46  }
47  if (x >= 0x100) {
48    bits += 8;
49    x >>= 8;
50  }
51  if (x >= 0x10) {
52    bits += 4;
53    x >>= 4;
54  }
55  switch (x) {
56    default: UNREACHABLE();
57    case 8: bits++;  // Fall through.
58    case 4: bits++;  // Fall through.
59    case 2: bits++;  // Fall through.
60    case 1: break;
61  }
62  DCHECK_EQ(1 << bits, original_x);
63  return bits;
64  return 0;
65}
66
67
68inline int MostSignificantBit(uint32_t x) {
69  static const int msb4[] = {0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4};
70  int nibble = 0;
71  if (x & 0xffff0000) {
72    nibble += 16;
73    x >>= 16;
74  }
75  if (x & 0xff00) {
76    nibble += 8;
77    x >>= 8;
78  }
79  if (x & 0xf0) {
80    nibble += 4;
81    x >>= 4;
82  }
83  return nibble + msb4[x];
84}
85
86
87// The C++ standard leaves the semantics of '>>' undefined for
88// negative signed operands. Most implementations do the right thing,
89// though.
90inline int ArithmeticShiftRight(int x, int s) {
91  return x >> s;
92}
93
94
95template <typename T>
96int Compare(const T& a, const T& b) {
97  if (a == b)
98    return 0;
99  else if (a < b)
100    return -1;
101  else
102    return 1;
103}
104
105
106template <typename T>
107int PointerValueCompare(const T* a, const T* b) {
108  return Compare<T>(*a, *b);
109}
110
111
112// Compare function to compare the object pointer value of two
113// handlified objects. The handles are passed as pointers to the
114// handles.
115template<typename T> class Handle;  // Forward declaration.
116template <typename T>
117int HandleObjectPointerCompare(const Handle<T>* a, const Handle<T>* b) {
118  return Compare<T*>(*(*a), *(*b));
119}
120
121
122template <typename T, typename U>
123inline bool IsAligned(T value, U alignment) {
124  return (value & (alignment - 1)) == 0;
125}
126
127
128// Returns true if (addr + offset) is aligned.
129inline bool IsAddressAligned(Address addr,
130                             intptr_t alignment,
131                             int offset = 0) {
132  intptr_t offs = OffsetFrom(addr + offset);
133  return IsAligned(offs, alignment);
134}
135
136
137// Returns the maximum of the two parameters.
138template <typename T>
139T Max(T a, T b) {
140  return a < b ? b : a;
141}
142
143
144// Returns the minimum of the two parameters.
145template <typename T>
146T Min(T a, T b) {
147  return a < b ? a : b;
148}
149
150
151// Returns the absolute value of its argument.
152template <typename T>
153T Abs(T a) {
154  return a < 0 ? -a : a;
155}
156
157
158// Floor(-0.0) == 0.0
159inline double Floor(double x) {
160#ifdef _MSC_VER
161  if (x == 0) return x;  // Fix for issue 3477.
162#endif
163  return std::floor(x);
164}
165
166
167// TODO(svenpanne) Clean up the whole power-of-2 mess.
168inline int32_t WhichPowerOf2Abs(int32_t x) {
169  return (x == kMinInt) ? 31 : WhichPowerOf2(Abs(x));
170}
171
172
173// Obtains the unsigned type corresponding to T
174// available in C++11 as std::make_unsigned
175template<typename T>
176struct make_unsigned {
177  typedef T type;
178};
179
180
181// Template specializations necessary to have make_unsigned work
182template<> struct make_unsigned<int32_t> {
183  typedef uint32_t type;
184};
185
186
187template<> struct make_unsigned<int64_t> {
188  typedef uint64_t type;
189};
190
191
192// ----------------------------------------------------------------------------
193// BitField is a help template for encoding and decode bitfield with
194// unsigned content.
195
196template<class T, int shift, int size, class U>
197class BitFieldBase {
198 public:
199  // A type U mask of bit field.  To use all bits of a type U of x bits
200  // in a bitfield without compiler warnings we have to compute 2^x
201  // without using a shift count of x in the computation.
202  static const U kOne = static_cast<U>(1U);
203  static const U kMask = ((kOne << shift) << size) - (kOne << shift);
204  static const U kShift = shift;
205  static const U kSize = size;
206  static const U kNext = kShift + kSize;
207
208  // Value for the field with all bits set.
209  static const T kMax = static_cast<T>((1U << size) - 1);
210
211  // Tells whether the provided value fits into the bit field.
212  static bool is_valid(T value) {
213    return (static_cast<U>(value) & ~static_cast<U>(kMax)) == 0;
214  }
215
216  // Returns a type U with the bit field value encoded.
217  static U encode(T value) {
218    DCHECK(is_valid(value));
219    return static_cast<U>(value) << shift;
220  }
221
222  // Returns a type U with the bit field value updated.
223  static U update(U previous, T value) {
224    return (previous & ~kMask) | encode(value);
225  }
226
227  // Extracts the bit field from the value.
228  static T decode(U value) {
229    return static_cast<T>((value & kMask) >> shift);
230  }
231};
232
233
234template<class T, int shift, int size>
235class BitField : public BitFieldBase<T, shift, size, uint32_t> { };
236
237
238template<class T, int shift, int size>
239class BitField64 : public BitFieldBase<T, shift, size, uint64_t> { };
240
241
242// ----------------------------------------------------------------------------
243// Hash function.
244
245static const uint32_t kZeroHashSeed = 0;
246
247// Thomas Wang, Integer Hash Functions.
248// http://www.concentric.net/~Ttwang/tech/inthash.htm
249inline uint32_t ComputeIntegerHash(uint32_t key, uint32_t seed) {
250  uint32_t hash = key;
251  hash = hash ^ seed;
252  hash = ~hash + (hash << 15);  // hash = (hash << 15) - hash - 1;
253  hash = hash ^ (hash >> 12);
254  hash = hash + (hash << 2);
255  hash = hash ^ (hash >> 4);
256  hash = hash * 2057;  // hash = (hash + (hash << 3)) + (hash << 11);
257  hash = hash ^ (hash >> 16);
258  return hash;
259}
260
261
262inline uint32_t ComputeLongHash(uint64_t key) {
263  uint64_t hash = key;
264  hash = ~hash + (hash << 18);  // hash = (hash << 18) - hash - 1;
265  hash = hash ^ (hash >> 31);
266  hash = hash * 21;  // hash = (hash + (hash << 2)) + (hash << 4);
267  hash = hash ^ (hash >> 11);
268  hash = hash + (hash << 6);
269  hash = hash ^ (hash >> 22);
270  return static_cast<uint32_t>(hash);
271}
272
273
274inline uint32_t ComputePointerHash(void* ptr) {
275  return ComputeIntegerHash(
276      static_cast<uint32_t>(reinterpret_cast<intptr_t>(ptr)),
277      v8::internal::kZeroHashSeed);
278}
279
280
281// ----------------------------------------------------------------------------
282// Generated memcpy/memmove
283
284// Initializes the codegen support that depends on CPU features. This is
285// called after CPU initialization.
286void init_memcopy_functions();
287
288#if defined(V8_TARGET_ARCH_IA32) || defined(V8_TARGET_ARCH_X87)
289// Limit below which the extra overhead of the MemCopy function is likely
290// to outweigh the benefits of faster copying.
291const int kMinComplexMemCopy = 64;
292
293// Copy memory area. No restrictions.
294void MemMove(void* dest, const void* src, size_t size);
295typedef void (*MemMoveFunction)(void* dest, const void* src, size_t size);
296
297// Keep the distinction of "move" vs. "copy" for the benefit of other
298// architectures.
299V8_INLINE void MemCopy(void* dest, const void* src, size_t size) {
300  MemMove(dest, src, size);
301}
302#elif defined(V8_HOST_ARCH_ARM)
303typedef void (*MemCopyUint8Function)(uint8_t* dest, const uint8_t* src,
304                                     size_t size);
305extern MemCopyUint8Function memcopy_uint8_function;
306V8_INLINE void MemCopyUint8Wrapper(uint8_t* dest, const uint8_t* src,
307                                   size_t chars) {
308  memcpy(dest, src, chars);
309}
310// For values < 16, the assembler function is slower than the inlined C code.
311const int kMinComplexMemCopy = 16;
312V8_INLINE void MemCopy(void* dest, const void* src, size_t size) {
313  (*memcopy_uint8_function)(reinterpret_cast<uint8_t*>(dest),
314                            reinterpret_cast<const uint8_t*>(src), size);
315}
316V8_INLINE void MemMove(void* dest, const void* src, size_t size) {
317  memmove(dest, src, size);
318}
319
320typedef void (*MemCopyUint16Uint8Function)(uint16_t* dest, const uint8_t* src,
321                                           size_t size);
322extern MemCopyUint16Uint8Function memcopy_uint16_uint8_function;
323void MemCopyUint16Uint8Wrapper(uint16_t* dest, const uint8_t* src,
324                               size_t chars);
325// For values < 12, the assembler function is slower than the inlined C code.
326const int kMinComplexConvertMemCopy = 12;
327V8_INLINE void MemCopyUint16Uint8(uint16_t* dest, const uint8_t* src,
328                                  size_t size) {
329  (*memcopy_uint16_uint8_function)(dest, src, size);
330}
331#elif defined(V8_HOST_ARCH_MIPS)
332typedef void (*MemCopyUint8Function)(uint8_t* dest, const uint8_t* src,
333                                     size_t size);
334extern MemCopyUint8Function memcopy_uint8_function;
335V8_INLINE void MemCopyUint8Wrapper(uint8_t* dest, const uint8_t* src,
336                                   size_t chars) {
337  memcpy(dest, src, chars);
338}
339// For values < 16, the assembler function is slower than the inlined C code.
340const int kMinComplexMemCopy = 16;
341V8_INLINE void MemCopy(void* dest, const void* src, size_t size) {
342  (*memcopy_uint8_function)(reinterpret_cast<uint8_t*>(dest),
343                            reinterpret_cast<const uint8_t*>(src), size);
344}
345V8_INLINE void MemMove(void* dest, const void* src, size_t size) {
346  memmove(dest, src, size);
347}
348#else
349// Copy memory area to disjoint memory area.
350V8_INLINE void MemCopy(void* dest, const void* src, size_t size) {
351  memcpy(dest, src, size);
352}
353V8_INLINE void MemMove(void* dest, const void* src, size_t size) {
354  memmove(dest, src, size);
355}
356const int kMinComplexMemCopy = 16 * kPointerSize;
357#endif  // V8_TARGET_ARCH_IA32
358
359
360// ----------------------------------------------------------------------------
361// Miscellaneous
362
363// A static resource holds a static instance that can be reserved in
364// a local scope using an instance of Access.  Attempts to re-reserve
365// the instance will cause an error.
366template <typename T>
367class StaticResource {
368 public:
369  StaticResource() : is_reserved_(false)  {}
370
371 private:
372  template <typename S> friend class Access;
373  T instance_;
374  bool is_reserved_;
375};
376
377
378// Locally scoped access to a static resource.
379template <typename T>
380class Access {
381 public:
382  explicit Access(StaticResource<T>* resource)
383    : resource_(resource)
384    , instance_(&resource->instance_) {
385    DCHECK(!resource->is_reserved_);
386    resource->is_reserved_ = true;
387  }
388
389  ~Access() {
390    resource_->is_reserved_ = false;
391    resource_ = NULL;
392    instance_ = NULL;
393  }
394
395  T* value()  { return instance_; }
396  T* operator -> ()  { return instance_; }
397
398 private:
399  StaticResource<T>* resource_;
400  T* instance_;
401};
402
403
404// A pointer that can only be set once and doesn't allow NULL values.
405template<typename T>
406class SetOncePointer {
407 public:
408  SetOncePointer() : pointer_(NULL) { }
409
410  bool is_set() const { return pointer_ != NULL; }
411
412  T* get() const {
413    DCHECK(pointer_ != NULL);
414    return pointer_;
415  }
416
417  void set(T* value) {
418    DCHECK(pointer_ == NULL && value != NULL);
419    pointer_ = value;
420  }
421
422 private:
423  T* pointer_;
424};
425
426
427template <typename T, int kSize>
428class EmbeddedVector : public Vector<T> {
429 public:
430  EmbeddedVector() : Vector<T>(buffer_, kSize) { }
431
432  explicit EmbeddedVector(T initial_value) : Vector<T>(buffer_, kSize) {
433    for (int i = 0; i < kSize; ++i) {
434      buffer_[i] = initial_value;
435    }
436  }
437
438  // When copying, make underlying Vector to reference our buffer.
439  EmbeddedVector(const EmbeddedVector& rhs)
440      : Vector<T>(rhs) {
441    MemCopy(buffer_, rhs.buffer_, sizeof(T) * kSize);
442    this->set_start(buffer_);
443  }
444
445  EmbeddedVector& operator=(const EmbeddedVector& rhs) {
446    if (this == &rhs) return *this;
447    Vector<T>::operator=(rhs);
448    MemCopy(buffer_, rhs.buffer_, sizeof(T) * kSize);
449    this->set_start(buffer_);
450    return *this;
451  }
452
453 private:
454  T buffer_[kSize];
455};
456
457
458/*
459 * A class that collects values into a backing store.
460 * Specialized versions of the class can allow access to the backing store
461 * in different ways.
462 * There is no guarantee that the backing store is contiguous (and, as a
463 * consequence, no guarantees that consecutively added elements are adjacent
464 * in memory). The collector may move elements unless it has guaranteed not
465 * to.
466 */
467template <typename T, int growth_factor = 2, int max_growth = 1 * MB>
468class Collector {
469 public:
470  explicit Collector(int initial_capacity = kMinCapacity)
471      : index_(0), size_(0) {
472    current_chunk_ = Vector<T>::New(initial_capacity);
473  }
474
475  virtual ~Collector() {
476    // Free backing store (in reverse allocation order).
477    current_chunk_.Dispose();
478    for (int i = chunks_.length() - 1; i >= 0; i--) {
479      chunks_.at(i).Dispose();
480    }
481  }
482
483  // Add a single element.
484  inline void Add(T value) {
485    if (index_ >= current_chunk_.length()) {
486      Grow(1);
487    }
488    current_chunk_[index_] = value;
489    index_++;
490    size_++;
491  }
492
493  // Add a block of contiguous elements and return a Vector backed by the
494  // memory area.
495  // A basic Collector will keep this vector valid as long as the Collector
496  // is alive.
497  inline Vector<T> AddBlock(int size, T initial_value) {
498    DCHECK(size > 0);
499    if (size > current_chunk_.length() - index_) {
500      Grow(size);
501    }
502    T* position = current_chunk_.start() + index_;
503    index_ += size;
504    size_ += size;
505    for (int i = 0; i < size; i++) {
506      position[i] = initial_value;
507    }
508    return Vector<T>(position, size);
509  }
510
511
512  // Add a contiguous block of elements and return a vector backed
513  // by the added block.
514  // A basic Collector will keep this vector valid as long as the Collector
515  // is alive.
516  inline Vector<T> AddBlock(Vector<const T> source) {
517    if (source.length() > current_chunk_.length() - index_) {
518      Grow(source.length());
519    }
520    T* position = current_chunk_.start() + index_;
521    index_ += source.length();
522    size_ += source.length();
523    for (int i = 0; i < source.length(); i++) {
524      position[i] = source[i];
525    }
526    return Vector<T>(position, source.length());
527  }
528
529
530  // Write the contents of the collector into the provided vector.
531  void WriteTo(Vector<T> destination) {
532    DCHECK(size_ <= destination.length());
533    int position = 0;
534    for (int i = 0; i < chunks_.length(); i++) {
535      Vector<T> chunk = chunks_.at(i);
536      for (int j = 0; j < chunk.length(); j++) {
537        destination[position] = chunk[j];
538        position++;
539      }
540    }
541    for (int i = 0; i < index_; i++) {
542      destination[position] = current_chunk_[i];
543      position++;
544    }
545  }
546
547  // Allocate a single contiguous vector, copy all the collected
548  // elements to the vector, and return it.
549  // The caller is responsible for freeing the memory of the returned
550  // vector (e.g., using Vector::Dispose).
551  Vector<T> ToVector() {
552    Vector<T> new_store = Vector<T>::New(size_);
553    WriteTo(new_store);
554    return new_store;
555  }
556
557  // Resets the collector to be empty.
558  virtual void Reset();
559
560  // Total number of elements added to collector so far.
561  inline int size() { return size_; }
562
563 protected:
564  static const int kMinCapacity = 16;
565  List<Vector<T> > chunks_;
566  Vector<T> current_chunk_;  // Block of memory currently being written into.
567  int index_;  // Current index in current chunk.
568  int size_;  // Total number of elements in collector.
569
570  // Creates a new current chunk, and stores the old chunk in the chunks_ list.
571  void Grow(int min_capacity) {
572    DCHECK(growth_factor > 1);
573    int new_capacity;
574    int current_length = current_chunk_.length();
575    if (current_length < kMinCapacity) {
576      // The collector started out as empty.
577      new_capacity = min_capacity * growth_factor;
578      if (new_capacity < kMinCapacity) new_capacity = kMinCapacity;
579    } else {
580      int growth = current_length * (growth_factor - 1);
581      if (growth > max_growth) {
582        growth = max_growth;
583      }
584      new_capacity = current_length + growth;
585      if (new_capacity < min_capacity) {
586        new_capacity = min_capacity + growth;
587      }
588    }
589    NewChunk(new_capacity);
590    DCHECK(index_ + min_capacity <= current_chunk_.length());
591  }
592
593  // Before replacing the current chunk, give a subclass the option to move
594  // some of the current data into the new chunk. The function may update
595  // the current index_ value to represent data no longer in the current chunk.
596  // Returns the initial index of the new chunk (after copied data).
597  virtual void NewChunk(int new_capacity)  {
598    Vector<T> new_chunk = Vector<T>::New(new_capacity);
599    if (index_ > 0) {
600      chunks_.Add(current_chunk_.SubVector(0, index_));
601    } else {
602      current_chunk_.Dispose();
603    }
604    current_chunk_ = new_chunk;
605    index_ = 0;
606  }
607};
608
609
610/*
611 * A collector that allows sequences of values to be guaranteed to
612 * stay consecutive.
613 * If the backing store grows while a sequence is active, the current
614 * sequence might be moved, but after the sequence is ended, it will
615 * not move again.
616 * NOTICE: Blocks allocated using Collector::AddBlock(int) can move
617 * as well, if inside an active sequence where another element is added.
618 */
619template <typename T, int growth_factor = 2, int max_growth = 1 * MB>
620class SequenceCollector : public Collector<T, growth_factor, max_growth> {
621 public:
622  explicit SequenceCollector(int initial_capacity)
623      : Collector<T, growth_factor, max_growth>(initial_capacity),
624        sequence_start_(kNoSequence) { }
625
626  virtual ~SequenceCollector() {}
627
628  void StartSequence() {
629    DCHECK(sequence_start_ == kNoSequence);
630    sequence_start_ = this->index_;
631  }
632
633  Vector<T> EndSequence() {
634    DCHECK(sequence_start_ != kNoSequence);
635    int sequence_start = sequence_start_;
636    sequence_start_ = kNoSequence;
637    if (sequence_start == this->index_) return Vector<T>();
638    return this->current_chunk_.SubVector(sequence_start, this->index_);
639  }
640
641  // Drops the currently added sequence, and all collected elements in it.
642  void DropSequence() {
643    DCHECK(sequence_start_ != kNoSequence);
644    int sequence_length = this->index_ - sequence_start_;
645    this->index_ = sequence_start_;
646    this->size_ -= sequence_length;
647    sequence_start_ = kNoSequence;
648  }
649
650  virtual void Reset() {
651    sequence_start_ = kNoSequence;
652    this->Collector<T, growth_factor, max_growth>::Reset();
653  }
654
655 private:
656  static const int kNoSequence = -1;
657  int sequence_start_;
658
659  // Move the currently active sequence to the new chunk.
660  virtual void NewChunk(int new_capacity) {
661    if (sequence_start_ == kNoSequence) {
662      // Fall back on default behavior if no sequence has been started.
663      this->Collector<T, growth_factor, max_growth>::NewChunk(new_capacity);
664      return;
665    }
666    int sequence_length = this->index_ - sequence_start_;
667    Vector<T> new_chunk = Vector<T>::New(sequence_length + new_capacity);
668    DCHECK(sequence_length < new_chunk.length());
669    for (int i = 0; i < sequence_length; i++) {
670      new_chunk[i] = this->current_chunk_[sequence_start_ + i];
671    }
672    if (sequence_start_ > 0) {
673      this->chunks_.Add(this->current_chunk_.SubVector(0, sequence_start_));
674    } else {
675      this->current_chunk_.Dispose();
676    }
677    this->current_chunk_ = new_chunk;
678    this->index_ = sequence_length;
679    sequence_start_ = 0;
680  }
681};
682
683
684// Compare 8bit/16bit chars to 8bit/16bit chars.
685template <typename lchar, typename rchar>
686inline int CompareCharsUnsigned(const lchar* lhs,
687                                const rchar* rhs,
688                                int chars) {
689  const lchar* limit = lhs + chars;
690  if (sizeof(*lhs) == sizeof(char) && sizeof(*rhs) == sizeof(char)) {
691    // memcmp compares byte-by-byte, yielding wrong results for two-byte
692    // strings on little-endian systems.
693    return memcmp(lhs, rhs, chars);
694  }
695  while (lhs < limit) {
696    int r = static_cast<int>(*lhs) - static_cast<int>(*rhs);
697    if (r != 0) return r;
698    ++lhs;
699    ++rhs;
700  }
701  return 0;
702}
703
704template<typename lchar, typename rchar>
705inline int CompareChars(const lchar* lhs, const rchar* rhs, int chars) {
706  DCHECK(sizeof(lchar) <= 2);
707  DCHECK(sizeof(rchar) <= 2);
708  if (sizeof(lchar) == 1) {
709    if (sizeof(rchar) == 1) {
710      return CompareCharsUnsigned(reinterpret_cast<const uint8_t*>(lhs),
711                                  reinterpret_cast<const uint8_t*>(rhs),
712                                  chars);
713    } else {
714      return CompareCharsUnsigned(reinterpret_cast<const uint8_t*>(lhs),
715                                  reinterpret_cast<const uint16_t*>(rhs),
716                                  chars);
717    }
718  } else {
719    if (sizeof(rchar) == 1) {
720      return CompareCharsUnsigned(reinterpret_cast<const uint16_t*>(lhs),
721                                  reinterpret_cast<const uint8_t*>(rhs),
722                                  chars);
723    } else {
724      return CompareCharsUnsigned(reinterpret_cast<const uint16_t*>(lhs),
725                                  reinterpret_cast<const uint16_t*>(rhs),
726                                  chars);
727    }
728  }
729}
730
731
732// Calculate 10^exponent.
733inline int TenToThe(int exponent) {
734  DCHECK(exponent <= 9);
735  DCHECK(exponent >= 1);
736  int answer = 10;
737  for (int i = 1; i < exponent; i++) answer *= 10;
738  return answer;
739}
740
741
742template<typename ElementType, int NumElements>
743class EmbeddedContainer {
744 public:
745  EmbeddedContainer() : elems_() { }
746
747  int length() const { return NumElements; }
748  const ElementType& operator[](int i) const {
749    DCHECK(i < length());
750    return elems_[i];
751  }
752  ElementType& operator[](int i) {
753    DCHECK(i < length());
754    return elems_[i];
755  }
756
757 private:
758  ElementType elems_[NumElements];
759};
760
761
762template<typename ElementType>
763class EmbeddedContainer<ElementType, 0> {
764 public:
765  int length() const { return 0; }
766  const ElementType& operator[](int i) const {
767    UNREACHABLE();
768    static ElementType t = 0;
769    return t;
770  }
771  ElementType& operator[](int i) {
772    UNREACHABLE();
773    static ElementType t = 0;
774    return t;
775  }
776};
777
778
779// Helper class for building result strings in a character buffer. The
780// purpose of the class is to use safe operations that checks the
781// buffer bounds on all operations in debug mode.
782// This simple base class does not allow formatted output.
783class SimpleStringBuilder {
784 public:
785  // Create a string builder with a buffer of the given size. The
786  // buffer is allocated through NewArray<char> and must be
787  // deallocated by the caller of Finalize().
788  explicit SimpleStringBuilder(int size);
789
790  SimpleStringBuilder(char* buffer, int size)
791      : buffer_(buffer, size), position_(0) { }
792
793  ~SimpleStringBuilder() { if (!is_finalized()) Finalize(); }
794
795  int size() const { return buffer_.length(); }
796
797  // Get the current position in the builder.
798  int position() const {
799    DCHECK(!is_finalized());
800    return position_;
801  }
802
803  // Reset the position.
804  void Reset() { position_ = 0; }
805
806  // Add a single character to the builder. It is not allowed to add
807  // 0-characters; use the Finalize() method to terminate the string
808  // instead.
809  void AddCharacter(char c) {
810    DCHECK(c != '\0');
811    DCHECK(!is_finalized() && position_ < buffer_.length());
812    buffer_[position_++] = c;
813  }
814
815  // Add an entire string to the builder. Uses strlen() internally to
816  // compute the length of the input string.
817  void AddString(const char* s);
818
819  // Add the first 'n' characters of the given string 's' to the
820  // builder. The input string must have enough characters.
821  void AddSubstring(const char* s, int n);
822
823  // Add character padding to the builder. If count is non-positive,
824  // nothing is added to the builder.
825  void AddPadding(char c, int count);
826
827  // Add the decimal representation of the value.
828  void AddDecimalInteger(int value);
829
830  // Finalize the string by 0-terminating it and returning the buffer.
831  char* Finalize();
832
833 protected:
834  Vector<char> buffer_;
835  int position_;
836
837  bool is_finalized() const { return position_ < 0; }
838
839 private:
840  DISALLOW_IMPLICIT_CONSTRUCTORS(SimpleStringBuilder);
841};
842
843
844// A poor man's version of STL's bitset: A bit set of enums E (without explicit
845// values), fitting into an integral type T.
846template <class E, class T = int>
847class EnumSet {
848 public:
849  explicit EnumSet(T bits = 0) : bits_(bits) {}
850  bool IsEmpty() const { return bits_ == 0; }
851  bool Contains(E element) const { return (bits_ & Mask(element)) != 0; }
852  bool ContainsAnyOf(const EnumSet& set) const {
853    return (bits_ & set.bits_) != 0;
854  }
855  void Add(E element) { bits_ |= Mask(element); }
856  void Add(const EnumSet& set) { bits_ |= set.bits_; }
857  void Remove(E element) { bits_ &= ~Mask(element); }
858  void Remove(const EnumSet& set) { bits_ &= ~set.bits_; }
859  void RemoveAll() { bits_ = 0; }
860  void Intersect(const EnumSet& set) { bits_ &= set.bits_; }
861  T ToIntegral() const { return bits_; }
862  bool operator==(const EnumSet& set) { return bits_ == set.bits_; }
863  bool operator!=(const EnumSet& set) { return bits_ != set.bits_; }
864  EnumSet<E, T> operator|(const EnumSet& set) const {
865    return EnumSet<E, T>(bits_ | set.bits_);
866  }
867
868 private:
869  T Mask(E element) const {
870    // The strange typing in DCHECK is necessary to avoid stupid warnings, see:
871    // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43680
872    DCHECK(static_cast<int>(element) < static_cast<int>(sizeof(T) * CHAR_BIT));
873    return static_cast<T>(1) << element;
874  }
875
876  T bits_;
877};
878
879// Bit field extraction.
880inline uint32_t unsigned_bitextract_32(int msb, int lsb, uint32_t x) {
881  return (x >> lsb) & ((1 << (1 + msb - lsb)) - 1);
882}
883
884inline uint64_t unsigned_bitextract_64(int msb, int lsb, uint64_t x) {
885  return (x >> lsb) & ((static_cast<uint64_t>(1) << (1 + msb - lsb)) - 1);
886}
887
888inline int32_t signed_bitextract_32(int msb, int lsb, int32_t x) {
889  return (x << (31 - msb)) >> (lsb + 31 - msb);
890}
891
892inline int signed_bitextract_64(int msb, int lsb, int x) {
893  // TODO(jbramley): This is broken for big bitfields.
894  return (x << (63 - msb)) >> (lsb + 63 - msb);
895}
896
897// Check number width.
898inline bool is_intn(int64_t x, unsigned n) {
899  DCHECK((0 < n) && (n < 64));
900  int64_t limit = static_cast<int64_t>(1) << (n - 1);
901  return (-limit <= x) && (x < limit);
902}
903
904inline bool is_uintn(int64_t x, unsigned n) {
905  DCHECK((0 < n) && (n < (sizeof(x) * kBitsPerByte)));
906  return !(x >> n);
907}
908
909template <class T>
910inline T truncate_to_intn(T x, unsigned n) {
911  DCHECK((0 < n) && (n < (sizeof(x) * kBitsPerByte)));
912  return (x & ((static_cast<T>(1) << n) - 1));
913}
914
915#define INT_1_TO_63_LIST(V)                                                    \
916V(1)  V(2)  V(3)  V(4)  V(5)  V(6)  V(7)  V(8)                                 \
917V(9)  V(10) V(11) V(12) V(13) V(14) V(15) V(16)                                \
918V(17) V(18) V(19) V(20) V(21) V(22) V(23) V(24)                                \
919V(25) V(26) V(27) V(28) V(29) V(30) V(31) V(32)                                \
920V(33) V(34) V(35) V(36) V(37) V(38) V(39) V(40)                                \
921V(41) V(42) V(43) V(44) V(45) V(46) V(47) V(48)                                \
922V(49) V(50) V(51) V(52) V(53) V(54) V(55) V(56)                                \
923V(57) V(58) V(59) V(60) V(61) V(62) V(63)
924
925#define DECLARE_IS_INT_N(N)                                                    \
926inline bool is_int##N(int64_t x) { return is_intn(x, N); }
927#define DECLARE_IS_UINT_N(N)                                                   \
928template <class T>                                                             \
929inline bool is_uint##N(T x) { return is_uintn(x, N); }
930#define DECLARE_TRUNCATE_TO_INT_N(N)                                           \
931template <class T>                                                             \
932inline T truncate_to_int##N(T x) { return truncate_to_intn(x, N); }
933INT_1_TO_63_LIST(DECLARE_IS_INT_N)
934INT_1_TO_63_LIST(DECLARE_IS_UINT_N)
935INT_1_TO_63_LIST(DECLARE_TRUNCATE_TO_INT_N)
936#undef DECLARE_IS_INT_N
937#undef DECLARE_IS_UINT_N
938#undef DECLARE_TRUNCATE_TO_INT_N
939
940class TypeFeedbackId {
941 public:
942  explicit TypeFeedbackId(int id) : id_(id) { }
943  int ToInt() const { return id_; }
944
945  static TypeFeedbackId None() { return TypeFeedbackId(kNoneId); }
946  bool IsNone() const { return id_ == kNoneId; }
947
948 private:
949  static const int kNoneId = -1;
950
951  int id_;
952};
953
954
955class BailoutId {
956 public:
957  explicit BailoutId(int id) : id_(id) { }
958  int ToInt() const { return id_; }
959
960  static BailoutId None() { return BailoutId(kNoneId); }
961  static BailoutId FunctionEntry() { return BailoutId(kFunctionEntryId); }
962  static BailoutId Declarations() { return BailoutId(kDeclarationsId); }
963  static BailoutId FirstUsable() { return BailoutId(kFirstUsableId); }
964  static BailoutId StubEntry() { return BailoutId(kStubEntryId); }
965
966  bool IsNone() const { return id_ == kNoneId; }
967  bool operator==(const BailoutId& other) const { return id_ == other.id_; }
968  bool operator!=(const BailoutId& other) const { return id_ != other.id_; }
969
970 private:
971  static const int kNoneId = -1;
972
973  // Using 0 could disguise errors.
974  static const int kFunctionEntryId = 2;
975
976  // This AST id identifies the point after the declarations have been visited.
977  // We need it to capture the environment effects of declarations that emit
978  // code (function declarations).
979  static const int kDeclarationsId = 3;
980
981  // Every FunctionState starts with this id.
982  static const int kFirstUsableId = 4;
983
984  // Every compiled stub starts with this id.
985  static const int kStubEntryId = 5;
986
987  int id_;
988};
989
990
991template <class C>
992class ContainerPointerWrapper {
993 public:
994  typedef typename C::iterator iterator;
995  typedef typename C::reverse_iterator reverse_iterator;
996  explicit ContainerPointerWrapper(C* container) : container_(container) {}
997  iterator begin() { return container_->begin(); }
998  iterator end() { return container_->end(); }
999  reverse_iterator rbegin() { return container_->rbegin(); }
1000  reverse_iterator rend() { return container_->rend(); }
1001 private:
1002  C* container_;
1003};
1004
1005
1006// ----------------------------------------------------------------------------
1007// I/O support.
1008
1009#if __GNUC__ >= 4
1010// On gcc we can ask the compiler to check the types of %d-style format
1011// specifiers and their associated arguments.  TODO(erikcorry) fix this
1012// so it works on MacOSX.
1013#if defined(__MACH__) && defined(__APPLE__)
1014#define PRINTF_CHECKING
1015#define FPRINTF_CHECKING
1016#define PRINTF_METHOD_CHECKING
1017#define FPRINTF_METHOD_CHECKING
1018#else  // MacOsX.
1019#define PRINTF_CHECKING __attribute__ ((format (printf, 1, 2)))
1020#define FPRINTF_CHECKING __attribute__ ((format (printf, 2, 3)))
1021#define PRINTF_METHOD_CHECKING __attribute__ ((format (printf, 2, 3)))
1022#define FPRINTF_METHOD_CHECKING __attribute__ ((format (printf, 3, 4)))
1023#endif
1024#else
1025#define PRINTF_CHECKING
1026#define FPRINTF_CHECKING
1027#define PRINTF_METHOD_CHECKING
1028#define FPRINTF_METHOD_CHECKING
1029#endif
1030
1031// Our version of printf().
1032void PRINTF_CHECKING PrintF(const char* format, ...);
1033void FPRINTF_CHECKING PrintF(FILE* out, const char* format, ...);
1034
1035// Prepends the current process ID to the output.
1036void PRINTF_CHECKING PrintPID(const char* format, ...);
1037
1038// Safe formatting print. Ensures that str is always null-terminated.
1039// Returns the number of chars written, or -1 if output was truncated.
1040int FPRINTF_CHECKING SNPrintF(Vector<char> str, const char* format, ...);
1041int VSNPrintF(Vector<char> str, const char* format, va_list args);
1042
1043void StrNCpy(Vector<char> dest, const char* src, size_t n);
1044
1045// Our version of fflush.
1046void Flush(FILE* out);
1047
1048inline void Flush() {
1049  Flush(stdout);
1050}
1051
1052
1053// Read a line of characters after printing the prompt to stdout. The resulting
1054// char* needs to be disposed off with DeleteArray by the caller.
1055char* ReadLine(const char* prompt);
1056
1057
1058// Read and return the raw bytes in a file. the size of the buffer is returned
1059// in size.
1060// The returned buffer must be freed by the caller.
1061byte* ReadBytes(const char* filename, int* size, bool verbose = true);
1062
1063
1064// Append size chars from str to the file given by filename.
1065// The file is overwritten. Returns the number of chars written.
1066int AppendChars(const char* filename,
1067                const char* str,
1068                int size,
1069                bool verbose = true);
1070
1071
1072// Write size chars from str to the file given by filename.
1073// The file is overwritten. Returns the number of chars written.
1074int WriteChars(const char* filename,
1075               const char* str,
1076               int size,
1077               bool verbose = true);
1078
1079
1080// Write size bytes to the file given by filename.
1081// The file is overwritten. Returns the number of bytes written.
1082int WriteBytes(const char* filename,
1083               const byte* bytes,
1084               int size,
1085               bool verbose = true);
1086
1087
1088// Write the C code
1089// const char* <varname> = "<str>";
1090// const int <varname>_len = <len>;
1091// to the file given by filename. Only the first len chars are written.
1092int WriteAsCFile(const char* filename, const char* varname,
1093                 const char* str, int size, bool verbose = true);
1094
1095
1096// ----------------------------------------------------------------------------
1097// Data structures
1098
1099template <typename T>
1100inline Vector< Handle<Object> > HandleVector(v8::internal::Handle<T>* elms,
1101                                             int length) {
1102  return Vector< Handle<Object> >(
1103      reinterpret_cast<v8::internal::Handle<Object>*>(elms), length);
1104}
1105
1106
1107// ----------------------------------------------------------------------------
1108// Memory
1109
1110// Copies words from |src| to |dst|. The data spans must not overlap.
1111template <typename T>
1112inline void CopyWords(T* dst, const T* src, size_t num_words) {
1113  STATIC_ASSERT(sizeof(T) == kPointerSize);
1114  // TODO(mvstanton): disabled because mac builds are bogus failing on this
1115  // assert. They are doing a signed comparison. Investigate in
1116  // the morning.
1117  // DCHECK(Min(dst, const_cast<T*>(src)) + num_words <=
1118  //       Max(dst, const_cast<T*>(src)));
1119  DCHECK(num_words > 0);
1120
1121  // Use block copying MemCopy if the segment we're copying is
1122  // enough to justify the extra call/setup overhead.
1123  static const size_t kBlockCopyLimit = 16;
1124
1125  if (num_words < kBlockCopyLimit) {
1126    do {
1127      num_words--;
1128      *dst++ = *src++;
1129    } while (num_words > 0);
1130  } else {
1131    MemCopy(dst, src, num_words * kPointerSize);
1132  }
1133}
1134
1135
1136// Copies words from |src| to |dst|. No restrictions.
1137template <typename T>
1138inline void MoveWords(T* dst, const T* src, size_t num_words) {
1139  STATIC_ASSERT(sizeof(T) == kPointerSize);
1140  DCHECK(num_words > 0);
1141
1142  // Use block copying MemCopy if the segment we're copying is
1143  // enough to justify the extra call/setup overhead.
1144  static const size_t kBlockCopyLimit = 16;
1145
1146  if (num_words < kBlockCopyLimit &&
1147      ((dst < src) || (dst >= (src + num_words * kPointerSize)))) {
1148    T* end = dst + num_words;
1149    do {
1150      num_words--;
1151      *dst++ = *src++;
1152    } while (num_words > 0);
1153  } else {
1154    MemMove(dst, src, num_words * kPointerSize);
1155  }
1156}
1157
1158
1159// Copies data from |src| to |dst|.  The data spans must not overlap.
1160template <typename T>
1161inline void CopyBytes(T* dst, const T* src, size_t num_bytes) {
1162  STATIC_ASSERT(sizeof(T) == 1);
1163  DCHECK(Min(dst, const_cast<T*>(src)) + num_bytes <=
1164         Max(dst, const_cast<T*>(src)));
1165  if (num_bytes == 0) return;
1166
1167  // Use block copying MemCopy if the segment we're copying is
1168  // enough to justify the extra call/setup overhead.
1169  static const int kBlockCopyLimit = kMinComplexMemCopy;
1170
1171  if (num_bytes < static_cast<size_t>(kBlockCopyLimit)) {
1172    do {
1173      num_bytes--;
1174      *dst++ = *src++;
1175    } while (num_bytes > 0);
1176  } else {
1177    MemCopy(dst, src, num_bytes);
1178  }
1179}
1180
1181
1182template <typename T, typename U>
1183inline void MemsetPointer(T** dest, U* value, int counter) {
1184#ifdef DEBUG
1185  T* a = NULL;
1186  U* b = NULL;
1187  a = b;  // Fake assignment to check assignability.
1188  USE(a);
1189#endif  // DEBUG
1190#if V8_HOST_ARCH_IA32
1191#define STOS "stosl"
1192#elif V8_HOST_ARCH_X64
1193#if V8_HOST_ARCH_32_BIT
1194#define STOS "addr32 stosl"
1195#else
1196#define STOS "stosq"
1197#endif
1198#endif
1199#if defined(__native_client__)
1200  // This STOS sequence does not validate for x86_64 Native Client.
1201  // Here we #undef STOS to force use of the slower C version.
1202  // TODO(bradchen): Profile V8 and implement a faster REP STOS
1203  // here if the profile indicates it matters.
1204#undef STOS
1205#endif
1206
1207#if defined(MEMORY_SANITIZER)
1208  // MemorySanitizer does not understand inline assembly.
1209#undef STOS
1210#endif
1211
1212#if defined(__GNUC__) && defined(STOS)
1213  asm volatile(
1214      "cld;"
1215      "rep ; " STOS
1216      : "+&c" (counter), "+&D" (dest)
1217      : "a" (value)
1218      : "memory", "cc");
1219#else
1220  for (int i = 0; i < counter; i++) {
1221    dest[i] = value;
1222  }
1223#endif
1224
1225#undef STOS
1226}
1227
1228
1229// Simple support to read a file into a 0-terminated C-string.
1230// The returned buffer must be freed by the caller.
1231// On return, *exits tells whether the file existed.
1232Vector<const char> ReadFile(const char* filename,
1233                            bool* exists,
1234                            bool verbose = true);
1235Vector<const char> ReadFile(FILE* file,
1236                            bool* exists,
1237                            bool verbose = true);
1238
1239
1240template <typename sourcechar, typename sinkchar>
1241INLINE(static void CopyCharsUnsigned(sinkchar* dest,
1242                                     const sourcechar* src,
1243                                     int chars));
1244#if defined(V8_HOST_ARCH_ARM)
1245INLINE(void CopyCharsUnsigned(uint8_t* dest, const uint8_t* src, int chars));
1246INLINE(void CopyCharsUnsigned(uint16_t* dest, const uint8_t* src, int chars));
1247INLINE(void CopyCharsUnsigned(uint16_t* dest, const uint16_t* src, int chars));
1248#elif defined(V8_HOST_ARCH_MIPS)
1249INLINE(void CopyCharsUnsigned(uint8_t* dest, const uint8_t* src, int chars));
1250INLINE(void CopyCharsUnsigned(uint16_t* dest, const uint16_t* src, int chars));
1251#endif
1252
1253// Copy from 8bit/16bit chars to 8bit/16bit chars.
1254template <typename sourcechar, typename sinkchar>
1255INLINE(void CopyChars(sinkchar* dest, const sourcechar* src, int chars));
1256
1257template<typename sourcechar, typename sinkchar>
1258void CopyChars(sinkchar* dest, const sourcechar* src, int chars) {
1259  DCHECK(sizeof(sourcechar) <= 2);
1260  DCHECK(sizeof(sinkchar) <= 2);
1261  if (sizeof(sinkchar) == 1) {
1262    if (sizeof(sourcechar) == 1) {
1263      CopyCharsUnsigned(reinterpret_cast<uint8_t*>(dest),
1264                        reinterpret_cast<const uint8_t*>(src),
1265                        chars);
1266    } else {
1267      CopyCharsUnsigned(reinterpret_cast<uint8_t*>(dest),
1268                        reinterpret_cast<const uint16_t*>(src),
1269                        chars);
1270    }
1271  } else {
1272    if (sizeof(sourcechar) == 1) {
1273      CopyCharsUnsigned(reinterpret_cast<uint16_t*>(dest),
1274                        reinterpret_cast<const uint8_t*>(src),
1275                        chars);
1276    } else {
1277      CopyCharsUnsigned(reinterpret_cast<uint16_t*>(dest),
1278                        reinterpret_cast<const uint16_t*>(src),
1279                        chars);
1280    }
1281  }
1282}
1283
1284template <typename sourcechar, typename sinkchar>
1285void CopyCharsUnsigned(sinkchar* dest, const sourcechar* src, int chars) {
1286  sinkchar* limit = dest + chars;
1287  if ((sizeof(*dest) == sizeof(*src)) &&
1288      (chars >= static_cast<int>(kMinComplexMemCopy / sizeof(*dest)))) {
1289    MemCopy(dest, src, chars * sizeof(*dest));
1290  } else {
1291    while (dest < limit) *dest++ = static_cast<sinkchar>(*src++);
1292  }
1293}
1294
1295
1296#if defined(V8_HOST_ARCH_ARM)
1297void CopyCharsUnsigned(uint8_t* dest, const uint8_t* src, int chars) {
1298  switch (static_cast<unsigned>(chars)) {
1299    case 0:
1300      break;
1301    case 1:
1302      *dest = *src;
1303      break;
1304    case 2:
1305      memcpy(dest, src, 2);
1306      break;
1307    case 3:
1308      memcpy(dest, src, 3);
1309      break;
1310    case 4:
1311      memcpy(dest, src, 4);
1312      break;
1313    case 5:
1314      memcpy(dest, src, 5);
1315      break;
1316    case 6:
1317      memcpy(dest, src, 6);
1318      break;
1319    case 7:
1320      memcpy(dest, src, 7);
1321      break;
1322    case 8:
1323      memcpy(dest, src, 8);
1324      break;
1325    case 9:
1326      memcpy(dest, src, 9);
1327      break;
1328    case 10:
1329      memcpy(dest, src, 10);
1330      break;
1331    case 11:
1332      memcpy(dest, src, 11);
1333      break;
1334    case 12:
1335      memcpy(dest, src, 12);
1336      break;
1337    case 13:
1338      memcpy(dest, src, 13);
1339      break;
1340    case 14:
1341      memcpy(dest, src, 14);
1342      break;
1343    case 15:
1344      memcpy(dest, src, 15);
1345      break;
1346    default:
1347      MemCopy(dest, src, chars);
1348      break;
1349  }
1350}
1351
1352
1353void CopyCharsUnsigned(uint16_t* dest, const uint8_t* src, int chars) {
1354  if (chars >= kMinComplexConvertMemCopy) {
1355    MemCopyUint16Uint8(dest, src, chars);
1356  } else {
1357    MemCopyUint16Uint8Wrapper(dest, src, chars);
1358  }
1359}
1360
1361
1362void CopyCharsUnsigned(uint16_t* dest, const uint16_t* src, int chars) {
1363  switch (static_cast<unsigned>(chars)) {
1364    case 0:
1365      break;
1366    case 1:
1367      *dest = *src;
1368      break;
1369    case 2:
1370      memcpy(dest, src, 4);
1371      break;
1372    case 3:
1373      memcpy(dest, src, 6);
1374      break;
1375    case 4:
1376      memcpy(dest, src, 8);
1377      break;
1378    case 5:
1379      memcpy(dest, src, 10);
1380      break;
1381    case 6:
1382      memcpy(dest, src, 12);
1383      break;
1384    case 7:
1385      memcpy(dest, src, 14);
1386      break;
1387    default:
1388      MemCopy(dest, src, chars * sizeof(*dest));
1389      break;
1390  }
1391}
1392
1393
1394#elif defined(V8_HOST_ARCH_MIPS)
1395void CopyCharsUnsigned(uint8_t* dest, const uint8_t* src, int chars) {
1396  if (chars < kMinComplexMemCopy) {
1397    memcpy(dest, src, chars);
1398  } else {
1399    MemCopy(dest, src, chars);
1400  }
1401}
1402
1403void CopyCharsUnsigned(uint16_t* dest, const uint16_t* src, int chars) {
1404  if (chars < kMinComplexMemCopy) {
1405    memcpy(dest, src, chars * sizeof(*dest));
1406  } else {
1407    MemCopy(dest, src, chars * sizeof(*dest));
1408  }
1409}
1410#endif
1411
1412
1413class StringBuilder : public SimpleStringBuilder {
1414 public:
1415  explicit StringBuilder(int size) : SimpleStringBuilder(size) { }
1416  StringBuilder(char* buffer, int size) : SimpleStringBuilder(buffer, size) { }
1417
1418  // Add formatted contents to the builder just like printf().
1419  void AddFormatted(const char* format, ...);
1420
1421  // Add formatted contents like printf based on a va_list.
1422  void AddFormattedList(const char* format, va_list list);
1423 private:
1424  DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder);
1425};
1426
1427
1428bool DoubleToBoolean(double d);
1429
1430template <typename Stream>
1431bool StringToArrayIndex(Stream* stream, uint32_t* index) {
1432  uint16_t ch = stream->GetNext();
1433
1434  // If the string begins with a '0' character, it must only consist
1435  // of it to be a legal array index.
1436  if (ch == '0') {
1437    *index = 0;
1438    return !stream->HasMore();
1439  }
1440
1441  // Convert string to uint32 array index; character by character.
1442  int d = ch - '0';
1443  if (d < 0 || d > 9) return false;
1444  uint32_t result = d;
1445  while (stream->HasMore()) {
1446    d = stream->GetNext() - '0';
1447    if (d < 0 || d > 9) return false;
1448    // Check that the new result is below the 32 bit limit.
1449    if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
1450    result = (result * 10) + d;
1451  }
1452
1453  *index = result;
1454  return true;
1455}
1456
1457
1458// Returns current value of top of the stack. Works correctly with ASAN.
1459DISABLE_ASAN
1460inline uintptr_t GetCurrentStackPosition() {
1461  // Takes the address of the limit variable in order to find out where
1462  // the top of stack is right now.
1463  uintptr_t limit = reinterpret_cast<uintptr_t>(&limit);
1464  return limit;
1465}
1466
1467}  // namespace internal
1468}  // namespace v8
1469
1470#endif  // V8_UTILS_H_
1471