Upgrade V8 to 2.5.7
authorRyan Dahl <ry@tinyclouds.org>
Fri, 19 Nov 2010 18:49:09 +0000 (10:49 -0800)
committerRyan Dahl <ry@tinyclouds.org>
Fri, 19 Nov 2010 18:49:09 +0000 (10:49 -0800)
147 files changed:
deps/v8/AUTHORS
deps/v8/ChangeLog
deps/v8/include/v8-debug.h
deps/v8/include/v8.h
deps/v8/include/v8stdint.h [new file with mode: 0644]
deps/v8/src/SConscript
deps/v8/src/accessors.cc
deps/v8/src/allocation.cc
deps/v8/src/allocation.h
deps/v8/src/api.cc
deps/v8/src/arm/assembler-arm.cc
deps/v8/src/arm/assembler-arm.h
deps/v8/src/arm/codegen-arm.cc
deps/v8/src/arm/codegen-arm.h
deps/v8/src/arm/constants-arm.h
deps/v8/src/arm/disasm-arm.cc
deps/v8/src/arm/full-codegen-arm.cc
deps/v8/src/arm/ic-arm.cc
deps/v8/src/arm/macro-assembler-arm.cc
deps/v8/src/arm/macro-assembler-arm.h
deps/v8/src/arm/simulator-arm.cc
deps/v8/src/arm/simulator-arm.h
deps/v8/src/arm/stub-cache-arm.cc
deps/v8/src/arm/virtual-frame-arm.cc
deps/v8/src/assembler.cc
deps/v8/src/assembler.h
deps/v8/src/bignum-dtoa.cc [new file with mode: 0644]
deps/v8/src/bignum-dtoa.h [new file with mode: 0644]
deps/v8/src/bignum.cc [new file with mode: 0644]
deps/v8/src/bignum.h [new file with mode: 0644]
deps/v8/src/bootstrapper.cc
deps/v8/src/checks.cc
deps/v8/src/checks.h
deps/v8/src/code-stubs.cc
deps/v8/src/code-stubs.h
deps/v8/src/codegen.cc
deps/v8/src/codegen.h
deps/v8/src/compiler.cc
deps/v8/src/conversions.cc
deps/v8/src/dateparser.h
deps/v8/src/debug-debugger.js
deps/v8/src/debug.cc
deps/v8/src/double.h
deps/v8/src/dtoa.cc
deps/v8/src/dtoa.h
deps/v8/src/execution.cc
deps/v8/src/execution.h
deps/v8/src/extensions/externalize-string-extension.cc [new file with mode: 0644]
deps/v8/src/extensions/externalize-string-extension.h [new file with mode: 0644]
deps/v8/src/extensions/gc-extension.cc [new file with mode: 0644]
deps/v8/src/extensions/gc-extension.h [new file with mode: 0644]
deps/v8/src/flag-definitions.h
deps/v8/src/full-codegen.cc
deps/v8/src/full-codegen.h
deps/v8/src/global-handles.cc
deps/v8/src/global-handles.h
deps/v8/src/globals.h
deps/v8/src/handles.cc
deps/v8/src/heap-inl.h
deps/v8/src/heap-profiler.cc
deps/v8/src/heap.cc
deps/v8/src/heap.h
deps/v8/src/ia32/assembler-ia32.cc
deps/v8/src/ia32/assembler-ia32.h
deps/v8/src/ia32/code-stubs-ia32.cc
deps/v8/src/ia32/codegen-ia32.cc
deps/v8/src/ia32/codegen-ia32.h
deps/v8/src/ia32/full-codegen-ia32.cc
deps/v8/src/ia32/ic-ia32.cc
deps/v8/src/ia32/macro-assembler-ia32.cc
deps/v8/src/ia32/macro-assembler-ia32.h
deps/v8/src/ia32/stub-cache-ia32.cc
deps/v8/src/ia32/virtual-frame-ia32.cc
deps/v8/src/jump-target-heavy.cc
deps/v8/src/jump-target-light.cc
deps/v8/src/list.h
deps/v8/src/mark-compact.cc
deps/v8/src/mark-compact.h
deps/v8/src/objects-debug.cc
deps/v8/src/objects-inl.h
deps/v8/src/objects.cc
deps/v8/src/objects.h
deps/v8/src/parser.cc
deps/v8/src/parser.h
deps/v8/src/platform-linux.cc
deps/v8/src/platform-win32.cc
deps/v8/src/preparser.h [new file with mode: 0644]
deps/v8/src/prescanner.h [new file with mode: 0644]
deps/v8/src/profile-generator.cc
deps/v8/src/profile-generator.h
deps/v8/src/regexp.js
deps/v8/src/runtime.cc
deps/v8/src/runtime.h
deps/v8/src/scanner-base.cc [new file with mode: 0644]
deps/v8/src/scanner-base.h [new file with mode: 0644]
deps/v8/src/scanner.cc
deps/v8/src/scanner.h
deps/v8/src/serialize.cc
deps/v8/src/spaces.cc
deps/v8/src/spaces.h
deps/v8/src/string.js
deps/v8/src/strtod.cc
deps/v8/src/stub-cache.cc
deps/v8/src/stub-cache.h
deps/v8/src/token.h
deps/v8/src/utils.cc
deps/v8/src/utils.h
deps/v8/src/v8.cc
deps/v8/src/v8.h
deps/v8/src/v8globals.h [new file with mode: 0644]
deps/v8/src/v8utils.h [new file with mode: 0644]
deps/v8/src/version.cc
deps/v8/src/virtual-frame.h
deps/v8/src/x64/assembler-x64.cc
deps/v8/src/x64/assembler-x64.h
deps/v8/src/x64/code-stubs-x64.cc
deps/v8/src/x64/codegen-x64.cc
deps/v8/src/x64/codegen-x64.h
deps/v8/src/x64/full-codegen-x64.cc
deps/v8/src/x64/ic-x64.cc
deps/v8/src/x64/macro-assembler-x64.cc
deps/v8/src/x64/macro-assembler-x64.h
deps/v8/src/x64/stub-cache-x64.cc
deps/v8/src/x64/virtual-frame-x64.cc
deps/v8/test/cctest/SConscript
deps/v8/test/cctest/test-api.cc
deps/v8/test/cctest/test-assembler-arm.cc
deps/v8/test/cctest/test-bignum-dtoa.cc [new file with mode: 0644]
deps/v8/test/cctest/test-bignum.cc [new file with mode: 0644]
deps/v8/test/cctest/test-debug.cc
deps/v8/test/cctest/test-disasm-arm.cc
deps/v8/test/cctest/test-double.cc
deps/v8/test/cctest/test-dtoa.cc [new file with mode: 0644]
deps/v8/test/cctest/test-heap-profiler.cc
deps/v8/test/cctest/test-heap.cc
deps/v8/test/cctest/test-mark-compact.cc
deps/v8/test/cctest/test-parsing.cc
deps/v8/test/cctest/test-spaces.cc
deps/v8/test/cctest/test-strtod.cc
deps/v8/test/mjsunit/regress/regress-918.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/regress-927.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/regress-931.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/regress-conditional-position.js [new file with mode: 0644]
deps/v8/test/mjsunit/string-split.js
deps/v8/tools/gyp/v8.gyp
deps/v8/tools/presubmit.py
deps/v8/tools/visual_studio/v8_base.vcproj

index 3749cebcd1763a9de665448b845cecbee18e8902..68f9b63babbfba90e5f51ec0ab1fd542fdeec429 100644 (file)
@@ -9,6 +9,7 @@ ARM Ltd.
 Hewlett-Packard Development Company, LP
 
 Alexander Botero-Lowry <alexbl@FreeBSD.org>
+Alexandre Rames <alexandre.rames@arm.com>
 Alexandre Vassalotti <avassalotti@gmail.com>
 Andreas Anyuru <andreas.anyuru@gmail.com>
 Burcu Dogan <burcujdogan@gmail.com>
index 69aff33d18535a4b82bbf63676ac6a993a8e06ef..c618f202f9b3c395912cfd6cf001f7574af1da9c 100644 (file)
@@ -1,3 +1,50 @@
+2010-11-18: Version 2.5.7
+
+        Fixed obscure evaluation order bug (issue 931).
+
+        Split the random number state between JavaScript and the private API.
+
+        Fixed performance bug causing GCs when generating stack traces on
+        code from very large scripts.
+
+        Fixed bug in parser that allowed (foo):42 as a labelled statement
+        (issue 918).
+
+        Provide more accurate results about used heap size via
+        GetHeapStatistics.
+
+        Allow build-time customization of the max semispace size.
+
+        Made String.prototype.split honor limit when separator is empty
+        (issue 929).
+
+        Added missing failure check after expecting an identifier in
+        preparser (Chromium issue 62639).
+
+
+2010-11-10: Version 2.5.6
+
+        Added support for VFP rounding modes to the ARM simulator.
+
+        Fixed multiplication overflow bug (issue 927).
+
+        Added a limit for the amount of executable memory (issue 925).
+
+
+2010-11-08: Version 2.5.5
+
+        Added more aggressive GC of external objects in near out-of-memory
+        situations.
+
+        Fixed a bug that gave the incorrect result for String.split called
+        on the empty string (issue 924).
+
+
+2010-11-03: Version 2.5.4
+
+        Improved V8 VFPv3 runtime detection to address issue 914.
+
+
 2010-11-01: Version 2.5.3
 
         Fixed a bug that prevents constants from overwriting function values
index 4314727adc42f30f9a2a572c9f048fa1f6fefce6..f17b848550d0f0736ebda3b7dfa3cd506227f4c4 100755 (executable)
@@ -142,7 +142,7 @@ class EXPORT Debug {
 
     virtual ~Message() {}
   };
-  
+
 
   /**
    * An event details object passed to the debug event listener.
@@ -300,7 +300,7 @@ class EXPORT Debug {
   * get access to information otherwise not available during normal JavaScript
   * execution e.g. details on stack frames. Receiver of the function call will
   * be the debugger context global object, however this is a subject to change.
-  * The following example show a JavaScript function which when passed to 
+  * The following example show a JavaScript function which when passed to
   * v8::Debug::Call will return the current line of JavaScript execution.
   *
   * \code
index c7e4552b4d449092effb0b711742f8c69757d522..9baa17db1d5a00191ce884c325978c89de438f93 100644 (file)
 #ifndef V8_H_
 #define V8_H_
 
-#include <stdio.h>
+#include "v8stdint.h"
 
 #ifdef _WIN32
-// When compiling on MinGW stdint.h is available.
-#ifdef __MINGW32__
-#include <stdint.h>
-#else  // __MINGW32__
-typedef signed char int8_t;
-typedef unsigned char uint8_t;
-typedef short int16_t;  // NOLINT
-typedef unsigned short uint16_t;  // NOLINT
-typedef int int32_t;
-typedef unsigned int uint32_t;
-typedef __int64 int64_t;
-typedef unsigned __int64 uint64_t;
-// intptr_t and friends are defined in crtdefs.h through stdio.h.
-#endif  // __MINGW32__
 
 // Setup for Windows DLL export/import. When building the V8 DLL the
 // BUILDING_V8_SHARED needs to be defined. When building a program which uses
@@ -76,8 +62,6 @@ typedef unsigned __int64 uint64_t;
 
 #else  // _WIN32
 
-#include <stdint.h>
-
 // Setup for Linux shared library export. There is no need to distinguish
 // between building or using the V8 shared library, but we should not
 // export symbols when we are building a static library.
@@ -127,7 +111,6 @@ class Arguments;
 class Object;
 class Heap;
 class Top;
-
 }
 
 
@@ -476,10 +459,10 @@ class V8EXPORT HandleScope {
       level = 0;
     }
   };
-  
+
   void Leave();
 
-  
+
   internal::Object** prev_next_;
   internal::Object** prev_limit_;
 
@@ -1055,7 +1038,7 @@ class String : public Primitive {
    */
   V8EXPORT bool IsExternalAscii() const;
 
-  class V8EXPORT ExternalStringResourceBase {
+  class V8EXPORT ExternalStringResourceBase {  // NOLINT
    public:
     virtual ~ExternalStringResourceBase() {}
 
@@ -2365,12 +2348,15 @@ class V8EXPORT ResourceConstraints {
   void set_max_young_space_size(int value) { max_young_space_size_ = value; }
   int max_old_space_size() const { return max_old_space_size_; }
   void set_max_old_space_size(int value) { max_old_space_size_ = value; }
+  int max_executable_size() { return max_executable_size_; }
+  void set_max_executable_size(int value) { max_executable_size_ = value; }
   uint32_t* stack_limit() const { return stack_limit_; }
   // Sets an address beyond which the VM's stack may not grow.
   void set_stack_limit(uint32_t* value) { stack_limit_ = value; }
  private:
   int max_young_space_size_;
   int max_old_space_size_;
+  int max_executable_size_;
   uint32_t* stack_limit_;
 };
 
@@ -2502,13 +2488,18 @@ class V8EXPORT HeapStatistics {
  public:
   HeapStatistics();
   size_t total_heap_size() { return total_heap_size_; }
+  size_t total_heap_size_executable() { return total_heap_size_executable_; }
   size_t used_heap_size() { return used_heap_size_; }
 
  private:
   void set_total_heap_size(size_t size) { total_heap_size_ = size; }
+  void set_total_heap_size_executable(size_t size) {
+    total_heap_size_executable_ = size;
+  }
   void set_used_heap_size(size_t size) { used_heap_size_ = size; }
 
   size_t total_heap_size_;
+  size_t total_heap_size_executable_;
   size_t used_heap_size_;
 
   friend class V8;
@@ -3260,8 +3251,8 @@ class V8EXPORT Locker {
 /**
  * An interface for exporting data from V8, using "push" model.
  */
-class V8EXPORT OutputStream {
-public:
+class V8EXPORT OutputStream {  // NOLINT
+ public:
   enum OutputEncoding {
     kAscii = 0  // 7-bit ASCII.
   };
@@ -3291,6 +3282,8 @@ public:
 
 namespace internal {
 
+static const int kApiPointerSize = sizeof(void*);  // NOLINT
+static const int kApiIntSize = sizeof(int);  // NOLINT
 
 // Tag information for HeapObject.
 const int kHeapObjectTag = 1;
@@ -3326,19 +3319,19 @@ template <> struct SmiConstants<8> {
   }
 };
 
-const int kSmiShiftSize = SmiConstants<sizeof(void*)>::kSmiShiftSize;
-const int kSmiValueSize = SmiConstants<sizeof(void*)>::kSmiValueSize;
+const int kSmiShiftSize = SmiConstants<kApiPointerSize>::kSmiShiftSize;
+const int kSmiValueSize = SmiConstants<kApiPointerSize>::kSmiValueSize;
 
 template <size_t ptr_size> struct InternalConstants;
 
 // Internal constants for 32-bit systems.
 template <> struct InternalConstants<4> {
-  static const int kStringResourceOffset = 3 * sizeof(void*);
+  static const int kStringResourceOffset = 3 * kApiPointerSize;
 };
 
 // Internal constants for 64-bit systems.
 template <> struct InternalConstants<8> {
-  static const int kStringResourceOffset = 3 * sizeof(void*);
+  static const int kStringResourceOffset = 3 * kApiPointerSize;
 };
 
 /**
@@ -3352,12 +3345,12 @@ class Internals {
   // These values match non-compiler-dependent values defined within
   // the implementation of v8.
   static const int kHeapObjectMapOffset = 0;
-  static const int kMapInstanceTypeOffset = sizeof(void*) + sizeof(int);
+  static const int kMapInstanceTypeOffset = kApiPointerSize + kApiIntSize;
   static const int kStringResourceOffset =
-      InternalConstants<sizeof(void*)>::kStringResourceOffset;
+      InternalConstants<kApiPointerSize>::kStringResourceOffset;
 
-  static const int kProxyProxyOffset = sizeof(void*);
-  static const int kJSObjectHeaderSize = 3 * sizeof(void*);
+  static const int kProxyProxyOffset = kApiPointerSize;
+  static const int kJSObjectHeaderSize = 3 * kApiPointerSize;
   static const int kFullStringRepresentationMask = 0x07;
   static const int kExternalTwoByteRepresentationTag = 0x02;
 
@@ -3375,7 +3368,7 @@ class Internals {
   }
 
   static inline int SmiValue(internal::Object* value) {
-    return SmiConstants<sizeof(void*)>::SmiToInt(value);
+    return SmiConstants<kApiPointerSize>::SmiToInt(value);
   }
 
   static inline int GetInstanceType(internal::Object* obj) {
@@ -3404,10 +3397,9 @@ class Internals {
     uint8_t* addr = reinterpret_cast<uint8_t*>(ptr) + offset - kHeapObjectTag;
     return *reinterpret_cast<T*>(addr);
   }
-
 };
 
-}
+}  // namespace internal
 
 
 template <class T>
@@ -3567,7 +3559,7 @@ Local<Value> Object::UncheckedGetInternalField(int index) {
     // If the object is a plain JSObject, which is the common case,
     // we know where to find the internal fields and can return the
     // value directly.
-    int offset = I::kJSObjectHeaderSize + (sizeof(void*) * index);
+    int offset = I::kJSObjectHeaderSize + (internal::kApiPointerSize * index);
     O* value = I::ReadField<O*>(obj, offset);
     O** result = HandleScope::CreateHandle(value);
     return Local<Value>(reinterpret_cast<Value*>(result));
@@ -3603,7 +3595,7 @@ void* Object::GetPointerFromInternalField(int index) {
     // If the object is a plain JSObject, which is the common case,
     // we know where to find the internal fields and can return the
     // value directly.
-    int offset = I::kJSObjectHeaderSize + (sizeof(void*) * index);
+    int offset = I::kJSObjectHeaderSize + (internal::kApiPointerSize * index);
     O* value = I::ReadField<O*>(obj, offset);
     return I::GetExternalPointer(value);
   }
diff --git a/deps/v8/include/v8stdint.h b/deps/v8/include/v8stdint.h
new file mode 100644 (file)
index 0000000..50b4f29
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Load definitions of standard types.
+
+#ifndef V8STDINT_H_
+#define V8STDINT_H_
+
+#include <stdio.h>
+
+#if defined(_WIN32) && !defined(__MINGW32__)
+
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef short int16_t;  // NOLINT
+typedef unsigned short uint16_t;  // NOLINT
+typedef int int32_t;
+typedef unsigned int uint32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+// intptr_t and friends are defined in crtdefs.h through stdio.h.
+
+#else
+
+#include <stdint.h>
+
+#endif
+
+#endif  // V8STDINT_H_
index ef5485d85428d07695516f5bd208a245d6d5df38..316387fa231e943a8d56315215432b0f863b5ed1 100755 (executable)
@@ -40,6 +40,8 @@ SOURCES = {
     api.cc
     assembler.cc
     ast.cc
+    bignum.cc
+    bignum-dtoa.cc
     bootstrapper.cc
     builtins.cc
     cached-powers.cc
@@ -95,6 +97,7 @@ SOURCES = {
     register-allocator.cc
     rewriter.cc
     runtime.cc
+    scanner-base.cc
     scanner.cc
     scopeinfo.cc
     scopes.cc
@@ -117,6 +120,8 @@ SOURCES = {
     version.cc
     virtual-frame.cc
     zone.cc
+    extensions/gc-extension.cc
+    extensions/externalize-string-extension.cc
     """),
   'arch:arm': Split("""
     jump-target-light.cc
index 7c21659ebc4d95d5fc5a2a07ba98f9ef356a07c3..08ef41b9f7ea60d95911fd4caa97d299d7bee20c 100644 (file)
@@ -316,8 +316,10 @@ MaybeObject* Accessors::ScriptGetLineEnds(Object* object, void*) {
   InitScriptLineEnds(script);
   ASSERT(script->line_ends()->IsFixedArray());
   Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
-  Handle<FixedArray> copy = Factory::CopyFixedArray(line_ends);
-  Handle<JSArray> js_array = Factory::NewJSArrayWithElements(copy);
+  // We do not want anyone to modify this array from JS.
+  ASSERT(*line_ends == Heap::empty_fixed_array() ||
+         line_ends->map() == Heap::fixed_cow_array_map());
+  Handle<JSArray> js_array = Factory::NewJSArrayWithElements(line_ends);
   return *js_array;
 }
 
index 678f4fd7d2f23495d1ed76adc03a0a17f07dc369..d74c37cd799499b32fe053fa5ceb2b1476547983 100644 (file)
 
 #include <stdlib.h>
 
-#include "v8.h"
+#include "../include/v8stdint.h"
+#include "globals.h"
+#include "checks.h"
+#include "allocation.h"
+#include "utils.h"
 
 namespace v8 {
 namespace internal {
 
-
 void* Malloced::New(size_t size) {
   ASSERT(NativeAllocationChecker::allocation_allowed());
   void* result = malloc(size);
-  if (result == NULL) V8::FatalProcessOutOfMemory("Malloced operator new");
+  if (result == NULL) {
+    v8::internal::FatalProcessOutOfMemory("Malloced operator new");
+  }
   return result;
 }
 
@@ -47,7 +52,7 @@ void Malloced::Delete(void* p) {
 
 
 void Malloced::FatalProcessOutOfMemory() {
-  V8::FatalProcessOutOfMemory("Out of memory");
+  v8::internal::FatalProcessOutOfMemory("Out of memory");
 }
 
 
@@ -82,7 +87,7 @@ void AllStatic::operator delete(void* p) {
 char* StrDup(const char* str) {
   int length = StrLength(str);
   char* result = NewArray<char>(length + 1);
-  memcpy(result, str, length * kCharSize);
+  memcpy(result, str, length);
   result[length] = '\0';
   return result;
 }
@@ -92,7 +97,7 @@ char* StrNDup(const char* str, int n) {
   int length = StrLength(str);
   if (n < length) length = n;
   char* result = NewArray<char>(length + 1);
-  memcpy(result, str, length * kCharSize);
+  memcpy(result, str, length);
   result[length] = '\0';
   return result;
 }
@@ -124,6 +129,7 @@ void* PreallocatedStorage::New(size_t size) {
   }
   ASSERT(free_list_.next_ != &free_list_);
   ASSERT(free_list_.previous_ != &free_list_);
+
   size = (size + kPointerSize - 1) & ~(kPointerSize - 1);
   // Search for exact fit.
   for (PreallocatedStorage* storage = free_list_.next_;
index 70a3a038899c73cf732d182e2f67384a42267236..6f4bd2fb545431d4a9eb0cc61c2978b7c12c76c4 100644 (file)
 namespace v8 {
 namespace internal {
 
+// Called when allocation routines fail to allocate.
+// This function should not return, but should terminate the current
+// processing.
+void FatalProcessOutOfMemory(const char* message);
 
 // A class that controls whether allocation is allowed.  This is for
 // the C++ heap only!
index 617922dd5a752e7667d4937eb59f1ede38223a5a..5912449169889c18e3064ca21338949bfb1cb0cc 100644 (file)
@@ -43,7 +43,6 @@
 #include "serialize.h"
 #include "snapshot.h"
 #include "top.h"
-#include "utils.h"
 #include "v8threads.h"
 #include "version.h"
 
@@ -116,7 +115,6 @@ static void DefaultFatalErrorHandler(const char* location,
 }
 
 
-
 static FatalErrorCallback& GetFatalErrorHandler() {
   if (exception_behavior == NULL) {
     exception_behavior = DefaultFatalErrorHandler;
@@ -125,6 +123,10 @@ static FatalErrorCallback& GetFatalErrorHandler() {
 }
 
 
+void i::FatalProcessOutOfMemory(const char* location) {
+  i::V8::FatalProcessOutOfMemory(location, false);
+}
+
 
 // When V8 cannot allocated memory FatalProcessOutOfMemory is called.
 // The default fatal error handler is called and execution is stopped.
@@ -394,14 +396,18 @@ v8::Handle<Boolean> False() {
 ResourceConstraints::ResourceConstraints()
   : max_young_space_size_(0),
     max_old_space_size_(0),
+    max_executable_size_(0),
     stack_limit_(NULL) { }
 
 
 bool SetResourceConstraints(ResourceConstraints* constraints) {
   int young_space_size = constraints->max_young_space_size();
   int old_gen_size = constraints->max_old_space_size();
-  if (young_space_size != 0 || old_gen_size != 0) {
-    bool result = i::Heap::ConfigureHeap(young_space_size / 2, old_gen_size);
+  int max_executable_size = constraints->max_executable_size();
+  if (young_space_size != 0 || old_gen_size != 0 || max_executable_size != 0) {
+    bool result = i::Heap::ConfigureHeap(young_space_size / 2,
+                                         old_gen_size,
+                                         max_executable_size);
     if (!result) return false;
   }
   if (constraints->stack_limit() != NULL) {
@@ -3260,11 +3266,15 @@ bool v8::V8::Dispose() {
 }
 
 
-HeapStatistics::HeapStatistics(): total_heap_size_(0), used_heap_size_(0) { }
+HeapStatistics::HeapStatistics(): total_heap_size_(0),
+                                  total_heap_size_executable_(0),
+                                  used_heap_size_(0) { }
 
 
 void v8::V8::GetHeapStatistics(HeapStatistics* heap_statistics) {
   heap_statistics->set_total_heap_size(i::Heap::CommittedMemory());
+  heap_statistics->set_total_heap_size_executable(
+      i::Heap::CommittedMemoryExecutable());
   heap_statistics->set_used_heap_size(i::Heap::SizeOfObjects());
 }
 
index ebbd9b1138a5182578d190d1d6ac430fe3940357..4cb421c577ec2bbcc0f1e5ed93cc65d933d9d81c 100644 (file)
@@ -317,7 +317,8 @@ static const Instr kLdrStrOffsetMask = 0x00000fff;
 static const int kMinimalBufferSize = 4*KB;
 static byte* spare_buffer_ = NULL;
 
-Assembler::Assembler(void* buffer, int buffer_size) {
+Assembler::Assembler(void* buffer, int buffer_size)
+    : positions_recorder_(this) {
   if (buffer == NULL) {
     // Do our own buffer management.
     if (buffer_size <= kMinimalBufferSize) {
@@ -354,10 +355,6 @@ Assembler::Assembler(void* buffer, int buffer_size) {
   no_const_pool_before_ = 0;
   last_const_pool_end_ = 0;
   last_bound_pos_ = 0;
-  current_statement_position_ = RelocInfo::kNoPosition;
-  current_position_ = RelocInfo::kNoPosition;
-  written_statement_position_ = current_statement_position_;
-  written_position_ = current_position_;
 }
 
 
@@ -752,15 +749,15 @@ static bool fits_shifter(uint32_t imm32,
 // if they can be encoded in the ARM's 12 bits of immediate-offset instruction
 // space.  There is no guarantee that the relocated location can be similarly
 // encoded.
-static bool MustUseConstantPool(RelocInfo::Mode rmode) {
-  if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
+bool Operand::must_use_constant_pool() const {
+  if (rmode_ == RelocInfo::EXTERNAL_REFERENCE) {
 #ifdef DEBUG
     if (!Serializer::enabled()) {
       Serializer::TooLateToEnableNow();
     }
 #endif  // def DEBUG
     return Serializer::enabled();
-  } else if (rmode == RelocInfo::NONE) {
+  } else if (rmode_ == RelocInfo::NONE) {
     return false;
   }
   return true;
@@ -769,7 +766,7 @@ static bool MustUseConstantPool(RelocInfo::Mode rmode) {
 
 bool Operand::is_single_instruction() const {
   if (rm_.is_valid()) return true;
-  if (MustUseConstantPool(rmode_)) return false;
+  if (must_use_constant_pool()) return false;
   uint32_t dummy1, dummy2;
   return fits_shifter(imm32_, &dummy1, &dummy2, NULL);
 }
@@ -785,7 +782,7 @@ void Assembler::addrmod1(Instr instr,
     // Immediate.
     uint32_t rotate_imm;
     uint32_t immed_8;
-    if (MustUseConstantPool(x.rmode_) ||
+    if (x.must_use_constant_pool() ||
         !fits_shifter(x.imm32_, &rotate_imm, &immed_8, &instr)) {
       // The immediate operand cannot be encoded as a shifter operand, so load
       // it first to register ip and change the original instruction to use ip.
@@ -794,8 +791,7 @@ void Assembler::addrmod1(Instr instr,
       CHECK(!rn.is(ip));  // rn should never be ip, or will be trashed
       Condition cond = static_cast<Condition>(instr & CondMask);
       if ((instr & ~CondMask) == 13*B21) {  // mov, S not set
-        if (MustUseConstantPool(x.rmode_) ||
-            !CpuFeatures::IsSupported(ARMv7)) {
+        if (x.must_use_constant_pool() || !CpuFeatures::IsSupported(ARMv7)) {
           RecordRelocInfo(x.rmode_, x.imm32_);
           ldr(rd, MemOperand(pc, 0), cond);
         } else {
@@ -806,7 +802,7 @@ void Assembler::addrmod1(Instr instr,
       } else {
         // If this is not a mov or mvn instruction we may still be able to avoid
         // a constant pool entry by using mvn or movw.
-        if (!MustUseConstantPool(x.rmode_) &&
+        if (!x.must_use_constant_pool() &&
             (instr & kMovMvnMask) != kMovMvnPattern) {
           mov(ip, x, LeaveCC, cond);
         } else {
@@ -999,7 +995,7 @@ void Assembler::bl(int branch_offset, Condition cond) {
 
 
 void Assembler::blx(int branch_offset) {  // v5 and above
-  WriteRecordedPositions();
+  positions_recorder()->WriteRecordedPositions();
   ASSERT((branch_offset & 1) == 0);
   int h = ((branch_offset & 2) >> 1)*B24;
   int imm24 = branch_offset >> 2;
@@ -1009,14 +1005,14 @@ void Assembler::blx(int branch_offset) {  // v5 and above
 
 
 void Assembler::blx(Register target, Condition cond) {  // v5 and above
-  WriteRecordedPositions();
+  positions_recorder()->WriteRecordedPositions();
   ASSERT(!target.is(pc));
   emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | 3*B4 | target.code());
 }
 
 
 void Assembler::bx(Register target, Condition cond) {  // v5 and above, plus v4t
-  WriteRecordedPositions();
+  positions_recorder()->WriteRecordedPositions();
   ASSERT(!target.is(pc));  // use of pc is actually allowed, but discouraged
   emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | B4 | target.code());
 }
@@ -1114,7 +1110,7 @@ void Assembler::orr(Register dst, Register src1, const Operand& src2,
 
 void Assembler::mov(Register dst, const Operand& src, SBit s, Condition cond) {
   if (dst.is(pc)) {
-    WriteRecordedPositions();
+    positions_recorder()->WriteRecordedPositions();
   }
   // Don't allow nop instructions in the form mov rn, rn to be generated using
   // the mov instruction. They must be generated using nop(int)
@@ -1339,7 +1335,7 @@ void Assembler::msr(SRegisterFieldMask fields, const Operand& src,
     // Immediate.
     uint32_t rotate_imm;
     uint32_t immed_8;
-    if (MustUseConstantPool(src.rmode_) ||
+    if (src.must_use_constant_pool() ||
         !fits_shifter(src.imm32_, &rotate_imm, &immed_8, NULL)) {
       // Immediate operand cannot be encoded, load it first to register ip.
       RecordRelocInfo(src.rmode_, src.imm32_);
@@ -1359,7 +1355,7 @@ void Assembler::msr(SRegisterFieldMask fields, const Operand& src,
 // Load/Store instructions.
 void Assembler::ldr(Register dst, const MemOperand& src, Condition cond) {
   if (dst.is(pc)) {
-    WriteRecordedPositions();
+    positions_recorder()->WriteRecordedPositions();
   }
   addrmod2(cond | B26 | L, dst, src);
 
@@ -2148,6 +2144,7 @@ static Instr EncodeVCVT(const VFPType dst_type,
                         const int dst_code,
                         const VFPType src_type,
                         const int src_code,
+                        Assembler::ConversionMode mode,
                         const Condition cond) {
   ASSERT(src_type != dst_type);
   int D, Vd, M, Vm;
@@ -2166,7 +2163,7 @@ static Instr EncodeVCVT(const VFPType dst_type,
     if (IsIntegerVFPType(dst_type)) {
       opc2 = IsSignedVFPType(dst_type) ? 0x5 : 0x4;
       sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0;
-      op = 1;  // round towards zero
+      op = mode;
     } else {
       ASSERT(IsIntegerVFPType(src_type));
       opc2 = 0x0;
@@ -2190,57 +2187,64 @@ static Instr EncodeVCVT(const VFPType dst_type,
 
 void Assembler::vcvt_f64_s32(const DwVfpRegister dst,
                              const SwVfpRegister src,
+                             ConversionMode mode,
                              const Condition cond) {
   ASSERT(CpuFeatures::IsEnabled(VFP3));
-  emit(EncodeVCVT(F64, dst.code(), S32, src.code(), cond));
+  emit(EncodeVCVT(F64, dst.code(), S32, src.code(), mode, cond));
 }
 
 
 void Assembler::vcvt_f32_s32(const SwVfpRegister dst,
                              const SwVfpRegister src,
+                             ConversionMode mode,
                              const Condition cond) {
   ASSERT(CpuFeatures::IsEnabled(VFP3));
-  emit(EncodeVCVT(F32, dst.code(), S32, src.code(), cond));
+  emit(EncodeVCVT(F32, dst.code(), S32, src.code(), mode, cond));
 }
 
 
 void Assembler::vcvt_f64_u32(const DwVfpRegister dst,
                              const SwVfpRegister src,
+                             ConversionMode mode,
                              const Condition cond) {
   ASSERT(CpuFeatures::IsEnabled(VFP3));
-  emit(EncodeVCVT(F64, dst.code(), U32, src.code(), cond));
+  emit(EncodeVCVT(F64, dst.code(), U32, src.code(), mode, cond));
 }
 
 
 void Assembler::vcvt_s32_f64(const SwVfpRegister dst,
                              const DwVfpRegister src,
+                             ConversionMode mode,
                              const Condition cond) {
   ASSERT(CpuFeatures::IsEnabled(VFP3));
-  emit(EncodeVCVT(S32, dst.code(), F64, src.code(), cond));
+  emit(EncodeVCVT(S32, dst.code(), F64, src.code(), mode, cond));
 }
 
 
 void Assembler::vcvt_u32_f64(const SwVfpRegister dst,
                              const DwVfpRegister src,
+                             ConversionMode mode,
                              const Condition cond) {
   ASSERT(CpuFeatures::IsEnabled(VFP3));
-  emit(EncodeVCVT(U32, dst.code(), F64, src.code(), cond));
+  emit(EncodeVCVT(U32, dst.code(), F64, src.code(), mode, cond));
 }
 
 
 void Assembler::vcvt_f64_f32(const DwVfpRegister dst,
                              const SwVfpRegister src,
+                             ConversionMode mode,
                              const Condition cond) {
   ASSERT(CpuFeatures::IsEnabled(VFP3));
-  emit(EncodeVCVT(F64, dst.code(), F32, src.code(), cond));
+  emit(EncodeVCVT(F64, dst.code(), F32, src.code(), mode, cond));
 }
 
 
 void Assembler::vcvt_f32_f64(const SwVfpRegister dst,
                              const DwVfpRegister src,
+                             ConversionMode mode,
                              const Condition cond) {
   ASSERT(CpuFeatures::IsEnabled(VFP3));
-  emit(EncodeVCVT(F32, dst.code(), F64, src.code(), cond));
+  emit(EncodeVCVT(F32, dst.code(), F64, src.code(), mode, cond));
 }
 
 
@@ -2333,6 +2337,16 @@ void Assembler::vcmp(const DwVfpRegister src1,
 }
 
 
+void Assembler::vmsr(Register dst, Condition cond) {
+  // Instruction details available in ARM DDI 0406A, A8-652.
+  // cond(31-28) | 1110 (27-24) | 1110(23-20)| 0001 (19-16) |
+  // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
+  ASSERT(CpuFeatures::IsEnabled(VFP3));
+  emit(cond | 0xE*B24 | 0xE*B20 |  B16 |
+       dst.code()*B12 | 0xA*B8 | B4);
+}
+
+
 void Assembler::vmrs(Register dst, Condition cond) {
   // Instruction details available in ARM DDI 0406A, A8-652.
   // cond(31-28) | 1110 (27-24) | 1111(23-20)| 0001 (19-16) |
@@ -2343,7 +2357,6 @@ void Assembler::vmrs(Register dst, Condition cond) {
 }
 
 
-
 void Assembler::vsqrt(const DwVfpRegister dst,
                       const DwVfpRegister src,
                       const Condition cond) {
@@ -2377,14 +2390,14 @@ void Assembler::BlockConstPoolFor(int instructions) {
 
 // Debugging.
 void Assembler::RecordJSReturn() {
-  WriteRecordedPositions();
+  positions_recorder()->WriteRecordedPositions();
   CheckBuffer();
   RecordRelocInfo(RelocInfo::JS_RETURN);
 }
 
 
 void Assembler::RecordDebugBreakSlot() {
-  WriteRecordedPositions();
+  positions_recorder()->WriteRecordedPositions();
   CheckBuffer();
   RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
 }
@@ -2398,47 +2411,6 @@ void Assembler::RecordComment(const char* msg) {
 }
 
 
-void Assembler::RecordPosition(int pos) {
-  if (pos == RelocInfo::kNoPosition) return;
-  ASSERT(pos >= 0);
-  current_position_ = pos;
-}
-
-
-void Assembler::RecordStatementPosition(int pos) {
-  if (pos == RelocInfo::kNoPosition) return;
-  ASSERT(pos >= 0);
-  current_statement_position_ = pos;
-}
-
-
-bool Assembler::WriteRecordedPositions() {
-  bool written = false;
-
-  // Write the statement position if it is different from what was written last
-  // time.
-  if (current_statement_position_ != written_statement_position_) {
-    CheckBuffer();
-    RecordRelocInfo(RelocInfo::STATEMENT_POSITION, current_statement_position_);
-    written_statement_position_ = current_statement_position_;
-    written = true;
-  }
-
-  // Write the position if it is different from what was written last time and
-  // also different from the written statement position.
-  if (current_position_ != written_position_ &&
-      current_position_ != written_statement_position_) {
-    CheckBuffer();
-    RecordRelocInfo(RelocInfo::POSITION, current_position_);
-    written_position_ = current_position_;
-    written = true;
-  }
-
-  // Return whether something was written.
-  return written;
-}
-
-
 void Assembler::GrowBuffer() {
   if (!own_buffer_) FATAL("external code buffer is too small");
 
index 5b647a7537e8f7322b86bcd5c5875c1bfaf4be03..606ff86340e76f51ab7ec6cda5f2a8e65c0db419 100644 (file)
@@ -219,6 +219,11 @@ const DwVfpRegister d13 = { 13 };
 const DwVfpRegister d14 = { 14 };
 const DwVfpRegister d15 = { 15 };
 
+// VFP FPSCR constants.
+static const uint32_t kVFPExceptionMask = 0xf;
+static const uint32_t kVFPRoundingModeMask = 3 << 22;
+static const uint32_t kVFPFlushToZeroMask = 1 << 24;
+static const uint32_t kVFPRoundToMinusInfinityBits = 2 << 22;
 
 // Coprocessor register
 struct CRegister {
@@ -448,6 +453,7 @@ class Operand BASE_EMBEDDED {
   // Return true of this operand fits in one instruction so that no
   // 2-instruction solution with a load into the ip register is necessary.
   bool is_single_instruction() const;
+  bool must_use_constant_pool() const;
 
   inline int32_t immediate() const {
     ASSERT(!rm_.is_valid());
@@ -1007,26 +1013,37 @@ class Assembler : public Malloced {
   void vmov(const Register dst,
             const SwVfpRegister src,
             const Condition cond = al);
+  enum ConversionMode {
+    FPSCRRounding = 0,
+    RoundToZero = 1
+  };
   void vcvt_f64_s32(const DwVfpRegister dst,
                     const SwVfpRegister src,
+                    ConversionMode mode = RoundToZero,
                     const Condition cond = al);
   void vcvt_f32_s32(const SwVfpRegister dst,
                     const SwVfpRegister src,
+                    ConversionMode mode = RoundToZero,
                     const Condition cond = al);
   void vcvt_f64_u32(const DwVfpRegister dst,
                     const SwVfpRegister src,
+                    ConversionMode mode = RoundToZero,
                     const Condition cond = al);
   void vcvt_s32_f64(const SwVfpRegister dst,
                     const DwVfpRegister src,
+                    ConversionMode mode = RoundToZero,
                     const Condition cond = al);
   void vcvt_u32_f64(const SwVfpRegister dst,
                     const DwVfpRegister src,
+                    ConversionMode mode = RoundToZero,
                     const Condition cond = al);
   void vcvt_f64_f32(const DwVfpRegister dst,
                     const SwVfpRegister src,
+                    ConversionMode mode = RoundToZero,
                     const Condition cond = al);
   void vcvt_f32_f64(const SwVfpRegister dst,
                     const DwVfpRegister src,
+                    ConversionMode mode = RoundToZero,
                     const Condition cond = al);
 
   void vadd(const DwVfpRegister dst,
@@ -1055,6 +1072,8 @@ class Assembler : public Malloced {
             const Condition cond = al);
   void vmrs(const Register dst,
             const Condition cond = al);
+  void vmsr(const Register dst,
+            const Condition cond = al);
   void vsqrt(const DwVfpRegister dst,
              const DwVfpRegister src,
              const Condition cond = al);
@@ -1117,13 +1136,9 @@ class Assembler : public Malloced {
   // Use --debug_code to enable.
   void RecordComment(const char* msg);
 
-  void RecordPosition(int pos);
-  void RecordStatementPosition(int pos);
-  bool WriteRecordedPositions();
-
   int pc_offset() const { return pc_ - buffer_; }
-  int current_position() const { return current_position_; }
-  int current_statement_position() const { return current_statement_position_; }
+
+  PositionsRecorder* positions_recorder() { return &positions_recorder_; }
 
   bool can_peephole_optimize(int instructions) {
     if (!FLAG_peephole_optimization) return false;
@@ -1259,12 +1274,6 @@ class Assembler : public Malloced {
   // The bound position, before this we cannot do instruction elimination.
   int last_bound_pos_;
 
-  // source position information
-  int current_position_;
-  int current_statement_position_;
-  int written_position_;
-  int written_statement_position_;
-
   // Code emission
   inline void CheckBuffer();
   void GrowBuffer();
@@ -1290,8 +1299,21 @@ class Assembler : public Malloced {
   friend class RelocInfo;
   friend class CodePatcher;
   friend class BlockConstPoolScope;
+
+  PositionsRecorder positions_recorder_;
+  friend class PositionsRecorder;
+  friend class EnsureSpace;
 };
 
+
+class EnsureSpace BASE_EMBEDDED {
+ public:
+  explicit EnsureSpace(Assembler* assembler) {
+    assembler->CheckBuffer();
+  }
+};
+
+
 } }  // namespace v8::internal
 
 #endif  // V8_ARM_ASSEMBLER_ARM_H_
index 70ff244649cc313f8110e6cb21341a99099b5628..dd0520feed4c4ca9a9ef1cff9947e5334531b77d 100644 (file)
@@ -43,6 +43,7 @@
 #include "register-allocator-inl.h"
 #include "runtime.h"
 #include "scopes.h"
+#include "stub-cache.h"
 #include "virtual-frame-inl.h"
 #include "virtual-frame-arm-inl.h"
 
@@ -557,7 +558,7 @@ void CodeGenerator::Load(Expression* expr) {
 
 void CodeGenerator::LoadGlobal() {
   Register reg = frame_->GetTOSRegister();
-  __ ldr(reg, GlobalObject());
+  __ ldr(reg, GlobalObjectOperand());
   frame_->EmitPush(reg);
 }
 
@@ -1891,18 +1892,15 @@ void CodeGenerator::CheckStack() {
   frame_->SpillAll();
   Comment cmnt(masm_, "[ check stack");
   __ LoadRoot(ip, Heap::kStackLimitRootIndex);
-  // Put the lr setup instruction in the delay slot.  kInstrSize is added to
-  // the implicit 8 byte offset that always applies to operations with pc and
-  // gives a return address 12 bytes down.
-  masm_->add(lr, pc, Operand(Assembler::kInstrSize));
   masm_->cmp(sp, Operand(ip));
   StackCheckStub stub;
   // Call the stub if lower.
-  masm_->mov(pc,
+  masm_->mov(ip,
              Operand(reinterpret_cast<intptr_t>(stub.GetCode().location()),
                      RelocInfo::CODE_TARGET),
              LeaveCC,
              lo);
+  masm_->Call(ip, lo);
 }
 
 
@@ -4232,7 +4230,7 @@ void CodeGenerator::VisitCall(Call* node) {
     // Setup the name register and call the IC initialization code.
     __ mov(r2, Operand(var->name()));
     InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
-    Handle<Code> stub = ComputeCallInitialize(arg_count, in_loop);
+    Handle<Code> stub = StubCache::ComputeCallInitialize(arg_count, in_loop);
     CodeForSourcePosition(node->position());
     frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET_CONTEXT,
                            arg_count + 1);
@@ -4326,7 +4324,8 @@ void CodeGenerator::VisitCall(Call* node) {
         // Set the name register and call the IC initialization code.
         __ mov(r2, Operand(name));
         InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
-        Handle<Code> stub = ComputeCallInitialize(arg_count, in_loop);
+        Handle<Code> stub =
+            StubCache::ComputeCallInitialize(arg_count, in_loop);
         CodeForSourcePosition(node->position());
         frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1);
         __ ldr(cp, frame_->Context());
@@ -4337,9 +4336,12 @@ void CodeGenerator::VisitCall(Call* node) {
       // -------------------------------------------
       // JavaScript example: 'array[index](1, 2, 3)'
       // -------------------------------------------
+
+      // Load the receiver and name of the function.
       Load(property->obj());
+      Load(property->key());
+
       if (property->is_synthetic()) {
-        Load(property->key());
         EmitKeyedLoad();
         // Put the function below the receiver.
         // Use the global receiver.
@@ -4349,21 +4351,28 @@ void CodeGenerator::VisitCall(Call* node) {
         CallWithArguments(args, RECEIVER_MIGHT_BE_VALUE, node->position());
         frame_->EmitPush(r0);
       } else {
+        // Swap the name of the function and the receiver on the stack to follow
+        // the calling convention for call ICs.
+        Register key = frame_->PopToRegister();
+        Register receiver = frame_->PopToRegister(key);
+        frame_->EmitPush(key);
+        frame_->EmitPush(receiver);
+
         // Load the arguments.
         int arg_count = args->length();
         for (int i = 0; i < arg_count; i++) {
           Load(args->at(i));
         }
 
-        // Set the name register and call the IC initialization code.
-        Load(property->key());
-        frame_->SpillAll();
-        frame_->EmitPop(r2);  // Function name.
-
+        // Load the key into r2 and call the IC initialization code.
         InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
-        Handle<Code> stub = ComputeKeyedCallInitialize(arg_count, in_loop);
+        Handle<Code> stub =
+            StubCache::ComputeKeyedCallInitialize(arg_count, in_loop);
         CodeForSourcePosition(node->position());
+        frame_->SpillAll();
+        __ ldr(r2, frame_->ElementAt(arg_count + 1));
         frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1);
+        frame_->Drop();  // Drop the key still on the stack.
         __ ldr(cp, frame_->Context());
         frame_->EmitPush(r0);
       }
@@ -5135,11 +5144,11 @@ class DeferredIsStringWrapperSafeForDefaultValueOf : public DeferredCode {
     __ b(eq, &false_result);
     __ ldr(scratch1_, FieldMemOperand(scratch1_, HeapObject::kMapOffset));
     __ ldr(scratch2_,
-           CodeGenerator::ContextOperand(cp, Context::GLOBAL_INDEX));
+           ContextOperand(cp, Context::GLOBAL_INDEX));
     __ ldr(scratch2_,
            FieldMemOperand(scratch2_, GlobalObject::kGlobalContextOffset));
     __ ldr(scratch2_,
-           CodeGenerator::ContextOperand(
+           ContextOperand(
                scratch2_, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
     __ cmp(scratch1_, scratch2_);
     __ b(ne, &false_result);
@@ -5496,73 +5505,6 @@ void CodeGenerator::GenerateRegExpConstructResult(ZoneList<Expression*>* args) {
 }
 
 
-void CodeGenerator::GenerateRegExpCloneResult(ZoneList<Expression*>* args) {
-  ASSERT_EQ(1, args->length());
-
-  Load(args->at(0));
-  frame_->PopToR0();
-  {
-    VirtualFrame::SpilledScope spilled_scope(frame_);
-
-    Label done;
-    Label call_runtime;
-    __ BranchOnSmi(r0, &done);
-
-    // Load JSRegExp map into r1. Check that argument object has this map.
-    // Arguments to this function should be results of calling RegExp exec,
-    // which is either an unmodified JSRegExpResult or null. Anything not having
-    // the unmodified JSRegExpResult map is returned unmodified.
-    // This also ensures that elements are fast.
-
-    __ ldr(r1, ContextOperand(cp, Context::GLOBAL_INDEX));
-    __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalContextOffset));
-    __ ldr(r1, ContextOperand(r1, Context::REGEXP_RESULT_MAP_INDEX));
-    __ ldr(ip, FieldMemOperand(r0, HeapObject::kMapOffset));
-    __ cmp(r1, Operand(ip));
-    __ b(ne, &done);
-
-    if (FLAG_debug_code) {
-      __ LoadRoot(r2, Heap::kEmptyFixedArrayRootIndex);
-      __ ldr(ip, FieldMemOperand(r0, JSObject::kPropertiesOffset));
-      __ cmp(ip, r2);
-      __ Check(eq, "JSRegExpResult: default map but non-empty properties.");
-    }
-
-    // All set, copy the contents to a new object.
-    __ AllocateInNewSpace(JSRegExpResult::kSize,
-                          r2,
-                          r3,
-                          r4,
-                          &call_runtime,
-                          NO_ALLOCATION_FLAGS);
-    // Store RegExpResult map as map of allocated object.
-    ASSERT(JSRegExpResult::kSize == 6 * kPointerSize);
-    // Copy all fields (map is already in r1) from (untagged) r0 to r2.
-    // Change map of elements array (ends up in r4) to be a FixedCOWArray.
-    __ bic(r0, r0, Operand(kHeapObjectTagMask));
-    __ ldm(ib, r0, r3.bit() | r4.bit() | r5.bit() | r6.bit() | r7.bit());
-    __ stm(ia, r2,
-           r1.bit() | r3.bit() | r4.bit() | r5.bit() | r6.bit() | r7.bit());
-    ASSERT(JSRegExp::kElementsOffset == 2 * kPointerSize);
-    // Check whether elements array is empty fixed array, and otherwise make
-    // it copy-on-write (it never should be empty unless someone is messing
-    // with the arguments to the runtime function).
-    __ LoadRoot(ip, Heap::kEmptyFixedArrayRootIndex);
-    __ add(r0, r2, Operand(kHeapObjectTag));  // Tag result and move it to r0.
-    __ cmp(r4, ip);
-    __ b(eq, &done);
-    __ LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex);
-    __ str(ip, FieldMemOperand(r4, HeapObject::kMapOffset));
-    __ b(&done);
-    __ bind(&call_runtime);
-    __ push(r0);
-    __ CallRuntime(Runtime::kRegExpCloneResult, 1);
-    __ bind(&done);
-  }
-  frame_->EmitPush(r0);
-}
-
-
 class DeferredSearchCache: public DeferredCode {
  public:
   DeferredSearchCache(Register dst, Register cache, Register key)
@@ -5892,7 +5834,7 @@ void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
     // Prepare stack for calling JS runtime function.
     // Push the builtins object found in the current global object.
     Register scratch = VirtualFrame::scratch0();
-    __ ldr(scratch, GlobalObject());
+    __ ldr(scratch, GlobalObjectOperand());
     Register builtins = frame_->GetTOSRegister();
     __ ldr(builtins, FieldMemOperand(scratch, GlobalObject::kBuiltinsOffset));
     frame_->EmitPush(builtins);
@@ -5910,7 +5852,7 @@ void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
     // Call the JS runtime function.
     __ mov(r2, Operand(node->name()));
     InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
-    Handle<Code> stub = ComputeCallInitialize(arg_count, in_loop);
+    Handle<Code> stub = StubCache::ComputeCallInitialize(arg_count, in_loop);
     frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1);
     __ ldr(cp, frame_->Context());
     frame_->EmitPush(r0);
index e6fd6071e1dc32e28083af176f242507c2af9177..2e8f46668c108199edfdec95774c0c3b44145604 100644 (file)
@@ -279,10 +279,6 @@ class CodeGenerator: public AstVisitor {
     return inlined_write_barrier_size_ + 4;
   }
 
-  static MemOperand ContextOperand(Register context, int index) {
-    return MemOperand(context, Context::SlotOffset(index));
-  }
-
  private:
   // Type of a member function that generates inline code for a native function.
   typedef void (CodeGenerator::*InlineFunctionGenerator)
@@ -349,10 +345,6 @@ class CodeGenerator: public AstVisitor {
                                                JumpTarget* slow);
 
   // Expressions
-  static MemOperand GlobalObject()  {
-    return ContextOperand(cp, Context::GLOBAL_INDEX);
-  }
-
   void LoadCondition(Expression* x,
                      JumpTarget* true_target,
                      JumpTarget* false_target,
@@ -452,10 +444,6 @@ class CodeGenerator: public AstVisitor {
   static Handle<Code> ComputeLazyCompile(int argc);
   void ProcessDeclarations(ZoneList<Declaration*>* declarations);
 
-  static Handle<Code> ComputeCallInitialize(int argc, InLoopFlag in_loop);
-
-  static Handle<Code> ComputeKeyedCallInitialize(int argc, InLoopFlag in_loop);
-
   // Declare global variables and functions in the given array of
   // name/value pairs.
   void DeclareGlobals(Handle<FixedArray> pairs);
@@ -518,8 +506,6 @@ class CodeGenerator: public AstVisitor {
 
   void GenerateRegExpConstructResult(ZoneList<Expression*>* args);
 
-  void GenerateRegExpCloneResult(ZoneList<Expression*>* args);
-
   // Support for fast native caches.
   void GenerateGetFromCache(ZoneList<Expression*>* args);
 
index 123c5e7972006b9bab51d4e64ca1fc05e43823d4..36f6283c967158152dba481d8996e1adf51a0014 100644 (file)
@@ -206,6 +206,13 @@ enum VFPRegPrecision {
   kDoublePrecision = 1
 };
 
+// VFP rounding modes. See ARM DDI 0406B Page A2-29.
+enum FPSCRRoundingModes {
+  RN,   // Round to Nearest.
+  RP,   // Round towards Plus Infinity.
+  RM,   // Round towards Minus Infinity.
+  RZ    // Round towards zero.
+};
 
 typedef int32_t instr_t;
 
index 4e7580f8684ef48a5c7d81907380b53ebb59fea5..297a2db5b2eb1650b3cea33601db66b073924574 100644 (file)
@@ -1046,6 +1046,7 @@ int Decoder::DecodeType7(Instr* instr) {
 // Dd = vdiv(Dn, Dm)
 // vcmp(Dd, Dm)
 // vmrs
+// vmsr
 // Dd = vsqrt(Dm)
 void Decoder::DecodeTypeVFP(Instr* instr) {
   ASSERT((instr->TypeField() == 7) && (instr->Bit(24) == 0x0) );
@@ -1111,16 +1112,22 @@ void Decoder::DecodeTypeVFP(Instr* instr) {
     if ((instr->VCField() == 0x0) &&
         (instr->VAField() == 0x0)) {
       DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(instr);
-    } else if ((instr->VLField() == 0x1) &&
-               (instr->VCField() == 0x0) &&
+    } else if ((instr->VCField() == 0x0) &&
                (instr->VAField() == 0x7) &&
                (instr->Bits(19, 16) == 0x1)) {
-      if (instr->Bits(15, 12) == 0xF)
-        Format(instr, "vmrs'cond APSR, FPSCR");
-      else
-        Unknown(instr);  // Not used by V8.
-    } else {
-      Unknown(instr);  // Not used by V8.
+      if (instr->VLField() == 0) {
+        if (instr->Bits(15, 12) == 0xF) {
+          Format(instr, "vmsr'cond FPSCR, APSR");
+        } else {
+          Format(instr, "vmsr'cond FPSCR, 'rt");
+        }
+      } else {
+        if (instr->Bits(15, 12) == 0xF) {
+          Format(instr, "vmrs'cond APSR, FPSCR");
+        } else {
+          Format(instr, "vmrs'cond 'rt, FPSCR");
+        }
+      }
     }
   }
 }
index 9935e038f5cdeadbf341e50497ecbf19a17a5a52..c50f84ad5e6234dd346334f88dd62d09ba7c2cb2 100644 (file)
@@ -36,6 +36,7 @@
 #include "full-codegen.h"
 #include "parser.h"
 #include "scopes.h"
+#include "stub-cache.h"
 
 namespace v8 {
 namespace internal {
@@ -171,19 +172,16 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
   }
 
   // Check the stack for overflow or break request.
-  // Put the lr setup instruction in the delay slot.  The kInstrSize is
-  // added to the implicit 8 byte offset that always applies to operations
-  // with pc and gives a return address 12 bytes down.
   { Comment cmnt(masm_, "[ Stack check");
     __ LoadRoot(r2, Heap::kStackLimitRootIndex);
-    __ add(lr, pc, Operand(Assembler::kInstrSize));
     __ cmp(sp, Operand(r2));
     StackCheckStub stub;
-    __ mov(pc,
+    __ mov(ip,
            Operand(reinterpret_cast<intptr_t>(stub.GetCode().location()),
                    RelocInfo::CODE_TARGET),
            LeaveCC,
            lo);
+    __ Call(ip, lo);
   }
 
   if (FLAG_trace) {
@@ -1019,7 +1017,7 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
     __ bind(&fast);
   }
 
-  __ ldr(r0, CodeGenerator::GlobalObject());
+  __ ldr(r0, GlobalObjectOperand());
   __ mov(r2, Operand(slot->var()->name()));
   RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
       ? RelocInfo::CODE_TARGET
@@ -1040,7 +1038,7 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var) {
     Comment cmnt(masm_, "Global variable");
     // Use inline caching. Variable name is passed in r2 and the global
     // object (receiver) in r0.
-    __ ldr(r0, CodeGenerator::GlobalObject());
+    __ ldr(r0, GlobalObjectOperand());
     __ mov(r2, Operand(var->name()));
     Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
     EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
@@ -1514,7 +1512,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
     // assignment.  Right-hand-side value is passed in r0, variable name in
     // r2, and the global object in r1.
     __ mov(r2, Operand(var->name()));
-    __ ldr(r1, CodeGenerator::GlobalObject());
+    __ ldr(r1, GlobalObjectOperand());
     Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
     EmitCallIC(ic, RelocInfo::CODE_TARGET);
 
@@ -1688,15 +1686,17 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
   // Code common for calls using the IC.
   ZoneList<Expression*>* args = expr->arguments();
   int arg_count = args->length();
-  for (int i = 0; i < arg_count; i++) {
-    VisitForStackValue(args->at(i));
+  { PreserveStatementPositionScope scope(masm()->positions_recorder());
+    for (int i = 0; i < arg_count; i++) {
+      VisitForStackValue(args->at(i));
+    }
+    __ mov(r2, Operand(name));
   }
-  __ mov(r2, Operand(name));
   // Record source position for debugger.
-  SetSourcePosition(expr->position());
+  SetSourcePosition(expr->position(), FORCED_POSITION);
   // Call the IC initialization code.
   InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
-  Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop);
+  Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, in_loop);
   EmitCallIC(ic, mode);
   // Restore context register.
   __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
@@ -1707,24 +1707,33 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
                                             Expression* key,
                                             RelocInfo::Mode mode) {
+  // Load the key.
+  VisitForAccumulatorValue(key);
+
+  // Swap the name of the function and the receiver on the stack to follow
+  // the calling convention for call ICs.
+  __ pop(r1);
+  __ push(r0);
+  __ push(r1);
+
   // Code common for calls using the IC.
   ZoneList<Expression*>* args = expr->arguments();
   int arg_count = args->length();
-  for (int i = 0; i < arg_count; i++) {
-    VisitForStackValue(args->at(i));
+  { PreserveStatementPositionScope scope(masm()->positions_recorder());
+    for (int i = 0; i < arg_count; i++) {
+      VisitForStackValue(args->at(i));
+    }
   }
-  VisitForAccumulatorValue(key);
-  __ mov(r2, r0);
   // Record source position for debugger.
-  SetSourcePosition(expr->position());
+  SetSourcePosition(expr->position(), FORCED_POSITION);
   // Call the IC initialization code.
   InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
-  Handle<Code> ic = CodeGenerator::ComputeKeyedCallInitialize(arg_count,
-                                                              in_loop);
+  Handle<Code> ic = StubCache::ComputeKeyedCallInitialize(arg_count, in_loop);
+  __ ldr(r2, MemOperand(sp, (arg_count + 1) * kPointerSize));  // Key.
   EmitCallIC(ic, mode);
   // Restore context register.
   __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
-  context()->Plug(r0);
+  context()->DropAndPlug(1, r0);  // Drop the key still on the stack.
 }
 
 
@@ -1732,11 +1741,13 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr) {
   // Code common for calls using the call stub.
   ZoneList<Expression*>* args = expr->arguments();
   int arg_count = args->length();
-  for (int i = 0; i < arg_count; i++) {
-    VisitForStackValue(args->at(i));
+  { PreserveStatementPositionScope scope(masm()->positions_recorder());
+    for (int i = 0; i < arg_count; i++) {
+      VisitForStackValue(args->at(i));
+    }
   }
   // Record source position for debugger.
-  SetSourcePosition(expr->position());
+  SetSourcePosition(expr->position(), FORCED_POSITION);
   InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
   CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
   __ CallStub(&stub);
@@ -1756,41 +1767,45 @@ void FullCodeGenerator::VisitCall(Call* expr) {
     // resolve the function we need to call and the receiver of the
     // call.  Then we call the resolved function using the given
     // arguments.
-    VisitForStackValue(fun);
-    __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
-    __ push(r2);  // Reserved receiver slot.
-
-    // Push the arguments.
     ZoneList<Expression*>* args = expr->arguments();
     int arg_count = args->length();
-    for (int i = 0; i < arg_count; i++) {
-      VisitForStackValue(args->at(i));
-    }
 
-    // Push copy of the function - found below the arguments.
-    __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
-    __ push(r1);
+    { PreserveStatementPositionScope pos_scope(masm()->positions_recorder());
+      VisitForStackValue(fun);
+      __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
+      __ push(r2);  // Reserved receiver slot.
+
+      // Push the arguments.
+      for (int i = 0; i < arg_count; i++) {
+        VisitForStackValue(args->at(i));
+      }
 
-    // Push copy of the first argument or undefined if it doesn't exist.
-    if (arg_count > 0) {
-      __ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
+      // Push copy of the function - found below the arguments.
+      __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
       __ push(r1);
-    } else {
-      __ push(r2);
-    }
 
-    // Push the receiver of the enclosing function and do runtime call.
-    __ ldr(r1, MemOperand(fp, (2 + scope()->num_parameters()) * kPointerSize));
-    __ push(r1);
-    __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
+      // Push copy of the first argument or undefined if it doesn't exist.
+      if (arg_count > 0) {
+        __ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
+        __ push(r1);
+      } else {
+        __ push(r2);
+      }
 
-    // The runtime call returns a pair of values in r0 (function) and
-    // r1 (receiver). Touch up the stack with the right values.
-    __ str(r0, MemOperand(sp, (arg_count + 1) * kPointerSize));
-    __ str(r1, MemOperand(sp, arg_count * kPointerSize));
+      // Push the receiver of the enclosing function and do runtime call.
+      __ ldr(r1,
+             MemOperand(fp, (2 + scope()->num_parameters()) * kPointerSize));
+      __ push(r1);
+      __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
+
+      // The runtime call returns a pair of values in r0 (function) and
+      // r1 (receiver). Touch up the stack with the right values.
+      __ str(r0, MemOperand(sp, (arg_count + 1) * kPointerSize));
+      __ str(r1, MemOperand(sp, arg_count * kPointerSize));
+    }
 
     // Record source position for debugger.
-    SetSourcePosition(expr->position());
+    SetSourcePosition(expr->position(), FORCED_POSITION);
     InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
     CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
     __ CallStub(&stub);
@@ -1799,7 +1814,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
     context()->DropAndPlug(1, r0);
   } else if (var != NULL && !var->is_this() && var->is_global()) {
     // Push global object as receiver for the call IC.
-    __ ldr(r0, CodeGenerator::GlobalObject());
+    __ ldr(r0, GlobalObjectOperand());
     __ push(r0);
     EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
   } else if (var != NULL && var->AsSlot() != NULL &&
@@ -1807,12 +1822,14 @@ void FullCodeGenerator::VisitCall(Call* expr) {
     // Call to a lookup slot (dynamically introduced variable).
     Label slow, done;
 
-    // Generate code for loading from variables potentially shadowed
-    // by eval-introduced variables.
-    EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
-                                    NOT_INSIDE_TYPEOF,
-                                    &slow,
-                                    &done);
+    { PreserveStatementPositionScope scope(masm()->positions_recorder());
+      // Generate code for loading from variables potentially shadowed
+      // by eval-introduced variables.
+      EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
+                                      NOT_INSIDE_TYPEOF,
+                                      &slow,
+                                      &done);
+    }
 
     __ bind(&slow);
     // Call the runtime to find the function to call (returned in r0)
@@ -1833,7 +1850,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
       // Push function.
       __ push(r0);
       // Push global receiver.
-      __ ldr(r1, CodeGenerator::GlobalObject());
+      __ ldr(r1, GlobalObjectOperand());
       __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
       __ push(r1);
       __ bind(&call);
@@ -1846,22 +1863,28 @@ void FullCodeGenerator::VisitCall(Call* expr) {
     Literal* key = prop->key()->AsLiteral();
     if (key != NULL && key->handle()->IsSymbol()) {
       // Call to a named property, use call IC.
-      VisitForStackValue(prop->obj());
+      { PreserveStatementPositionScope scope(masm()->positions_recorder());
+        VisitForStackValue(prop->obj());
+      }
       EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
     } else {
       // Call to a keyed property.
       // For a synthetic property use keyed load IC followed by function call,
       // for a regular property use keyed CallIC.
-      VisitForStackValue(prop->obj());
+      { PreserveStatementPositionScope scope(masm()->positions_recorder());
+        VisitForStackValue(prop->obj());
+      }
       if (prop->is_synthetic()) {
-        VisitForAccumulatorValue(prop->key());
+        { PreserveStatementPositionScope scope(masm()->positions_recorder());
+          VisitForAccumulatorValue(prop->key());
+        }
         // Record source code position for IC call.
-        SetSourcePosition(prop->position());
+        SetSourcePosition(prop->position(), FORCED_POSITION);
         __ pop(r1);  // We do not need to keep the receiver.
 
         Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
         EmitCallIC(ic, RelocInfo::CODE_TARGET);
-        __ ldr(r1, CodeGenerator::GlobalObject());
+        __ ldr(r1, GlobalObjectOperand());
         __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
         __ Push(r0, r1);  // Function, receiver.
         EmitCallWithStub(expr);
@@ -1879,9 +1902,12 @@ void FullCodeGenerator::VisitCall(Call* expr) {
         loop_depth() == 0) {
       lit->set_try_full_codegen(true);
     }
-    VisitForStackValue(fun);
+
+    { PreserveStatementPositionScope scope(masm()->positions_recorder());
+      VisitForStackValue(fun);
+    }
     // Load global receiver object.
-    __ ldr(r1, CodeGenerator::GlobalObject());
+    __ ldr(r1, GlobalObjectOperand());
     __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
     __ push(r1);
     // Emit function call.
@@ -2759,7 +2785,7 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
 
   if (expr->is_jsruntime()) {
     // Prepare for calling JS runtime function.
-    __ ldr(r0, CodeGenerator::GlobalObject());
+    __ ldr(r0, GlobalObjectOperand());
     __ ldr(r0, FieldMemOperand(r0, GlobalObject::kBuiltinsOffset));
     __ push(r0);
   }
@@ -2773,8 +2799,7 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
   if (expr->is_jsruntime()) {
     // Call the JS runtime function.
     __ mov(r2, Operand(expr->name()));
-    Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
-                                                           NOT_IN_LOOP);
+    Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, NOT_IN_LOOP);
     EmitCallIC(ic, RelocInfo::CODE_TARGET);
     // Restore context register.
     __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
@@ -2811,7 +2836,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
           VisitForStackValue(prop->obj());
           VisitForStackValue(prop->key());
         } else if (var->is_global()) {
-          __ ldr(r1, CodeGenerator::GlobalObject());
+          __ ldr(r1, GlobalObjectOperand());
           __ mov(r0, Operand(var->name()));
           __ Push(r1, r0);
         } else {
@@ -3077,7 +3102,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
   VariableProxy* proxy = expr->AsVariableProxy();
   if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) {
     Comment cmnt(masm_, "Global variable");
-    __ ldr(r0, CodeGenerator::GlobalObject());
+    __ ldr(r0, GlobalObjectOperand());
     __ mov(r2, Operand(proxy->name()));
     Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
     // Use a regular load, not a contextual load, to avoid a reference
index a09afdf754ecab1f9e311b1b750b8eaf5fa438f2..4c1f9835f4d4a34829051a50e8a8cafecdc90c5d 100644 (file)
@@ -1988,9 +1988,9 @@ void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,
 
       // Not infinity or NaN simply convert to int.
       if (IsElementTypeSigned(array_type)) {
-        __ vcvt_s32_f64(s0, d0, ne);
+        __ vcvt_s32_f64(s0, d0, Assembler::RoundToZero, ne);
       } else {
-        __ vcvt_u32_f64(s0, d0, ne);
+        __ vcvt_u32_f64(s0, d0, Assembler::RoundToZero, ne);
       }
       __ vmov(r5, s0, ne);
 
index 7f6090bc50f8d4e82ab96c13f01fd695b2e964fa..d2c22af53df78b9cf0ed7c187cd40866716813c7 100644 (file)
@@ -129,7 +129,7 @@ void MacroAssembler::Call(intptr_t target, RelocInfo::Mode rmode,
     // address is loaded. The mov method will automatically record
     // positions when pc is the target, since this is not the case here
     // we have to do it explicitly.
-    WriteRecordedPositions();
+    positions_recorder()->WriteRecordedPositions();
 
     mov(ip, Operand(target, rmode), LeaveCC, cond);
     blx(ip, cond);
@@ -220,20 +220,20 @@ void MacroAssembler::Move(Register dst, Register src) {
 
 void MacroAssembler::And(Register dst, Register src1, const Operand& src2,
                          Condition cond) {
-  if (!CpuFeatures::IsSupported(ARMv7) || src2.is_single_instruction()) {
-    and_(dst, src1, src2, LeaveCC, cond);
-    return;
-  }
-  int32_t immediate = src2.immediate();
-  if (immediate == 0) {
+  if (!src2.is_reg() &&
+      !src2.must_use_constant_pool() &&
+      src2.immediate() == 0) {
     mov(dst, Operand(0, RelocInfo::NONE), LeaveCC, cond);
-    return;
-  }
-  if (IsPowerOf2(immediate + 1) && ((immediate & 1) != 0)) {
-    ubfx(dst, src1, 0, WhichPowerOf2(immediate + 1), cond);
-    return;
+
+  } else if (!src2.is_single_instruction() &&
+             !src2.must_use_constant_pool() &&
+             CpuFeatures::IsSupported(ARMv7) &&
+             IsPowerOf2(src2.immediate() + 1)) {
+    ubfx(dst, src1, 0, WhichPowerOf2(src2.immediate() + 1), cond);
+
+  } else {
+    and_(dst, src1, src2, LeaveCC, cond);
   }
-  and_(dst, src1, src2, LeaveCC, cond);
 }
 
 
index 48a805996697da3f04a354f8d2f10000becccb0f..8d89d6984ce5fd3079c7cb2d59b1f0ac6d3dd057 100644 (file)
@@ -727,6 +727,16 @@ class CodePatcher {
 // -----------------------------------------------------------------------------
 // Static helper functions.
 
+static MemOperand ContextOperand(Register context, int index) {
+  return MemOperand(context, Context::SlotOffset(index));
+}
+
+
+static inline MemOperand GlobalObjectOperand()  {
+  return ContextOperand(cp, Context::GLOBAL_INDEX);
+}
+
+
 #ifdef GENERATED_CODE_COVERAGE
 #define CODE_COVERAGE_STRINGIFY(x) #x
 #define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
index cb91520f3a5ac67b811b1918cb922811c0b7e4e2..3ec5f449d8ab5a4e4faac0c910fe87be7669ab94 100644 (file)
@@ -705,6 +705,7 @@ Simulator::Simulator() {
   z_flag_FPSCR_ = false;
   c_flag_FPSCR_ = false;
   v_flag_FPSCR_ = false;
+  FPSCR_rounding_mode_ = RZ;
 
   inv_op_vfp_flag_ = false;
   div_zero_vfp_flag_ = false;
@@ -2501,10 +2502,45 @@ void Simulator::DecodeTypeVFP(Instr* instr) {
                (instr->VAField() == 0x7) &&
                (instr->Bits(19, 16) == 0x1)) {
       // vmrs
-      if (instr->RtField() == 0xF)
+      uint32_t rt = instr->RtField();
+      if (rt == 0xF) {
         Copy_FPSCR_to_APSR();
-      else
-        UNIMPLEMENTED();  // Not used by V8.
+      } else {
+        // Emulate FPSCR from the Simulator flags.
+        uint32_t fpscr = (n_flag_FPSCR_ << 31) |
+                         (z_flag_FPSCR_ << 30) |
+                         (c_flag_FPSCR_ << 29) |
+                         (v_flag_FPSCR_ << 28) |
+                         (inexact_vfp_flag_ << 4) |
+                         (underflow_vfp_flag_ << 3) |
+                         (overflow_vfp_flag_ << 2) |
+                         (div_zero_vfp_flag_ << 1) |
+                         (inv_op_vfp_flag_ << 0) |
+                         (FPSCR_rounding_mode_ << 22);
+        set_register(rt, fpscr);
+      }
+    } else if ((instr->VLField() == 0x0) &&
+               (instr->VCField() == 0x0) &&
+               (instr->VAField() == 0x7) &&
+               (instr->Bits(19, 16) == 0x1)) {
+      // vmsr
+      uint32_t rt = instr->RtField();
+      if (rt == pc) {
+        UNREACHABLE();
+      } else {
+        uint32_t rt_value = get_register(rt);
+        n_flag_FPSCR_ = (rt_value >> 31) & 1;
+        z_flag_FPSCR_ = (rt_value >> 30) & 1;
+        c_flag_FPSCR_ = (rt_value >> 29) & 1;
+        v_flag_FPSCR_ = (rt_value >> 28) & 1;
+        inexact_vfp_flag_ = (rt_value >> 4) & 1;
+        underflow_vfp_flag_ = (rt_value >> 3) & 1;
+        overflow_vfp_flag_ = (rt_value >> 2) & 1;
+        div_zero_vfp_flag_ = (rt_value >> 1) & 1;
+        inv_op_vfp_flag_ = (rt_value >> 0) & 1;
+        FPSCR_rounding_mode_ =
+          static_cast<FPSCRRoundingModes>((rt_value >> 22) & 3);
+      }
     } else {
       UNIMPLEMENTED();  // Not used by V8.
     }
@@ -2605,29 +2641,71 @@ void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr) {
 
   if (to_integer) {
     bool unsigned_integer = (instr->Bit(16) == 0);
+    FPSCRRoundingModes mode;
     if (instr->Bit(7) != 1) {
-      // Only rounding towards zero supported.
-      UNIMPLEMENTED();  // Not used by V8.
+      // Use FPSCR defined rounding mode.
+      mode = FPSCR_rounding_mode_;
+      // Only RZ and RM modes are supported.
+      ASSERT((mode == RM) || (mode == RZ));
+    } else {
+      // VFP uses round towards zero by default.
+      mode = RZ;
     }
 
     int dst = instr->VFPDRegCode(kSinglePrecision);
     int src = instr->VFPMRegCode(src_precision);
+    int32_t kMaxInt = v8::internal::kMaxInt;
+    int32_t kMinInt = v8::internal::kMinInt;
+    switch (mode) {
+      case RM:
+        if (src_precision == kDoublePrecision) {
+          double val = get_double_from_d_register(src);
 
-    if (src_precision == kDoublePrecision) {
-      double val = get_double_from_d_register(src);
+          inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val);
 
-      int sint = unsigned_integer ? static_cast<uint32_t>(val) :
-                                    static_cast<int32_t>(val);
+          int sint = unsigned_integer ? static_cast<uint32_t>(val) :
+                                        static_cast<int32_t>(val);
+          sint = sint > val ? sint - 1 : sint;
 
-      set_s_register_from_sinteger(dst, sint);
-    } else {
-      float val = get_float_from_s_register(src);
+          set_s_register_from_sinteger(dst, sint);
+        } else {
+          float val = get_float_from_s_register(src);
+
+          inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val);
 
-      int sint = unsigned_integer ? static_cast<uint32_t>(val) :
-                                      static_cast<int32_t>(val);
+          int sint = unsigned_integer ? static_cast<uint32_t>(val) :
+                                        static_cast<int32_t>(val);
+          sint = sint > val ? sint - 1 : sint;
 
-      set_s_register_from_sinteger(dst, sint);
+          set_s_register_from_sinteger(dst, sint);
+        }
+        break;
+      case RZ:
+        if (src_precision == kDoublePrecision) {
+          double val = get_double_from_d_register(src);
+
+          inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val);
+
+          int sint = unsigned_integer ? static_cast<uint32_t>(val) :
+                                        static_cast<int32_t>(val);
+
+          set_s_register_from_sinteger(dst, sint);
+        } else {
+          float val = get_float_from_s_register(src);
+
+          inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val);
+
+          int sint = unsigned_integer ? static_cast<uint32_t>(val) :
+                                        static_cast<int32_t>(val);
+
+          set_s_register_from_sinteger(dst, sint);
+        }
+        break;
+
+      default:
+        UNREACHABLE();
     }
+
   } else {
     bool unsigned_integer = (instr->Bit(7) == 0);
 
index 3e023489eefa4a02713012fa851ec3e3ba808c93..c37b3f7156d157a8b3a734e6b0cf2163109bbd4a 100644 (file)
@@ -306,6 +306,9 @@ class Simulator {
   bool c_flag_FPSCR_;
   bool v_flag_FPSCR_;
 
+  // VFP rounding mode. See ARM DDI 0406B Page A2-29.
+  FPSCRRoundingModes FPSCR_rounding_mode_;
+
   // VFP FP exception flags architecture state.
   bool inv_op_vfp_flag_;
   bool div_zero_vfp_flag_;
index 5e29c2e48501ed448ba78a305c22c1d669764f5e..a0ef80a0fdeda56c0af5cd28cb9376331bb27721 100644 (file)
@@ -1676,8 +1676,143 @@ MaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object,
                                                     JSGlobalPropertyCell* cell,
                                                     JSFunction* function,
                                                     String* name) {
-  // TODO(872): implement this.
-  return Heap::undefined_value();
+  // ----------- S t a t e -------------
+  //  -- r2                     : function name
+  //  -- lr                     : return address
+  //  -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
+  //  -- ...
+  //  -- sp[argc * 4]           : receiver
+  // -----------------------------------
+
+  if (!CpuFeatures::IsSupported(VFP3)) return Heap::undefined_value();
+  CpuFeatures::Scope scope_vfp3(VFP3);
+
+  const int argc = arguments().immediate();
+
+  // If the object is not a JSObject or we got an unexpected number of
+  // arguments, bail out to the regular call.
+  if (!object->IsJSObject() || argc != 1) return Heap::undefined_value();
+
+  Label miss, slow;
+  GenerateNameCheck(name, &miss);
+
+  if (cell == NULL) {
+    __ ldr(r1, MemOperand(sp, 1 * kPointerSize));
+
+    STATIC_ASSERT(kSmiTag == 0);
+    __ BranchOnSmi(r1, &miss);
+
+    CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, r4, name,
+                    &miss);
+  } else {
+    ASSERT(cell->value() == function);
+    GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
+    GenerateLoadFunctionFromCell(cell, function, &miss);
+  }
+
+  // Load the (only) argument into r0.
+  __ ldr(r0, MemOperand(sp, 0 * kPointerSize));
+
+  // If the argument is a smi, just return.
+  STATIC_ASSERT(kSmiTag == 0);
+  __ tst(r0, Operand(kSmiTagMask));
+  __ Drop(argc + 1, eq);
+  __ Ret(eq);
+
+  __ CheckMap(r0, r1, Heap::kHeapNumberMapRootIndex, &slow, true);
+
+  Label wont_fit_smi, no_vfp_exception, restore_fpscr_and_return;
+
+  // If vfp3 is enabled, we use the fpu rounding with the RM (round towards
+  // minus infinity) mode.
+
+  // Load the HeapNumber value.
+  // We will need access to the value in the core registers, so we load it
+  // with ldrd and move it to the fpu. It also spares a sub instruction for
+  // updating the HeapNumber value address, as vldr expects a multiple
+  // of 4 offset.
+  __ Ldrd(r4, r5, FieldMemOperand(r0, HeapNumber::kValueOffset));
+  __ vmov(d1, r4, r5);
+
+  // Backup FPSCR.
+  __ vmrs(r3);
+  // Set custom FPCSR:
+  //  - Set rounding mode to "Round towards Minus Infinity"
+  //    (ie bits [23:22] = 0b10).
+  //  - Clear vfp cumulative exception flags (bits [3:0]).
+  //  - Make sure Flush-to-zero mode control bit is unset (bit 22).
+  __ bic(r9, r3,
+      Operand(kVFPExceptionMask | kVFPRoundingModeMask | kVFPFlushToZeroMask));
+  __ orr(r9, r9, Operand(kVFPRoundToMinusInfinityBits));
+  __ vmsr(r9);
+
+  // Convert the argument to an integer.
+  __ vcvt_s32_f64(s0, d1, Assembler::FPSCRRounding, al);
+
+  // Use vcvt latency to start checking for special cases.
+  // Get the argument exponent and clear the sign bit.
+  __ bic(r6, r5, Operand(HeapNumber::kSignMask));
+  __ mov(r6, Operand(r6, LSR, HeapNumber::kMantissaBitsInTopWord));
+
+  // Retrieve FPSCR and check for vfp exceptions.
+  __ vmrs(r9);
+  __ tst(r9, Operand(kVFPExceptionMask));
+  __ b(&no_vfp_exception, eq);
+
+  // Check for NaN, Infinity, and -Infinity.
+  // They are invariant through a Math.Floor call, so just
+  // return the original argument.
+  __ sub(r7, r6, Operand(HeapNumber::kExponentMask
+        >> HeapNumber::kMantissaBitsInTopWord), SetCC);
+  __ b(&restore_fpscr_and_return, eq);
+  // We had an overflow or underflow in the conversion. Check if we
+  // have a big exponent.
+  __ cmp(r7, Operand(HeapNumber::kMantissaBits));
+  // If greater or equal, the argument is already round and in r0.
+  __ b(&restore_fpscr_and_return, ge);
+  __ b(&slow);
+
+  __ bind(&no_vfp_exception);
+  // Move the result back to general purpose register r0.
+  __ vmov(r0, s0);
+  // Check if the result fits into a smi.
+  __ add(r1, r0, Operand(0x40000000), SetCC);
+  __ b(&wont_fit_smi, mi);
+  // Tag the result.
+  STATIC_ASSERT(kSmiTag == 0);
+  __ mov(r0, Operand(r0, LSL, kSmiTagSize));
+
+  // Check for -0.
+  __ cmp(r0, Operand(0));
+  __ b(&restore_fpscr_and_return, ne);
+  // r5 already holds the HeapNumber exponent.
+  __ tst(r5, Operand(HeapNumber::kSignMask));
+  // If our HeapNumber is negative it was -0, so load its address and return.
+  // Else r0 is loaded with 0, so we can also just return.
+  __ ldr(r0, MemOperand(sp, 0 * kPointerSize), ne);
+
+  __ bind(&restore_fpscr_and_return);
+  // Restore FPSCR and return.
+  __ vmsr(r3);
+  __ Drop(argc + 1);
+  __ Ret();
+
+  __ bind(&wont_fit_smi);
+  __ bind(&slow);
+  // Restore FPCSR and fall to slow case.
+  __ vmsr(r3);
+
+  // Tail call the full function. We do not have to patch the receiver
+  // because the function makes no use of it.
+  __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
+
+  __ bind(&miss);
+  // r2: function name.
+  MaybeObject* obj = GenerateMissBranch();
+  if (obj->IsFailure()) return obj;
+
+  // Return the generated code.
+  return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
 }
 
 
index da76edf39194166377e3790458eda4e9cbb8e497..45f48767c4da43089f55e2dec7f014e2a8a83cfa 100644 (file)
@@ -245,18 +245,15 @@ void VirtualFrame::AllocateStackSlots() {
     __ LoadRoot(r2, Heap::kStackLimitRootIndex);
   }
   // Check the stack for overflow or a break request.
-  // Put the lr setup instruction in the delay slot.  The kInstrSize is added
-  // to the implicit 8 byte offset that always applies to operations with pc
-  // and gives a return address 12 bytes down.
-  masm()->add(lr, pc, Operand(Assembler::kInstrSize));
   masm()->cmp(sp, Operand(r2));
   StackCheckStub stub;
   // Call the stub if lower.
-  masm()->mov(pc,
+  masm()->mov(ip,
               Operand(reinterpret_cast<intptr_t>(stub.GetCode().location()),
                       RelocInfo::CODE_TARGET),
               LeaveCC,
               lo);
+  masm()->Call(ip, lo);
 }
 
 
index ce90dceacbc9f8b0e3651efd5fb4f18f50cc6d24..7493673e8191f68e74fcbb6b465591897d832b3b 100644 (file)
@@ -804,4 +804,53 @@ ExternalReference ExternalReference::debug_step_in_fp_address() {
 }
 #endif
 
+
+void PositionsRecorder::RecordPosition(int pos,
+                                       PositionRecordingType recording_type) {
+  ASSERT(pos != RelocInfo::kNoPosition);
+  ASSERT(pos >= 0);
+  current_position_ = pos;
+  current_position_recording_type_ = recording_type;
+}
+
+
+void PositionsRecorder::RecordStatementPosition(int pos) {
+  ASSERT(pos != RelocInfo::kNoPosition);
+  ASSERT(pos >= 0);
+  current_statement_position_ = pos;
+}
+
+
+bool PositionsRecorder::WriteRecordedPositions() {
+  bool written = false;
+
+  // Write the statement position if it is different from what was written last
+  // time.
+  if (current_statement_position_ != written_statement_position_) {
+    EnsureSpace ensure_space(assembler_);
+    assembler_->RecordRelocInfo(RelocInfo::STATEMENT_POSITION,
+                                current_statement_position_);
+    written_statement_position_ = current_statement_position_;
+    written = true;
+  }
+
+  // Write the position if it is different from what was written last time and
+  // also different from the written statement position or was forced.
+  if (current_position_ != written_position_ &&
+      (current_position_ != current_statement_position_ || !written) &&
+      (current_position_ != written_statement_position_
+       || current_position_recording_type_ == FORCED_POSITION)) {
+    EnsureSpace ensure_space(assembler_);
+    assembler_->RecordRelocInfo(RelocInfo::POSITION, current_position_);
+    written_position_ = current_position_;
+    written = true;
+  }
+
+  current_position_recording_type_ = NORMAL_POSITION;
+
+  // Return whether something was written.
+  return written;
+}
+
+
 } }  // namespace v8::internal
index 66811777fad6a93e98239c3172e462aea33e0e79..09159fed08ee7babde1bfd27d51af5ee117209c5 100644 (file)
@@ -584,6 +584,67 @@ class ExternalReference BASE_EMBEDDED {
 };
 
 
+// -----------------------------------------------------------------------------
+// Position recording support
+
+enum PositionRecordingType { FORCED_POSITION, NORMAL_POSITION };
+
+class PositionsRecorder BASE_EMBEDDED {
+ public:
+  explicit PositionsRecorder(Assembler* assembler)
+      : assembler_(assembler),
+        current_position_(RelocInfo::kNoPosition),
+        current_position_recording_type_(NORMAL_POSITION),
+        written_position_(RelocInfo::kNoPosition),
+        current_statement_position_(RelocInfo::kNoPosition),
+        written_statement_position_(RelocInfo::kNoPosition) { }
+
+  // Set current position to pos. If recording_type is FORCED_POSITION then
+  // WriteRecordedPositions will write this position even if it is equal to
+  // statement position previously written for another pc.
+  void RecordPosition(int pos,
+                      PositionRecordingType recording_type = NORMAL_POSITION);
+
+  // Set current statement position to pos.
+  void RecordStatementPosition(int pos);
+
+  // Write recorded positions to relocation information.
+  bool WriteRecordedPositions();
+
+  int current_position() const { return current_position_; }
+
+  int current_statement_position() const { return current_statement_position_; }
+
+ private:
+  Assembler* assembler_;
+
+  int current_position_;
+  PositionRecordingType current_position_recording_type_;
+  int written_position_;
+
+  int current_statement_position_;
+  int written_statement_position_;
+};
+
+
+class PreserveStatementPositionScope BASE_EMBEDDED {
+ public:
+  explicit PreserveStatementPositionScope(PositionsRecorder* positions_recorder)
+      : positions_recorder_(positions_recorder),
+        statement_position_(positions_recorder->current_statement_position()) {}
+
+  ~PreserveStatementPositionScope() {
+    if (statement_position_ != RelocInfo::kNoPosition) {
+      positions_recorder_->RecordStatementPosition(statement_position_);
+    }
+  }
+
+ private:
+  PositionsRecorder* positions_recorder_;
+  int statement_position_;
+};
+
+
 // -----------------------------------------------------------------------------
 // Utility functions
 
diff --git a/deps/v8/src/bignum-dtoa.cc b/deps/v8/src/bignum-dtoa.cc
new file mode 100644 (file)
index 0000000..088dd79
--- /dev/null
@@ -0,0 +1,655 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <math.h>
+
+#include "v8.h"
+#include "bignum-dtoa.h"
+
+#include "bignum.h"
+#include "double.h"
+
+namespace v8 {
+namespace internal {
+
+static int NormalizedExponent(uint64_t significand, int exponent) {
+  ASSERT(significand != 0);
+  while ((significand & Double::kHiddenBit) == 0) {
+    significand = significand << 1;
+    exponent = exponent - 1;
+  }
+  return exponent;
+}
+
+
+// Forward declarations:
+// Returns an estimation of k such that 10^(k-1) <= v < 10^k.
+static int EstimatePower(int exponent);
+// Computes v / 10^estimated_power exactly, as a ratio of two bignums, numerator
+// and denominator.
+static void InitialScaledStartValues(double v,
+                                     int estimated_power,
+                                     bool need_boundary_deltas,
+                                     Bignum* numerator,
+                                     Bignum* denominator,
+                                     Bignum* delta_minus,
+                                     Bignum* delta_plus);
+// Multiplies numerator/denominator so that its values lies in the range 1-10.
+// Returns decimal_point s.t.
+//  v = numerator'/denominator' * 10^(decimal_point-1)
+//     where numerator' and denominator' are the values of numerator and
+//     denominator after the call to this function.
+static void FixupMultiply10(int estimated_power, bool is_even,
+                            int* decimal_point,
+                            Bignum* numerator, Bignum* denominator,
+                            Bignum* delta_minus, Bignum* delta_plus);
+// Generates digits from the left to the right and stops when the generated
+// digits yield the shortest decimal representation of v.
+static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator,
+                                   Bignum* delta_minus, Bignum* delta_plus,
+                                   bool is_even,
+                                   Vector<char> buffer, int* length);
+// Generates 'requested_digits' after the decimal point.
+static void BignumToFixed(int requested_digits, int* decimal_point,
+                          Bignum* numerator, Bignum* denominator,
+                          Vector<char>(buffer), int* length);
+// Generates 'count' digits of numerator/denominator.
+// Once 'count' digits have been produced rounds the result depending on the
+// remainder (remainders of exactly .5 round upwards). Might update the
+// decimal_point when rounding up (for example for 0.9999).
+static void GenerateCountedDigits(int count, int* decimal_point,
+                                  Bignum* numerator, Bignum* denominator,
+                                  Vector<char>(buffer), int* length);
+
+
+void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits,
+                Vector<char> buffer, int* length, int* decimal_point) {
+  ASSERT(v > 0);
+  ASSERT(!Double(v).IsSpecial());
+  uint64_t significand = Double(v).Significand();
+  bool is_even = (significand & 1) == 0;
+  int exponent = Double(v).Exponent();
+  int normalized_exponent = NormalizedExponent(significand, exponent);
+  // estimated_power might be too low by 1.
+  int estimated_power = EstimatePower(normalized_exponent);
+
+  // Shortcut for Fixed.
+  // The requested digits correspond to the digits after the point. If the
+  // number is much too small, then there is no need in trying to get any
+  // digits.
+  if (mode == BIGNUM_DTOA_FIXED && -estimated_power - 1 > requested_digits) {
+    buffer[0] = '\0';
+    *length = 0;
+    // Set decimal-point to -requested_digits. This is what Gay does.
+    // Note that it should not have any effect anyways since the string is
+    // empty.
+    *decimal_point = -requested_digits;
+    return;
+  }
+
+  Bignum numerator;
+  Bignum denominator;
+  Bignum delta_minus;
+  Bignum delta_plus;
+  // Make sure the bignum can grow large enough. The smallest double equals
+  // 4e-324. In this case the denominator needs fewer than 324*4 binary digits.
+  // The maximum double is 1.7976931348623157e308 which needs fewer than
+  // 308*4 binary digits.
+  ASSERT(Bignum::kMaxSignificantBits >= 324*4);
+  bool need_boundary_deltas = (mode == BIGNUM_DTOA_SHORTEST);
+  InitialScaledStartValues(v, estimated_power, need_boundary_deltas,
+                           &numerator, &denominator,
+                           &delta_minus, &delta_plus);
+  // We now have v = (numerator / denominator) * 10^estimated_power.
+  FixupMultiply10(estimated_power, is_even, decimal_point,
+                  &numerator, &denominator,
+                  &delta_minus, &delta_plus);
+  // We now have v = (numerator / denominator) * 10^(decimal_point-1), and
+  //  1 <= (numerator + delta_plus) / denominator < 10
+  switch (mode) {
+    case BIGNUM_DTOA_SHORTEST:
+      GenerateShortestDigits(&numerator, &denominator,
+                             &delta_minus, &delta_plus,
+                             is_even, buffer, length);
+      break;
+    case BIGNUM_DTOA_FIXED:
+      BignumToFixed(requested_digits, decimal_point,
+                    &numerator, &denominator,
+                    buffer, length);
+      break;
+    case BIGNUM_DTOA_PRECISION:
+      GenerateCountedDigits(requested_digits, decimal_point,
+                            &numerator, &denominator,
+                            buffer, length);
+      break;
+    default:
+      UNREACHABLE();
+  }
+  buffer[*length] = '\0';
+}
+
+
+// The procedure starts generating digits from the left to the right and stops
+// when the generated digits yield the shortest decimal representation of v. A
+// decimal representation of v is a number lying closer to v than to any other
+// double, so it converts to v when read.
+//
+// This is true if d, the decimal representation, is between m- and m+, the
+// upper and lower boundaries. d must be strictly between them if !is_even.
+//           m- := (numerator - delta_minus) / denominator
+//           m+ := (numerator + delta_plus) / denominator
+//
+// Precondition: 0 <= (numerator+delta_plus) / denominator < 10.
+//   If 1 <= (numerator+delta_plus) / denominator < 10 then no leading 0 digit
+//   will be produced. This should be the standard precondition.
+static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator,
+                                   Bignum* delta_minus, Bignum* delta_plus,
+                                   bool is_even,
+                                   Vector<char> buffer, int* length) {
+  // Small optimization: if delta_minus and delta_plus are the same just reuse
+  // one of the two bignums.
+  if (Bignum::Equal(*delta_minus, *delta_plus)) {
+    delta_plus = delta_minus;
+  }
+  *length = 0;
+  while (true) {
+    uint16_t digit;
+    digit = numerator->DivideModuloIntBignum(*denominator);
+    ASSERT(digit <= 9);  // digit is a uint16_t and therefore always positive.
+    // digit = numerator / denominator (integer division).
+    // numerator = numerator % denominator.
+    buffer[(*length)++] = digit + '0';
+
+    // Can we stop already?
+    // If the remainder of the division is less than the distance to the lower
+    // boundary we can stop. In this case we simply round down (discarding the
+    // remainder).
+    // Similarly we test if we can round up (using the upper boundary).
+    bool in_delta_room_minus;
+    bool in_delta_room_plus;
+    if (is_even) {
+      in_delta_room_minus = Bignum::LessEqual(*numerator, *delta_minus);
+    } else {
+      in_delta_room_minus = Bignum::Less(*numerator, *delta_minus);
+    }
+    if (is_even) {
+      in_delta_room_plus =
+          Bignum::PlusCompare(*numerator, *delta_plus, *denominator) >= 0;
+    } else {
+      in_delta_room_plus =
+          Bignum::PlusCompare(*numerator, *delta_plus, *denominator) > 0;
+    }
+    if (!in_delta_room_minus && !in_delta_room_plus) {
+      // Prepare for next iteration.
+      numerator->Times10();
+      delta_minus->Times10();
+      // We optimized delta_plus to be equal to delta_minus (if they share the
+      // same value). So don't multiply delta_plus if they point to the same
+      // object.
+      if (delta_minus != delta_plus) {
+        delta_plus->Times10();
+      }
+    } else if (in_delta_room_minus && in_delta_room_plus) {
+      // Let's see if 2*numerator < denominator.
+      // If yes, then the next digit would be < 5 and we can round down.
+      int compare = Bignum::PlusCompare(*numerator, *numerator, *denominator);
+      if (compare < 0) {
+        // Remaining digits are less than .5. -> Round down (== do nothing).
+      } else if (compare > 0) {
+        // Remaining digits are more than .5 of denominator. -> Round up.
+        // Note that the last digit could not be a '9' as otherwise the whole
+        // loop would have stopped earlier.
+        // We still have an assert here in case the preconditions were not
+        // satisfied.
+        ASSERT(buffer[(*length) - 1] != '9');
+        buffer[(*length) - 1]++;
+      } else {
+        // Halfway case.
+        // TODO(floitsch): need a way to solve half-way cases.
+        //   For now let's round towards even (since this is what Gay seems to
+        //   do).
+
+        if ((buffer[(*length) - 1] - '0') % 2 == 0) {
+          // Round down => Do nothing.
+        } else {
+          ASSERT(buffer[(*length) - 1] != '9');
+          buffer[(*length) - 1]++;
+        }
+      }
+      return;
+    } else if (in_delta_room_minus) {
+      // Round down (== do nothing).
+      return;
+    } else {  // in_delta_room_plus
+      // Round up.
+      // Note again that the last digit could not be '9' since this would have
+      // stopped the loop earlier.
+      // We still have an ASSERT here, in case the preconditions were not
+      // satisfied.
+      ASSERT(buffer[(*length) -1] != '9');
+      buffer[(*length) - 1]++;
+      return;
+    }
+  }
+}
+
+
+// Let v = numerator / denominator < 10.
+// Then we generate 'count' digits of d = x.xxxxx... (without the decimal point)
+// from left to right. Once 'count' digits have been produced we decide wether
+// to round up or down. Remainders of exactly .5 round upwards. Numbers such
+// as 9.999999 propagate a carry all the way, and change the
+// exponent (decimal_point), when rounding upwards.
+static void GenerateCountedDigits(int count, int* decimal_point,
+                                  Bignum* numerator, Bignum* denominator,
+                                  Vector<char>(buffer), int* length) {
+  ASSERT(count >= 0);
+  for (int i = 0; i < count - 1; ++i) {
+    uint16_t digit;
+    digit = numerator->DivideModuloIntBignum(*denominator);
+    ASSERT(digit <= 9);  // digit is a uint16_t and therefore always positive.
+    // digit = numerator / denominator (integer division).
+    // numerator = numerator % denominator.
+    buffer[i] = digit + '0';
+    // Prepare for next iteration.
+    numerator->Times10();
+  }
+  // Generate the last digit.
+  uint16_t digit;
+  digit = numerator->DivideModuloIntBignum(*denominator);
+  if (Bignum::PlusCompare(*numerator, *numerator, *denominator) >= 0) {
+    digit++;
+  }
+  buffer[count - 1] = digit + '0';
+  // Correct bad digits (in case we had a sequence of '9's). Propagate the
+  // carry until we hat a non-'9' or til we reach the first digit.
+  for (int i = count - 1; i > 0; --i) {
+    if (buffer[i] != '0' + 10) break;
+    buffer[i] = '0';
+    buffer[i - 1]++;
+  }
+  if (buffer[0] == '0' + 10) {
+    // Propagate a carry past the top place.
+    buffer[0] = '1';
+    (*decimal_point)++;
+  }
+  *length = count;
+}
+
+
+// Generates 'requested_digits' after the decimal point. It might omit
+// trailing '0's. If the input number is too small then no digits at all are
+// generated (ex.: 2 fixed digits for 0.00001).
+//
+// Input verifies:  1 <= (numerator + delta) / denominator < 10.
+static void BignumToFixed(int requested_digits, int* decimal_point,
+                          Bignum* numerator, Bignum* denominator,
+                          Vector<char>(buffer), int* length) {
+  // Note that we have to look at more than just the requested_digits, since
+  // a number could be rounded up. Example: v=0.5 with requested_digits=0.
+  // Even though the power of v equals 0 we can't just stop here.
+  if (-(*decimal_point) > requested_digits) {
+    // The number is definitively too small.
+    // Ex: 0.001 with requested_digits == 1.
+    // Set decimal-point to -requested_digits. This is what Gay does.
+    // Note that it should not have any effect anyways since the string is
+    // empty.
+    *decimal_point = -requested_digits;
+    *length = 0;
+    return;
+  } else if (-(*decimal_point) == requested_digits) {
+    // We only need to verify if the number rounds down or up.
+    // Ex: 0.04 and 0.06 with requested_digits == 1.
+    ASSERT(*decimal_point == -requested_digits);
+    // Initially the fraction lies in range (1, 10]. Multiply the denominator
+    // by 10 so that we can compare more easily.
+    denominator->Times10();
+    if (Bignum::PlusCompare(*numerator, *numerator, *denominator) >= 0) {
+      // If the fraction is >= 0.5 then we have to include the rounded
+      // digit.
+      buffer[0] = '1';
+      *length = 1;
+      (*decimal_point)++;
+    } else {
+      // Note that we caught most of similar cases earlier.
+      *length = 0;
+    }
+    return;
+  } else {
+    // The requested digits correspond to the digits after the point.
+    // The variable 'needed_digits' includes the digits before the point.
+    int needed_digits = (*decimal_point) + requested_digits;
+    GenerateCountedDigits(needed_digits, decimal_point,
+                          numerator, denominator,
+                          buffer, length);
+  }
+}
+
+
+// Returns an estimation of k such that 10^(k-1) <= v < 10^k where
+// v = f * 2^exponent and 2^52 <= f < 2^53.
+// v is hence a normalized double with the given exponent. The output is an
+// approximation for the exponent of the decimal approimation .digits * 10^k.
+//
+// The result might undershoot by 1 in which case 10^k <= v < 10^k+1.
+// Note: this property holds for v's upper boundary m+ too.
+//    10^k <= m+ < 10^k+1.
+//   (see explanation below).
+//
+// Examples:
+//  EstimatePower(0)   => 16
+//  EstimatePower(-52) => 0
+//
+// Note: e >= 0 => EstimatedPower(e) > 0. No similar claim can be made for e<0.
+static int EstimatePower(int exponent) {
+  // This function estimates log10 of v where v = f*2^e (with e == exponent).
+  // Note that 10^floor(log10(v)) <= v, but v <= 10^ceil(log10(v)).
+  // Note that f is bounded by its container size. Let p = 53 (the double's
+  // significand size). Then 2^(p-1) <= f < 2^p.
+  //
+  // Given that log10(v) == log2(v)/log2(10) and e+(len(f)-1) is quite close
+  // to log2(v) the function is simplified to (e+(len(f)-1)/log2(10)).
+  // The computed number undershoots by less than 0.631 (when we compute log3
+  // and not log10).
+  //
+  // Optimization: since we only need an approximated result this computation
+  // can be performed on 64 bit integers. On x86/x64 architecture the speedup is
+  // not really measurable, though.
+  //
+  // Since we want to avoid overshooting we decrement by 1e10 so that
+  // floating-point imprecisions don't affect us.
+  //
+  // Explanation for v's boundary m+: the computation takes advantage of
+  // the fact that 2^(p-1) <= f < 2^p. Boundaries still satisfy this requirement
+  // (even for denormals where the delta can be much more important).
+
+  const double k1Log10 = 0.30102999566398114;  // 1/lg(10)
+
+  // For doubles len(f) == 53 (don't forget the hidden bit).
+  const int kSignificandSize = 53;
+  double estimate = ceil((exponent + kSignificandSize - 1) * k1Log10 - 1e-10);
+  return static_cast<int>(estimate);
+}
+
+
+// See comments for InitialScaledStartValues.
+static void InitialScaledStartValuesPositiveExponent(
+    double v, int estimated_power, bool need_boundary_deltas,
+    Bignum* numerator, Bignum* denominator,
+    Bignum* delta_minus, Bignum* delta_plus) {
+  // A positive exponent implies a positive power.
+  ASSERT(estimated_power >= 0);
+  // Since the estimated_power is positive we simply multiply the denominator
+  // by 10^estimated_power.
+
+  // numerator = v.
+  numerator->AssignUInt64(Double(v).Significand());
+  numerator->ShiftLeft(Double(v).Exponent());
+  // denominator = 10^estimated_power.
+  denominator->AssignPowerUInt16(10, estimated_power);
+
+  if (need_boundary_deltas) {
+    // Introduce a common denominator so that the deltas to the boundaries are
+    // integers.
+    denominator->ShiftLeft(1);
+    numerator->ShiftLeft(1);
+    // Let v = f * 2^e, then m+ - v = 1/2 * 2^e; With the common
+    // denominator (of 2) delta_plus equals 2^e.
+    delta_plus->AssignUInt16(1);
+    delta_plus->ShiftLeft(Double(v).Exponent());
+    // Same for delta_minus (with adjustments below if f == 2^p-1).
+    delta_minus->AssignUInt16(1);
+    delta_minus->ShiftLeft(Double(v).Exponent());
+
+    // If the significand (without the hidden bit) is 0, then the lower
+    // boundary is closer than just half a ulp (unit in the last place).
+    // There is only one exception: if the next lower number is a denormal then
+    // the distance is 1 ulp. This cannot be the case for exponent >= 0 (but we
+    // have to test it in the other function where exponent < 0).
+    uint64_t v_bits = Double(v).AsUint64();
+    if ((v_bits & Double::kSignificandMask) == 0) {
+      // The lower boundary is closer at half the distance of "normal" numbers.
+      // Increase the common denominator and adapt all but the delta_minus.
+      denominator->ShiftLeft(1);  // *2
+      numerator->ShiftLeft(1);    // *2
+      delta_plus->ShiftLeft(1);   // *2
+    }
+  }
+}
+
+
+// See comments for InitialScaledStartValues
+static void InitialScaledStartValuesNegativeExponentPositivePower(
+    double v, int estimated_power, bool need_boundary_deltas,
+    Bignum* numerator, Bignum* denominator,
+    Bignum* delta_minus, Bignum* delta_plus) {
+  uint64_t significand = Double(v).Significand();
+  int exponent = Double(v).Exponent();
+  // v = f * 2^e with e < 0, and with estimated_power >= 0.
+  // This means that e is close to 0 (have a look at how estimated_power is
+  // computed).
+
+  // numerator = significand
+  //  since v = significand * 2^exponent this is equivalent to
+  //  numerator = v * / 2^-exponent
+  numerator->AssignUInt64(significand);
+  // denominator = 10^estimated_power * 2^-exponent (with exponent < 0)
+  denominator->AssignPowerUInt16(10, estimated_power);
+  denominator->ShiftLeft(-exponent);
+
+  if (need_boundary_deltas) {
+    // Introduce a common denominator so that the deltas to the boundaries are
+    // integers.
+    denominator->ShiftLeft(1);
+    numerator->ShiftLeft(1);
+    // Let v = f * 2^e, then m+ - v = 1/2 * 2^e; With the common
+    // denominator (of 2) delta_plus equals 2^e.
+    // Given that the denominator already includes v's exponent the distance
+    // to the boundaries is simply 1.
+    delta_plus->AssignUInt16(1);
+    // Same for delta_minus (with adjustments below if f == 2^p-1).
+    delta_minus->AssignUInt16(1);
+
+    // If the significand (without the hidden bit) is 0, then the lower
+    // boundary is closer than just one ulp (unit in the last place).
+    // There is only one exception: if the next lower number is a denormal
+    // then the distance is 1 ulp. Since the exponent is close to zero
+    // (otherwise estimated_power would have been negative) this cannot happen
+    // here either.
+    uint64_t v_bits = Double(v).AsUint64();
+    if ((v_bits & Double::kSignificandMask) == 0) {
+      // The lower boundary is closer at half the distance of "normal" numbers.
+      // Increase the denominator and adapt all but the delta_minus.
+      denominator->ShiftLeft(1);  // *2
+      numerator->ShiftLeft(1);    // *2
+      delta_plus->ShiftLeft(1);   // *2
+    }
+  }
+}
+
+
+// See comments for InitialScaledStartValues
+static void InitialScaledStartValuesNegativeExponentNegativePower(
+    double v, int estimated_power, bool need_boundary_deltas,
+    Bignum* numerator, Bignum* denominator,
+    Bignum* delta_minus, Bignum* delta_plus) {
+  const uint64_t kMinimalNormalizedExponent =
+      V8_2PART_UINT64_C(0x00100000, 00000000);
+  uint64_t significand = Double(v).Significand();
+  int exponent = Double(v).Exponent();
+  // Instead of multiplying the denominator with 10^estimated_power we
+  // multiply all values (numerator and deltas) by 10^-estimated_power.
+
+  // Use numerator as temporary container for power_ten.
+  Bignum* power_ten = numerator;
+  power_ten->AssignPowerUInt16(10, -estimated_power);
+
+  if (need_boundary_deltas) {
+    // Since power_ten == numerator we must make a copy of 10^estimated_power
+    // before we complete the computation of the numerator.
+    // delta_plus = delta_minus = 10^estimated_power
+    delta_plus->AssignBignum(*power_ten);
+    delta_minus->AssignBignum(*power_ten);
+  }
+
+  // numerator = significand * 2 * 10^-estimated_power
+  //  since v = significand * 2^exponent this is equivalent to
+  // numerator = v * 10^-estimated_power * 2 * 2^-exponent.
+  // Remember: numerator has been abused as power_ten. So no need to assign it
+  //  to itself.
+  ASSERT(numerator == power_ten);
+  numerator->MultiplyByUInt64(significand);
+
+  // denominator = 2 * 2^-exponent with exponent < 0.
+  denominator->AssignUInt16(1);
+  denominator->ShiftLeft(-exponent);
+
+  if (need_boundary_deltas) {
+    // Introduce a common denominator so that the deltas to the boundaries are
+    // integers.
+    numerator->ShiftLeft(1);
+    denominator->ShiftLeft(1);
+    // With this shift the boundaries have their correct value, since
+    // delta_plus = 10^-estimated_power, and
+    // delta_minus = 10^-estimated_power.
+    // These assignments have been done earlier.
+
+    // The special case where the lower boundary is twice as close.
+    // This time we have to look out for the exception too.
+    uint64_t v_bits = Double(v).AsUint64();
+    if ((v_bits & Double::kSignificandMask) == 0 &&
+        // The only exception where a significand == 0 has its boundaries at
+        // "normal" distances:
+        (v_bits & Double::kExponentMask) != kMinimalNormalizedExponent) {
+      numerator->ShiftLeft(1);    // *2
+      denominator->ShiftLeft(1);  // *2
+      delta_plus->ShiftLeft(1);   // *2
+    }
+  }
+}
+
+
+// Let v = significand * 2^exponent.
+// Computes v / 10^estimated_power exactly, as a ratio of two bignums, numerator
+// and denominator. The functions GenerateShortestDigits and
+// GenerateCountedDigits will then convert this ratio to its decimal
+// representation d, with the required accuracy.
+// Then d * 10^estimated_power is the representation of v.
+// (Note: the fraction and the estimated_power might get adjusted before
+// generating the decimal representation.)
+//
+// The initial start values consist of:
+//  - a scaled numerator: s.t. numerator/denominator == v / 10^estimated_power.
+//  - a scaled (common) denominator.
+//  optionally (used by GenerateShortestDigits to decide if it has the shortest
+//  decimal converting back to v):
+//  - v - m-: the distance to the lower boundary.
+//  - m+ - v: the distance to the upper boundary.
+//
+// v, m+, m-, and therefore v - m- and m+ - v all share the same denominator.
+//
+// Let ep == estimated_power, then the returned values will satisfy:
+//  v / 10^ep = numerator / denominator.
+//  v's boundarys m- and m+:
+//    m- / 10^ep == v / 10^ep - delta_minus / denominator
+//    m+ / 10^ep == v / 10^ep + delta_plus / denominator
+//  Or in other words:
+//    m- == v - delta_minus * 10^ep / denominator;
+//    m+ == v + delta_plus * 10^ep / denominator;
+//
+// Since 10^(k-1) <= v < 10^k    (with k == estimated_power)
+//  or       10^k <= v < 10^(k+1)
+//  we then have 0.1 <= numerator/denominator < 1
+//           or    1 <= numerator/denominator < 10
+//
+// It is then easy to kickstart the digit-generation routine.
+//
+// The boundary-deltas are only filled if need_boundary_deltas is set.
+static void InitialScaledStartValues(double v,
+                                     int estimated_power,
+                                     bool need_boundary_deltas,
+                                     Bignum* numerator,
+                                     Bignum* denominator,
+                                     Bignum* delta_minus,
+                                     Bignum* delta_plus) {
+  if (Double(v).Exponent() >= 0) {
+    InitialScaledStartValuesPositiveExponent(
+        v, estimated_power, need_boundary_deltas,
+        numerator, denominator, delta_minus, delta_plus);
+  } else if (estimated_power >= 0) {
+    InitialScaledStartValuesNegativeExponentPositivePower(
+        v, estimated_power, need_boundary_deltas,
+        numerator, denominator, delta_minus, delta_plus);
+  } else {
+    InitialScaledStartValuesNegativeExponentNegativePower(
+        v, estimated_power, need_boundary_deltas,
+        numerator, denominator, delta_minus, delta_plus);
+  }
+}
+
+
+// This routine multiplies numerator/denominator so that its values lies in the
+// range 1-10. That is after a call to this function we have:
+//    1 <= (numerator + delta_plus) /denominator < 10.
+// Let numerator the input before modification and numerator' the argument
+// after modification, then the output-parameter decimal_point is such that
+//  numerator / denominator * 10^estimated_power ==
+//    numerator' / denominator' * 10^(decimal_point - 1)
+// In some cases estimated_power was too low, and this is already the case. We
+// then simply adjust the power so that 10^(k-1) <= v < 10^k (with k ==
+// estimated_power) but do not touch the numerator or denominator.
+// Otherwise the routine multiplies the numerator and the deltas by 10.
+static void FixupMultiply10(int estimated_power, bool is_even,
+                            int* decimal_point,
+                            Bignum* numerator, Bignum* denominator,
+                            Bignum* delta_minus, Bignum* delta_plus) {
+  bool in_range;
+  if (is_even) {
+    // For IEEE doubles half-way cases (in decimal system numbers ending with 5)
+    // are rounded to the closest floating-point number with even significand.
+    in_range = Bignum::PlusCompare(*numerator, *delta_plus, *denominator) >= 0;
+  } else {
+    in_range = Bignum::PlusCompare(*numerator, *delta_plus, *denominator) > 0;
+  }
+  if (in_range) {
+    // Since numerator + delta_plus >= denominator we already have
+    // 1 <= numerator/denominator < 10. Simply update the estimated_power.
+    *decimal_point = estimated_power + 1;
+  } else {
+    *decimal_point = estimated_power;
+    numerator->Times10();
+    if (Bignum::Equal(*delta_minus, *delta_plus)) {
+      delta_minus->Times10();
+      delta_plus->AssignBignum(*delta_minus);
+    } else {
+      delta_minus->Times10();
+      delta_plus->Times10();
+    }
+  }
+}
+
+} }  // namespace v8::internal
diff --git a/deps/v8/src/bignum-dtoa.h b/deps/v8/src/bignum-dtoa.h
new file mode 100644 (file)
index 0000000..ea1acbb
--- /dev/null
@@ -0,0 +1,81 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_BIGNUM_DTOA_H_
+#define V8_BIGNUM_DTOA_H_
+
+namespace v8 {
+namespace internal {
+
+enum BignumDtoaMode {
+  // Return the shortest correct representation.
+  // For example the output of 0.299999999999999988897 is (the less accurate but
+  // correct) 0.3.
+  BIGNUM_DTOA_SHORTEST,
+  // Return a fixed number of digits after the decimal point.
+  // For instance fixed(0.1, 4) becomes 0.1000
+  // If the input number is big, the output will be big.
+  BIGNUM_DTOA_FIXED,
+  // Return a fixed number of digits, no matter what the exponent is.
+  BIGNUM_DTOA_PRECISION
+};
+
+// Converts the given double 'v' to ascii.
+// The result should be interpreted as buffer * 10^(point-length).
+// The buffer will be null-terminated.
+//
+// The input v must be > 0 and different from NaN, and Infinity.
+//
+// The output depends on the given mode:
+//  - SHORTEST: produce the least amount of digits for which the internal
+//   identity requirement is still satisfied. If the digits are printed
+//   (together with the correct exponent) then reading this number will give
+//   'v' again. The buffer will choose the representation that is closest to
+//   'v'. If there are two at the same distance, than the number is round up.
+//   In this mode the 'requested_digits' parameter is ignored.
+//  - FIXED: produces digits necessary to print a given number with
+//   'requested_digits' digits after the decimal point. The produced digits
+//   might be too short in which case the caller has to fill the gaps with '0's.
+//   Example: toFixed(0.001, 5) is allowed to return buffer="1", point=-2.
+//   Halfway cases are rounded up. The call toFixed(0.15, 2) thus returns
+//     buffer="2", point=0.
+//   Note: the length of the returned buffer has no meaning wrt the significance
+//   of its digits. That is, just because it contains '0's does not mean that
+//   any other digit would not satisfy the internal identity requirement.
+//  - PRECISION: produces 'requested_digits' where the first digit is not '0'.
+//   Even though the length of produced digits usually equals
+//   'requested_digits', the function is allowed to return fewer digits, in
+//   which case the caller has to fill the missing digits with '0's.
+//   Halfway cases are again rounded up.
+// 'BignumDtoa' expects the given buffer to be big enough to hold all digits
+// and a terminating null-character.
+void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits,
+                Vector<char> buffer, int* length, int* point);
+
+} }  // namespace v8::internal
+
+#endif  // V8_BIGNUM_DTOA_H_
diff --git a/deps/v8/src/bignum.cc b/deps/v8/src/bignum.cc
new file mode 100644 (file)
index 0000000..dd1537a
--- /dev/null
@@ -0,0 +1,767 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "bignum.h"
+#include "utils.h"
+
+namespace v8 {
+namespace internal {
+
+Bignum::Bignum()
+    : bigits_(bigits_buffer_, kBigitCapacity), used_digits_(0), exponent_(0) {
+  for (int i = 0; i < kBigitCapacity; ++i) {
+    bigits_[i] = 0;
+  }
+}
+
+
+template<typename S>
+static int BitSize(S value) {
+  return 8 * sizeof(value);
+}
+
+// Guaranteed to lie in one Bigit.
+void Bignum::AssignUInt16(uint16_t value) {
+  ASSERT(kBigitSize >= BitSize(value));
+  Zero();
+  if (value == 0) return;
+
+  EnsureCapacity(1);
+  bigits_[0] = value;
+  used_digits_ = 1;
+}
+
+
+void Bignum::AssignUInt64(uint64_t value) {
+  const int kUInt64Size = 64;
+
+  Zero();
+  if (value == 0) return;
+
+  int needed_bigits = kUInt64Size / kBigitSize + 1;
+  EnsureCapacity(needed_bigits);
+  for (int i = 0; i < needed_bigits; ++i) {
+    bigits_[i] = value & kBigitMask;
+    value = value >> kBigitSize;
+  }
+  used_digits_ = needed_bigits;
+  Clamp();
+}
+
+
+void Bignum::AssignBignum(const Bignum& other) {
+  exponent_ = other.exponent_;
+  for (int i = 0; i < other.used_digits_; ++i) {
+    bigits_[i] = other.bigits_[i];
+  }
+  // Clear the excess digits (if there were any).
+  for (int i = other.used_digits_; i < used_digits_; ++i) {
+    bigits_[i] = 0;
+  }
+  used_digits_ = other.used_digits_;
+}
+
+
+static uint64_t ReadUInt64(Vector<const char> buffer,
+                           int from,
+                           int digits_to_read) {
+  uint64_t result = 0;
+  for (int i = from; i < from + digits_to_read; ++i) {
+    int digit = buffer[i] - '0';
+    ASSERT(0 <= digit && digit <= 9);
+    result = result * 10 + digit;
+  }
+  return result;
+}
+
+
+void Bignum::AssignDecimalString(Vector<const char> value) {
+  // 2^64 = 18446744073709551616 > 10^19
+  const int kMaxUint64DecimalDigits = 19;
+  Zero();
+  int length = value.length();
+  int pos = 0;
+  // Let's just say that each digit needs 4 bits.
+  while (length >= kMaxUint64DecimalDigits) {
+    uint64_t digits = ReadUInt64(value, pos, kMaxUint64DecimalDigits);
+    pos += kMaxUint64DecimalDigits;
+    length -= kMaxUint64DecimalDigits;
+    MultiplyByPowerOfTen(kMaxUint64DecimalDigits);
+    AddUInt64(digits);
+  }
+  uint64_t digits = ReadUInt64(value, pos, length);
+  MultiplyByPowerOfTen(length);
+  AddUInt64(digits);
+  Clamp();
+}
+
+
+static int HexCharValue(char c) {
+  if ('0' <= c && c <= '9') return c - '0';
+  if ('a' <= c && c <= 'f') return 10 + c - 'a';
+  if ('A' <= c && c <= 'F') return 10 + c - 'A';
+  UNREACHABLE();
+  return 0;  // To make compiler happy.
+}
+
+
+void Bignum::AssignHexString(Vector<const char> value) {
+  Zero();
+  int length = value.length();
+
+  int needed_bigits = length * 4 / kBigitSize + 1;
+  EnsureCapacity(needed_bigits);
+  int string_index = length - 1;
+  for (int i = 0; i < needed_bigits - 1; ++i) {
+    // These bigits are guaranteed to be "full".
+    Chunk current_bigit = 0;
+    for (int j = 0; j < kBigitSize / 4; j++) {
+      current_bigit += HexCharValue(value[string_index--]) << (j * 4);
+    }
+    bigits_[i] = current_bigit;
+  }
+  used_digits_ = needed_bigits - 1;
+
+  Chunk most_significant_bigit = 0;  // Could be = 0;
+  for (int j = 0; j <= string_index; ++j) {
+    most_significant_bigit <<= 4;
+    most_significant_bigit += HexCharValue(value[j]);
+  }
+  if (most_significant_bigit != 0) {
+    bigits_[used_digits_] = most_significant_bigit;
+    used_digits_++;
+  }
+  Clamp();
+}
+
+
+void Bignum::AddUInt64(uint64_t operand) {
+  if (operand == 0) return;
+  Bignum other;
+  other.AssignUInt64(operand);
+  AddBignum(other);
+}
+
+
+void Bignum::AddBignum(const Bignum& other) {
+  ASSERT(IsClamped());
+  ASSERT(other.IsClamped());
+
+  // If this has a greater exponent than other append zero-bigits to this.
+  // After this call exponent_ <= other.exponent_.
+  Align(other);
+
+  // There are two possibilities:
+  //   aaaaaaaaaaa 0000  (where the 0s represent a's exponent)
+  //     bbbbb 00000000
+  //   ----------------
+  //   ccccccccccc 0000
+  // or
+  //    aaaaaaaaaa 0000
+  //  bbbbbbbbb 0000000
+  //  -----------------
+  //  cccccccccccc 0000
+  // In both cases we might need a carry bigit.
+
+  EnsureCapacity(1 + Max(BigitLength(), other.BigitLength()) - exponent_);
+  Chunk carry = 0;
+  int bigit_pos = other.exponent_ - exponent_;
+  ASSERT(bigit_pos >= 0);
+  for (int i = 0; i < other.used_digits_; ++i) {
+    Chunk sum = bigits_[bigit_pos] + other.bigits_[i] + carry;
+    bigits_[bigit_pos] = sum & kBigitMask;
+    carry = sum >> kBigitSize;
+    bigit_pos++;
+  }
+
+  while (carry != 0) {
+    Chunk sum = bigits_[bigit_pos] + carry;
+    bigits_[bigit_pos] = sum & kBigitMask;
+    carry = sum >> kBigitSize;
+    bigit_pos++;
+  }
+  used_digits_ = Max(bigit_pos, used_digits_);
+  ASSERT(IsClamped());
+}
+
+
+void Bignum::SubtractBignum(const Bignum& other) {
+  ASSERT(IsClamped());
+  ASSERT(other.IsClamped());
+  // We require this to be bigger than other.
+  ASSERT(LessEqual(other, *this));
+
+  Align(other);
+
+  int offset = other.exponent_ - exponent_;
+  Chunk borrow = 0;
+  int i;
+  for (i = 0; i < other.used_digits_; ++i) {
+    ASSERT((borrow == 0) || (borrow == 1));
+    Chunk difference = bigits_[i + offset] - other.bigits_[i] - borrow;
+    bigits_[i + offset] = difference & kBigitMask;
+    borrow = difference >> (kChunkSize - 1);
+  }
+  while (borrow != 0) {
+    Chunk difference = bigits_[i + offset] - borrow;
+    bigits_[i + offset] = difference & kBigitMask;
+    borrow = difference >> (kChunkSize - 1);
+    ++i;
+  }
+  Clamp();
+}
+
+
+void Bignum::ShiftLeft(int shift_amount) {
+  if (used_digits_ == 0) return;
+  exponent_ += shift_amount / kBigitSize;
+  int local_shift = shift_amount % kBigitSize;
+  EnsureCapacity(used_digits_ + 1);
+  BigitsShiftLeft(local_shift);
+}
+
+
+void Bignum::MultiplyByUInt32(uint32_t factor) {
+  if (factor == 1) return;
+  if (factor == 0) {
+    Zero();
+    return;
+  }
+  if (used_digits_ == 0) return;
+
+  // The product of a bigit with the factor is of size kBigitSize + 32.
+  // Assert that this number + 1 (for the carry) fits into double chunk.
+  ASSERT(kDoubleChunkSize >= kBigitSize + 32 + 1);
+  DoubleChunk carry = 0;
+  for (int i = 0; i < used_digits_; ++i) {
+    DoubleChunk product = static_cast<DoubleChunk>(factor) * bigits_[i] + carry;
+    bigits_[i] = static_cast<Chunk>(product & kBigitMask);
+    carry = (product >> kBigitSize);
+  }
+  while (carry != 0) {
+    EnsureCapacity(used_digits_ + 1);
+    bigits_[used_digits_] = carry & kBigitMask;
+    used_digits_++;
+    carry >>= kBigitSize;
+  }
+}
+
+
+void Bignum::MultiplyByUInt64(uint64_t factor) {
+  if (factor == 1) return;
+  if (factor == 0) {
+    Zero();
+    return;
+  }
+  ASSERT(kBigitSize < 32);
+  uint64_t carry = 0;
+  uint64_t low = factor & 0xFFFFFFFF;
+  uint64_t high = factor >> 32;
+  for (int i = 0; i < used_digits_; ++i) {
+    uint64_t product_low = low * bigits_[i];
+    uint64_t product_high = high * bigits_[i];
+    uint64_t tmp = (carry & kBigitMask) + product_low;
+    bigits_[i] = tmp & kBigitMask;
+    carry = (carry >> kBigitSize) + (tmp >> kBigitSize) +
+        (product_high << (32 - kBigitSize));
+  }
+  while (carry != 0) {
+    EnsureCapacity(used_digits_ + 1);
+    bigits_[used_digits_] = carry & kBigitMask;
+    used_digits_++;
+    carry >>= kBigitSize;
+  }
+}
+
+
+void Bignum::MultiplyByPowerOfTen(int exponent) {
+  const uint64_t kFive27 = V8_2PART_UINT64_C(0x6765c793, fa10079d);
+  const uint16_t kFive1 = 5;
+  const uint16_t kFive2 = kFive1 * 5;
+  const uint16_t kFive3 = kFive2 * 5;
+  const uint16_t kFive4 = kFive3 * 5;
+  const uint16_t kFive5 = kFive4 * 5;
+  const uint16_t kFive6 = kFive5 * 5;
+  const uint32_t kFive7 = kFive6 * 5;
+  const uint32_t kFive8 = kFive7 * 5;
+  const uint32_t kFive9 = kFive8 * 5;
+  const uint32_t kFive10 = kFive9 * 5;
+  const uint32_t kFive11 = kFive10 * 5;
+  const uint32_t kFive12 = kFive11 * 5;
+  const uint32_t kFive13 = kFive12 * 5;
+  const uint32_t kFive1_to_12[] =
+      { kFive1, kFive2, kFive3, kFive4, kFive5, kFive6,
+        kFive7, kFive8, kFive9, kFive10, kFive11, kFive12 };
+
+  ASSERT(exponent >= 0);
+  if (exponent == 0) return;
+  if (used_digits_ == 0) return;
+
+  // We shift by exponent at the end just before returning.
+  int remaining_exponent = exponent;
+  while (remaining_exponent >= 27) {
+    MultiplyByUInt64(kFive27);
+    remaining_exponent -= 27;
+  }
+  while (remaining_exponent >= 13) {
+    MultiplyByUInt32(kFive13);
+    remaining_exponent -= 13;
+  }
+  if (remaining_exponent > 0) {
+    MultiplyByUInt32(kFive1_to_12[remaining_exponent - 1]);
+  }
+  ShiftLeft(exponent);
+}
+
+
+void Bignum::Square() {
+  ASSERT(IsClamped());
+  int product_length = 2 * used_digits_;
+  EnsureCapacity(product_length);
+
+  // Comba multiplication: compute each column separately.
+  // Example: r = a2a1a0 * b2b1b0.
+  //    r =  1    * a0b0 +
+  //        10    * (a1b0 + a0b1) +
+  //        100   * (a2b0 + a1b1 + a0b2) +
+  //        1000  * (a2b1 + a1b2) +
+  //        10000 * a2b2
+  //
+  // In the worst case we have to accumulate nb-digits products of digit*digit.
+  //
+  // Assert that the additional number of bits in a DoubleChunk are enough to
+  // sum up used_digits of Bigit*Bigit.
+  if ((1 << (2 * (kChunkSize - kBigitSize))) <= used_digits_) {
+    UNIMPLEMENTED();
+  }
+  DoubleChunk accumulator = 0;
+  // First shift the digits so we don't overwrite them.
+  int copy_offset = used_digits_;
+  for (int i = 0; i < used_digits_; ++i) {
+    bigits_[copy_offset + i] = bigits_[i];
+  }
+  // We have two loops to avoid some 'if's in the loop.
+  for (int i = 0; i < used_digits_; ++i) {
+    // Process temporary digit i with power i.
+    // The sum of the two indices must be equal to i.
+    int bigit_index1 = i;
+    int bigit_index2 = 0;
+    // Sum all of the sub-products.
+    while (bigit_index1 >= 0) {
+      Chunk chunk1 = bigits_[copy_offset + bigit_index1];
+      Chunk chunk2 = bigits_[copy_offset + bigit_index2];
+      accumulator += static_cast<DoubleChunk>(chunk1) * chunk2;
+      bigit_index1--;
+      bigit_index2++;
+    }
+    bigits_[i] = static_cast<Chunk>(accumulator) & kBigitMask;
+    accumulator >>= kBigitSize;
+  }
+  for (int i = used_digits_; i < product_length; ++i) {
+    int bigit_index1 = used_digits_ - 1;
+    int bigit_index2 = i - bigit_index1;
+    // Invariant: sum of both indices is again equal to i.
+    // Inner loop runs 0 times on last iteration, emptying accumulator.
+    while (bigit_index2 < used_digits_) {
+      Chunk chunk1 = bigits_[copy_offset + bigit_index1];
+      Chunk chunk2 = bigits_[copy_offset + bigit_index2];
+      accumulator += static_cast<DoubleChunk>(chunk1) * chunk2;
+      bigit_index1--;
+      bigit_index2++;
+    }
+    // The overwritten bigits_[i] will never be read in further loop iterations,
+    // because bigit_index1 and bigit_index2 are always greater
+    // than i - used_digits_.
+    bigits_[i] = static_cast<Chunk>(accumulator) & kBigitMask;
+    accumulator >>= kBigitSize;
+  }
+  // Since the result was guaranteed to lie inside the number the
+  // accumulator must be 0 now.
+  ASSERT(accumulator == 0);
+
+  // Don't forget to update the used_digits and the exponent.
+  used_digits_ = product_length;
+  exponent_ *= 2;
+  Clamp();
+}
+
+
+void Bignum::AssignPowerUInt16(uint16_t base, int power_exponent) {
+  ASSERT(base != 0);
+  ASSERT(power_exponent >= 0);
+  if (power_exponent == 0) {
+    AssignUInt16(1);
+    return;
+  }
+  Zero();
+  int shifts = 0;
+  // We expect base to be in range 2-32, and most often to be 10.
+  // It does not make much sense to implement different algorithms for counting
+  // the bits.
+  while ((base & 1) == 0) {
+    base >>= 1;
+    shifts++;
+  }
+  int bit_size = 0;
+  int tmp_base = base;
+  while (tmp_base != 0) {
+    tmp_base >>= 1;
+    bit_size++;
+  }
+  int final_size = bit_size * power_exponent;
+  // 1 extra bigit for the shifting, and one for rounded final_size.
+  EnsureCapacity(final_size / kBigitSize + 2);
+
+  // Left to Right exponentiation.
+  int mask = 1;
+  while (power_exponent >= mask) mask <<= 1;
+
+  // The mask is now pointing to the bit above the most significant 1-bit of
+  // power_exponent.
+  // Get rid of first 1-bit;
+  mask >>= 2;
+  uint64_t this_value = base;
+
+  bool delayed_multipliciation = false;
+  const uint64_t max_32bits = 0xFFFFFFFF;
+  while (mask != 0 && this_value <= max_32bits) {
+    this_value = this_value * this_value;
+    // Verify that there is enough space in this_value to perform the
+    // multiplication.  The first bit_size bits must be 0.
+    if ((power_exponent & mask) != 0) {
+      uint64_t base_bits_mask =
+          ~((static_cast<uint64_t>(1) << (64 - bit_size)) - 1);
+      bool high_bits_zero = (this_value & base_bits_mask) == 0;
+      if (high_bits_zero) {
+        this_value *= base;
+      } else {
+        delayed_multipliciation = true;
+      }
+    }
+    mask >>= 1;
+  }
+  AssignUInt64(this_value);
+  if (delayed_multipliciation) {
+    MultiplyByUInt32(base);
+  }
+
+  // Now do the same thing as a bignum.
+  while (mask != 0) {
+    Square();
+    if ((power_exponent & mask) != 0) {
+      MultiplyByUInt32(base);
+    }
+    mask >>= 1;
+  }
+
+  // And finally add the saved shifts.
+  ShiftLeft(shifts * power_exponent);
+}
+
+
+// Precondition: this/other < 16bit.
+uint16_t Bignum::DivideModuloIntBignum(const Bignum& other) {
+  ASSERT(IsClamped());
+  ASSERT(other.IsClamped());
+  ASSERT(other.used_digits_ > 0);
+
+  // Easy case: if we have less digits than the divisor than the result is 0.
+  // Note: this handles the case where this == 0, too.
+  if (BigitLength() < other.BigitLength()) {
+    return 0;
+  }
+
+  Align(other);
+
+  uint16_t result = 0;
+
+  // Start by removing multiples of 'other' until both numbers have the same
+  // number of digits.
+  while (BigitLength() > other.BigitLength()) {
+    // This naive approach is extremely inefficient if the this divided other
+    // might be big. This function is implemented for doubleToString where
+    // the result should be small (less than 10).
+    ASSERT(other.bigits_[other.used_digits_ - 1] >= ((1 << kBigitSize) / 16));
+    // Remove the multiples of the first digit.
+    // Example this = 23 and other equals 9. -> Remove 2 multiples.
+    result += bigits_[used_digits_ - 1];
+    SubtractTimes(other, bigits_[used_digits_ - 1]);
+  }
+
+  ASSERT(BigitLength() == other.BigitLength());
+
+  // Both bignums are at the same length now.
+  // Since other has more than 0 digits we know that the access to
+  // bigits_[used_digits_ - 1] is safe.
+  Chunk this_bigit = bigits_[used_digits_ - 1];
+  Chunk other_bigit = other.bigits_[other.used_digits_ - 1];
+
+  if (other.used_digits_ == 1) {
+    // Shortcut for easy (and common) case.
+    int quotient = this_bigit / other_bigit;
+    bigits_[used_digits_ - 1] = this_bigit - other_bigit * quotient;
+    result += quotient;
+    Clamp();
+    return result;
+  }
+
+  int division_estimate = this_bigit / (other_bigit + 1);
+  result += division_estimate;
+  SubtractTimes(other, division_estimate);
+
+  if (other_bigit * (division_estimate + 1) > this_bigit) {
+    // No need to even try to subtract. Even if other's remaining digits were 0
+    // another subtraction would be too much.
+    return result;
+  }
+
+  while (LessEqual(other, *this)) {
+    SubtractBignum(other);
+    result++;
+  }
+  return result;
+}
+
+
+template<typename S>
+static int SizeInHexChars(S number) {
+  ASSERT(number > 0);
+  int result = 0;
+  while (number != 0) {
+    number >>= 4;
+    result++;
+  }
+  return result;
+}
+
+
+static char HexCharOfValue(int value) {
+  ASSERT(0 <= value && value <= 16);
+  if (value < 10) return value + '0';
+  return value - 10 + 'A';
+}
+
+
+bool Bignum::ToHexString(char* buffer, int buffer_size) const {
+  ASSERT(IsClamped());
+  // Each bigit must be printable as separate hex-character.
+  ASSERT(kBigitSize % 4 == 0);
+  const int kHexCharsPerBigit = kBigitSize / 4;
+
+  if (used_digits_ == 0) {
+    if (buffer_size < 2) return false;
+    buffer[0] = '0';
+    buffer[1] = '\0';
+    return true;
+  }
+  // We add 1 for the terminating '\0' character.
+  int needed_chars = (BigitLength() - 1) * kHexCharsPerBigit +
+      SizeInHexChars(bigits_[used_digits_ - 1]) + 1;
+  if (needed_chars > buffer_size) return false;
+  int string_index = needed_chars - 1;
+  buffer[string_index--] = '\0';
+  for (int i = 0; i < exponent_; ++i) {
+    for (int j = 0; j < kHexCharsPerBigit; ++j) {
+      buffer[string_index--] = '0';
+    }
+  }
+  for (int i = 0; i < used_digits_ - 1; ++i) {
+    Chunk current_bigit = bigits_[i];
+    for (int j = 0; j < kHexCharsPerBigit; ++j) {
+      buffer[string_index--] = HexCharOfValue(current_bigit & 0xF);
+      current_bigit >>= 4;
+    }
+  }
+  // And finally the last bigit.
+  Chunk most_significant_bigit = bigits_[used_digits_ - 1];
+  while (most_significant_bigit != 0) {
+    buffer[string_index--] = HexCharOfValue(most_significant_bigit & 0xF);
+    most_significant_bigit >>= 4;
+  }
+  return true;
+}
+
+
+Bignum::Chunk Bignum::BigitAt(int index) const {
+  if (index >= BigitLength()) return 0;
+  if (index < exponent_) return 0;
+  return bigits_[index - exponent_];
+}
+
+
+int Bignum::Compare(const Bignum& a, const Bignum& b) {
+  ASSERT(a.IsClamped());
+  ASSERT(b.IsClamped());
+  int bigit_length_a = a.BigitLength();
+  int bigit_length_b = b.BigitLength();
+  if (bigit_length_a < bigit_length_b) return -1;
+  if (bigit_length_a > bigit_length_b) return +1;
+  for (int i = bigit_length_a - 1; i >= Min(a.exponent_, b.exponent_); --i) {
+    Chunk bigit_a = a.BigitAt(i);
+    Chunk bigit_b = b.BigitAt(i);
+    if (bigit_a < bigit_b) return -1;
+    if (bigit_a > bigit_b) return +1;
+    // Otherwise they are equal up to this digit. Try the next digit.
+  }
+  return 0;
+}
+
+
+int Bignum::PlusCompare(const Bignum& a, const Bignum& b, const Bignum& c) {
+  ASSERT(a.IsClamped());
+  ASSERT(b.IsClamped());
+  ASSERT(c.IsClamped());
+  if (a.BigitLength() < b.BigitLength()) {
+    return PlusCompare(b, a, c);
+  }
+  if (a.BigitLength() + 1 < c.BigitLength()) return -1;
+  if (a.BigitLength() > c.BigitLength()) return +1;
+  // The exponent encodes 0-bigits. So if there are more 0-digits in 'a' than
+  // 'b' has digits, then the bigit-length of 'a'+'b' must be equal to the one
+  // of 'a'.
+  if (a.exponent_ >= b.BigitLength() && a.BigitLength() < c.BigitLength()) {
+    return -1;
+  }
+
+  Chunk borrow = 0;
+  // Starting at min_exponent all digits are == 0. So no need to compare them.
+  int min_exponent = Min(Min(a.exponent_, b.exponent_), c.exponent_);
+  for (int i = c.BigitLength() - 1; i >= min_exponent; --i) {
+    Chunk chunk_a = a.BigitAt(i);
+    Chunk chunk_b = b.BigitAt(i);
+    Chunk chunk_c = c.BigitAt(i);
+    Chunk sum = chunk_a + chunk_b;
+    if (sum > chunk_c + borrow) {
+      return +1;
+    } else {
+      borrow = chunk_c + borrow - sum;
+      if (borrow > 1) return -1;
+      borrow <<= kBigitSize;
+    }
+  }
+  if (borrow == 0) return 0;
+  return -1;
+}
+
+
+void Bignum::Clamp() {
+  while (used_digits_ > 0 && bigits_[used_digits_ - 1] == 0) {
+    used_digits_--;
+  }
+  if (used_digits_ == 0) {
+    // Zero.
+    exponent_ = 0;
+  }
+}
+
+
+bool Bignum::IsClamped() const {
+  return used_digits_ == 0 || bigits_[used_digits_ - 1] != 0;
+}
+
+
+void Bignum::Zero() {
+  for (int i = 0; i < used_digits_; ++i) {
+    bigits_[i] = 0;
+  }
+  used_digits_ = 0;
+  exponent_ = 0;
+}
+
+
+void Bignum::Align(const Bignum& other) {
+  if (exponent_ > other.exponent_) {
+    // If "X" represents a "hidden" digit (by the exponent) then we are in the
+    // following case (a == this, b == other):
+    // a:  aaaaaaXXXX   or a:   aaaaaXXX
+    // b:     bbbbbbX      b: bbbbbbbbXX
+    // We replace some of the hidden digits (X) of a with 0 digits.
+    // a:  aaaaaa000X   or a:   aaaaa0XX
+    int zero_digits = exponent_ - other.exponent_;
+    EnsureCapacity(used_digits_ + zero_digits);
+    for (int i = used_digits_ - 1; i >= 0; --i) {
+      bigits_[i + zero_digits] = bigits_[i];
+    }
+    for (int i = 0; i < zero_digits; ++i) {
+      bigits_[i] = 0;
+    }
+    used_digits_ += zero_digits;
+    exponent_ -= zero_digits;
+    ASSERT(used_digits_ >= 0);
+    ASSERT(exponent_ >= 0);
+  }
+}
+
+
+void Bignum::BigitsShiftLeft(int shift_amount) {
+  ASSERT(shift_amount < kBigitSize);
+  ASSERT(shift_amount >= 0);
+  Chunk carry = 0;
+  for (int i = 0; i < used_digits_; ++i) {
+    Chunk new_carry = bigits_[i] >> (kBigitSize - shift_amount);
+    bigits_[i] = ((bigits_[i] << shift_amount) + carry) & kBigitMask;
+    carry = new_carry;
+  }
+  if (carry != 0) {
+    bigits_[used_digits_] = carry;
+    used_digits_++;
+  }
+}
+
+
+void Bignum::SubtractTimes(const Bignum& other, int factor) {
+  ASSERT(exponent_ <= other.exponent_);
+  if (factor < 3) {
+    for (int i = 0; i < factor; ++i) {
+      SubtractBignum(other);
+    }
+    return;
+  }
+  Chunk borrow = 0;
+  int exponent_diff = other.exponent_ - exponent_;
+  for (int i = 0; i < other.used_digits_; ++i) {
+    DoubleChunk product = static_cast<DoubleChunk>(factor) * other.bigits_[i];
+    DoubleChunk remove = borrow + product;
+    Chunk difference = bigits_[i + exponent_diff] - (remove & kBigitMask);
+    bigits_[i + exponent_diff] = difference & kBigitMask;
+    borrow = static_cast<Chunk>((difference >> (kChunkSize - 1)) +
+                                (remove >> kBigitSize));
+  }
+  for (int i = other.used_digits_ + exponent_diff; i < used_digits_; ++i) {
+    if (borrow == 0) return;
+    Chunk difference = bigits_[i] - borrow;
+    bigits_[i] = difference & kBigitMask;
+    borrow = difference >> (kChunkSize - 1);
+    ++i;
+  }
+  Clamp();
+}
+
+
+} }  // namespace v8::internal
diff --git a/deps/v8/src/bignum.h b/deps/v8/src/bignum.h
new file mode 100644 (file)
index 0000000..1d2bff6
--- /dev/null
@@ -0,0 +1,140 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_BIGNUM_H_
+#define V8_BIGNUM_H_
+
+namespace v8 {
+namespace internal {
+
+class Bignum {
+ public:
+  // 3584 = 128 * 28. We can represent 2^3584 > 10^1000 accurately.
+  // This bignum can encode much bigger numbers, since it contains an
+  // exponent.
+  static const int kMaxSignificantBits = 3584;
+
+  Bignum();
+  void AssignUInt16(uint16_t value);
+  void AssignUInt64(uint64_t value);
+  void AssignBignum(const Bignum& other);
+
+  void AssignDecimalString(Vector<const char> value);
+  void AssignHexString(Vector<const char> value);
+
+  void AssignPowerUInt16(uint16_t base, int exponent);
+
+  void AddUInt16(uint16_t operand);
+  void AddUInt64(uint64_t operand);
+  void AddBignum(const Bignum& other);
+  // Precondition: this >= other.
+  void SubtractBignum(const Bignum& other);
+
+  void Square();
+  void ShiftLeft(int shift_amount);
+  void MultiplyByUInt32(uint32_t factor);
+  void MultiplyByUInt64(uint64_t factor);
+  void MultiplyByPowerOfTen(int exponent);
+  void Times10() { return MultiplyByUInt32(10); }
+  // Pseudocode:
+  //  int result = this / other;
+  //  this = this % other;
+  // In the worst case this function is in O(this/other).
+  uint16_t DivideModuloIntBignum(const Bignum& other);
+
+  bool ToHexString(char* buffer, int buffer_size) const;
+
+  static int Compare(const Bignum& a, const Bignum& b);
+  static bool Equal(const Bignum& a, const Bignum& b) {
+    return Compare(a, b) == 0;
+  }
+  static bool LessEqual(const Bignum& a, const Bignum& b) {
+    return Compare(a, b) <= 0;
+  }
+  static bool Less(const Bignum& a, const Bignum& b) {
+    return Compare(a, b) < 0;
+  }
+  // Returns Compare(a + b, c);
+  static int PlusCompare(const Bignum& a, const Bignum& b, const Bignum& c);
+  // Returns a + b == c
+  static bool PlusEqual(const Bignum& a, const Bignum& b, const Bignum& c) {
+    return PlusCompare(a, b, c) == 0;
+  }
+  // Returns a + b <= c
+  static bool PlusLessEqual(const Bignum& a, const Bignum& b, const Bignum& c) {
+    return PlusCompare(a, b, c) <= 0;
+  }
+  // Returns a + b < c
+  static bool PlusLess(const Bignum& a, const Bignum& b, const Bignum& c) {
+    return PlusCompare(a, b, c) < 0;
+  }
+ private:
+  typedef uint32_t Chunk;
+  typedef uint64_t DoubleChunk;
+
+  static const int kChunkSize = sizeof(Chunk) * 8;
+  static const int kDoubleChunkSize = sizeof(DoubleChunk) * 8;
+  // With bigit size of 28 we loose some bits, but a double still fits easily
+  // into two chunks, and more importantly we can use the Comba multiplication.
+  static const int kBigitSize = 28;
+  static const Chunk kBigitMask = (1 << kBigitSize) - 1;
+  // Every instance allocates kBigitLength chunks on the stack. Bignums cannot
+  // grow. There are no checks if the stack-allocated space is sufficient.
+  static const int kBigitCapacity = kMaxSignificantBits / kBigitSize;
+
+  void EnsureCapacity(int size) {
+    if (size > kBigitCapacity) {
+      UNREACHABLE();
+    }
+  }
+  void Align(const Bignum& other);
+  void Clamp();
+  bool IsClamped() const;
+  void Zero();
+  // Requires this to have enough capacity (no tests done).
+  // Updates used_digits_ if necessary.
+  // by must be < kBigitSize.
+  void BigitsShiftLeft(int shift_amount);
+  // BigitLength includes the "hidden" digits encoded in the exponent.
+  int BigitLength() const { return used_digits_ + exponent_; }
+  Chunk BigitAt(int index) const;
+  void SubtractTimes(const Bignum& other, int factor);
+
+  Chunk bigits_buffer_[kBigitCapacity];
+  // A vector backed by bigits_buffer_. This way accesses to the array are
+  // checked for out-of-bounds errors.
+  Vector<Chunk> bigits_;
+  int used_digits_;
+  // The Bignum's value equals value(bigits_) * 2^(exponent_ * kBigitSize).
+  int exponent_;
+
+  DISALLOW_COPY_AND_ASSIGN(Bignum);
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_BIGNUM_H_
index 0e49966bbdd7f50570569c1d34364786bfc2eaaa..f60a975dc10ac640bd7bf0ac54a967718ae3b0d0 100644 (file)
@@ -39,6 +39,8 @@
 #include "objects-visiting.h"
 #include "snapshot.h"
 #include "stub-cache.h"
+#include "extensions/externalize-string-extension.h"
+#include "extensions/gc-extension.h"
 
 namespace v8 {
 namespace internal {
@@ -137,6 +139,8 @@ Handle<String> Bootstrapper::NativesSourceLookup(int index) {
 
 void Bootstrapper::Initialize(bool create_heap_objects) {
   extensions_cache.Initialize(create_heap_objects);
+  GCExtension::Register();
+  ExternalizeStringExtension::Register();
 }
 
 
index b5df316d0f736a38bf11cd0ccea90bcaa742635e..1ab8802ec3ffb163897adee3da9214987b7774b0 100644 (file)
@@ -98,3 +98,12 @@ void API_Fatal(const char* location, const char* format, ...) {
   i::OS::PrintError("\n#\n\n");
   i::OS::Abort();
 }
+
+
+namespace v8 { namespace internal {
+
+  bool EnableSlowAsserts() { return FLAG_enable_slow_asserts; }
+
+  intptr_t HeapObjectTagMask() { return kHeapObjectTagMask; }
+
+} }  // namespace v8::internal
index 5ea59920ac1ee7497d7ee7c252e8906cb47600b6..6b493225ad0ddaba06beea683907c9fcaae862d0 100644 (file)
@@ -30,8 +30,6 @@
 
 #include <string.h>
 
-#include "flags.h"
-
 extern "C" void V8_Fatal(const char* file, int line, const char* format, ...);
 void API_Fatal(const char* location, const char* format, ...);
 
@@ -279,6 +277,12 @@ template <int> class StaticAssertionHelper { };
     SEMI_STATIC_JOIN(__StaticAssertTypedef__, __LINE__)
 
 
+namespace v8 { namespace internal {
+
+bool EnableSlowAsserts();
+
+} }  // namespace v8::internal
+
 // The ASSERT macro is equivalent to CHECK except that it only
 // generates code in debug builds.
 #ifdef DEBUG
@@ -287,7 +291,7 @@ template <int> class StaticAssertionHelper { };
 #define ASSERT_EQ(v1, v2)    CHECK_EQ(v1, v2)
 #define ASSERT_NE(v1, v2)    CHECK_NE(v1, v2)
 #define ASSERT_GE(v1, v2)    CHECK_GE(v1, v2)
-#define SLOW_ASSERT(condition) if (FLAG_enable_slow_asserts) CHECK(condition)
+#define SLOW_ASSERT(condition) if (EnableSlowAsserts()) CHECK(condition)
 #else
 #define ASSERT_RESULT(expr)     (expr)
 #define ASSERT(condition)      ((void) 0)
@@ -303,11 +307,16 @@ template <int> class StaticAssertionHelper { };
 // and release compilation modes behaviour.
 #define STATIC_ASSERT(test)  STATIC_CHECK(test)
 
+namespace v8 { namespace internal {
+
+intptr_t HeapObjectTagMask();
+
+} }  // namespace v8::internal
 
 #define ASSERT_TAG_ALIGNED(address) \
-  ASSERT((reinterpret_cast<intptr_t>(address) & kHeapObjectTagMask) == 0)
+  ASSERT((reinterpret_cast<intptr_t>(address) & HeapObjectTagMask()) == 0)
 
-#define ASSERT_SIZE_TAG_ALIGNED(size) ASSERT((size & kHeapObjectTagMask) == 0)
+#define ASSERT_SIZE_TAG_ALIGNED(size) ASSERT((size & HeapObjectTagMask()) == 0)
 
 #define ASSERT_NOT_NULL(p)  ASSERT_NE(NULL, p)
 
index 787ec2a7a1ee2d8d0b37d522d6453c4e2a93803b..8b9198fb99e4fc2c95d5c066497f45d82d30c129 100644 (file)
@@ -37,7 +37,6 @@ namespace v8 {
 namespace internal {
 
 bool CodeStub::FindCodeInCache(Code** code_out) {
-  if (has_custom_cache()) return GetCustomCache(code_out);
   int index = Heap::code_stubs()->FindEntry(GetKey());
   if (index != NumberDictionary::kNotFound) {
     *code_out = Code::cast(Heap::code_stubs()->ValueAt(index));
@@ -105,17 +104,14 @@ Handle<Code> CodeStub::GetCode() {
     Handle<Code> new_object = Factory::NewCode(desc, flags, masm.CodeObject());
     RecordCodeGeneration(*new_object, &masm);
 
-    if (has_custom_cache()) {
-      SetCustomCache(*new_object);
-    } else {
-      // Update the dictionary and the root in Heap.
-      Handle<NumberDictionary> dict =
-          Factory::DictionaryAtNumberPut(
-              Handle<NumberDictionary>(Heap::code_stubs()),
-              GetKey(),
-              new_object);
-      Heap::public_set_code_stubs(*dict);
-    }
+    // Update the dictionary and the root in Heap.
+    Handle<NumberDictionary> dict =
+        Factory::DictionaryAtNumberPut(
+            Handle<NumberDictionary>(Heap::code_stubs()),
+            GetKey(),
+            new_object);
+    Heap::public_set_code_stubs(*dict);
+
     code = *new_object;
   }
 
@@ -147,15 +143,11 @@ MaybeObject* CodeStub::TryGetCode() {
     code = Code::cast(new_object);
     RecordCodeGeneration(code, &masm);
 
-    if (has_custom_cache()) {
-      SetCustomCache(code);
-    } else {
-      // Try to update the code cache but do not fail if unable.
-      MaybeObject* maybe_new_object =
-          Heap::code_stubs()->AtNumberPut(GetKey(), code);
-      if (maybe_new_object->ToObject(&new_object)) {
-        Heap::public_set_code_stubs(NumberDictionary::cast(new_object));
-      }
+    // Try to update the code cache but do not fail if unable.
+    MaybeObject* maybe_new_object =
+        Heap::code_stubs()->AtNumberPut(GetKey(), code);
+    if (maybe_new_object->ToObject(&new_object)) {
+      Heap::public_set_code_stubs(NumberDictionary::cast(new_object));
     }
   }
 
index c0a8d3063c8002cdf1b6ea78669cd40d3ebb18d5..b156647d5d3a73f84a9d87c22dcc8c1f901c3ea0 100644 (file)
@@ -124,12 +124,6 @@ class CodeStub BASE_EMBEDDED {
 
   virtual ~CodeStub() {}
 
-  // Override these methods to provide a custom caching mechanism for
-  // an individual type of code stub.
-  virtual bool GetCustomCache(Code** code_out) { return false; }
-  virtual void SetCustomCache(Code* value) { }
-  virtual bool has_custom_cache() { return false; }
-
  protected:
   static const int kMajorBits = 5;
   static const int kMinorBits = kBitsPerInt - kSmiTagSize - kMajorBits;
@@ -524,32 +518,6 @@ class CEntryStub : public CodeStub {
 };
 
 
-class ApiGetterEntryStub : public CodeStub {
- public:
-  ApiGetterEntryStub(Handle<AccessorInfo> info,
-                     ApiFunction* fun)
-      : info_(info),
-        fun_(fun) { }
-  void Generate(MacroAssembler* masm);
-  virtual bool has_custom_cache() { return true; }
-  virtual bool GetCustomCache(Code** code_out);
-  virtual void SetCustomCache(Code* value);
-
-  static const int kStackSpace = 5;
-  static const int kArgc = 2;
- private:
-  Handle<AccessorInfo> info() { return info_; }
-  ApiFunction* fun() { return fun_; }
-  Major MajorKey() { return NoCache; }
-  int MinorKey() { return 0; }
-  const char* GetName() { return "ApiEntryStub"; }
-  // The accessor info associated with the function.
-  Handle<AccessorInfo> info_;
-  // The function to be called.
-  ApiFunction* fun_;
-};
-
-
 class JSEntryStub : public CodeStub {
  public:
   JSEntryStub() { }
index bda697abafdb2cc9e6fa85c0f5c8d891476ef7e9..fb8c5cd4a31e15082f5e92b3a9541bd5ab2d61f4 100644 (file)
@@ -70,9 +70,10 @@ void CodeGenerator::ProcessDeferred() {
     DeferredCode* code = deferred_.RemoveLast();
     ASSERT(masm_ == code->masm());
     // Record position of deferred code stub.
-    masm_->RecordStatementPosition(code->statement_position());
+    masm_->positions_recorder()->RecordStatementPosition(
+        code->statement_position());
     if (code->position() != RelocInfo::kNoPosition) {
-      masm_->RecordPosition(code->position());
+      masm_->positions_recorder()->RecordPosition(code->position());
     }
     // Generate the code.
     Comment cmnt(masm_, code->comment());
@@ -251,39 +252,6 @@ bool CodeGenerator::ShouldGenerateLog(Expression* type) {
 #endif
 
 
-Handle<Code> CodeGenerator::ComputeCallInitialize(
-    int argc,
-    InLoopFlag in_loop) {
-  if (in_loop == IN_LOOP) {
-    // Force the creation of the corresponding stub outside loops,
-    // because it may be used when clearing the ICs later - it is
-    // possible for a series of IC transitions to lose the in-loop
-    // information, and the IC clearing code can't generate a stub
-    // that it needs so we need to ensure it is generated already.
-    ComputeCallInitialize(argc, NOT_IN_LOOP);
-  }
-  CALL_HEAP_FUNCTION(
-      StubCache::ComputeCallInitialize(argc, in_loop, Code::CALL_IC),
-      Code);
-}
-
-
-Handle<Code> CodeGenerator::ComputeKeyedCallInitialize(
-    int argc,
-    InLoopFlag in_loop) {
-  if (in_loop == IN_LOOP) {
-    // Force the creation of the corresponding stub outside loops,
-    // because it may be used when clearing the ICs later - it is
-    // possible for a series of IC transitions to lose the in-loop
-    // information, and the IC clearing code can't generate a stub
-    // that it needs so we need to ensure it is generated already.
-    ComputeKeyedCallInitialize(argc, NOT_IN_LOOP);
-  }
-  CALL_HEAP_FUNCTION(
-      StubCache::ComputeCallInitialize(argc, in_loop, Code::KEYED_CALL_IC),
-      Code);
-}
-
 void CodeGenerator::ProcessDeclarations(ZoneList<Declaration*>* declarations) {
   int length = declarations->length();
   int globals = 0;
@@ -402,10 +370,10 @@ bool CodeGenerator::RecordPositions(MacroAssembler* masm,
                                     int pos,
                                     bool right_here) {
   if (pos != RelocInfo::kNoPosition) {
-    masm->RecordStatementPosition(pos);
-    masm->RecordPosition(pos);
+    masm->positions_recorder()->RecordStatementPosition(pos);
+    masm->positions_recorder()->RecordPosition(pos);
     if (right_here) {
-      return masm->WriteRecordedPositions();
+      return masm->positions_recorder()->WriteRecordedPositions();
     }
   }
   return false;
@@ -435,7 +403,7 @@ void CodeGenerator::CodeForDoWhileConditionPosition(DoWhileStatement* stmt) {
 
 void CodeGenerator::CodeForSourcePosition(int pos) {
   if (FLAG_debug_info && pos != RelocInfo::kNoPosition) {
-    masm()->RecordPosition(pos);
+    masm()->positions_recorder()->RecordPosition(pos);
   }
 }
 
@@ -481,20 +449,4 @@ int CEntryStub::MinorKey() {
 }
 
 
-bool ApiGetterEntryStub::GetCustomCache(Code** code_out) {
-  Object* cache = info()->load_stub_cache();
-  if (cache->IsUndefined()) {
-    return false;
-  } else {
-    *code_out = Code::cast(cache);
-    return true;
-  }
-}
-
-
-void ApiGetterEntryStub::SetCustomCache(Code* value) {
-  info()->set_load_stub_cache(value);
-}
-
-
 } }  // namespace v8::internal
index 8f923dd34b294775b0950cab5d05d9d60bfc7d4d..66300d6caf49b0e85af809ff778e3e1a06846884 100644 (file)
@@ -58,8 +58,6 @@
 //   Generate
 //   ComputeLazyCompile
 //   BuildFunctionInfo
-//   ComputeCallInitialize
-//   ComputeCallInitializeInLoop
 //   ProcessDeclarations
 //   DeclareGlobals
 //   CheckForInlineRuntimeCall
index 6f02960dda7cd3cc0519f05baeba32ab63a7ddd4..29bbbc7034e92deef346bb0d85e7c3e2aad4e4f8 100755 (executable)
@@ -279,7 +279,6 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
     // in that case too.
     ScriptDataImpl* pre_data = input_pre_data;
     if (pre_data == NULL
-        && FLAG_lazy
         && source_length >= FLAG_min_preparse_length) {
       pre_data = ParserApi::PartialPreParse(source, NULL, extension);
     }
index 790e807aef4f898413774f6c0c6b6f7ca648e7ea..c0dbf73ad025faf140a9ecef196bb8f600e17c7d 100644 (file)
@@ -33,7 +33,7 @@
 #include "conversions-inl.h"
 #include "dtoa.h"
 #include "factory.h"
-#include "scanner.h"
+#include "scanner-base.h"
 #include "strtod.h"
 
 namespace v8 {
@@ -121,7 +121,7 @@ static const double JUNK_STRING_VALUE = OS::nan_value();
 template <class Iterator, class EndMark>
 static inline bool AdvanceToNonspace(Iterator* current, EndMark end) {
   while (*current != end) {
-    if (!Scanner::kIsWhiteSpace.get(**current)) return true;
+    if (!ScannerConstants::kIsWhiteSpace.get(**current)) return true;
     ++*current;
   }
   return false;
@@ -654,7 +654,7 @@ static double InternalStringToDouble(Iterator current,
   buffer[buffer_pos] = '\0';
 
   double converted = Strtod(Vector<const char>(buffer, buffer_pos), exponent);
-  return sign? -converted: converted;
+  return sign ? -converted : converted;
 }
 
 
@@ -711,11 +711,6 @@ double StringToDouble(Vector<const char> str,
 }
 
 
-extern "C" char* dtoa(double d, int mode, int ndigits,
-                      int* decpt, int* sign, char** rve);
-
-extern "C" void freedtoa(char* s);
-
 const char* DoubleToCString(double v, Vector<char> buffer) {
   StringBuilder builder(buffer.start(), buffer.length());
 
@@ -739,21 +734,13 @@ const char* DoubleToCString(double v, Vector<char> buffer) {
     default: {
       int decimal_point;
       int sign;
-      char* decimal_rep;
-      bool used_gay_dtoa = false;
       const int kV8DtoaBufferCapacity = kBase10MaximalLength + 1;
-      char v8_dtoa_buffer[kV8DtoaBufferCapacity];
+      char decimal_rep[kV8DtoaBufferCapacity];
       int length;
 
-      if (DoubleToAscii(v, DTOA_SHORTEST, 0,
-                        Vector<char>(v8_dtoa_buffer, kV8DtoaBufferCapacity),
-                        &sign, &length, &decimal_point)) {
-        decimal_rep = v8_dtoa_buffer;
-      } else {
-        decimal_rep = dtoa(v, 0, 0, &decimal_point, &sign, NULL);
-        used_gay_dtoa = true;
-        length = StrLength(decimal_rep);
-      }
+      DoubleToAscii(v, DTOA_SHORTEST, 0,
+                    Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
+                    &sign, &length, &decimal_point);
 
       if (sign) builder.AddCharacter('-');
 
@@ -787,8 +774,6 @@ const char* DoubleToCString(double v, Vector<char> buffer) {
         if (exponent < 0) exponent = -exponent;
         builder.AddFormatted("%d", exponent);
       }
-
-      if (used_gay_dtoa) freedtoa(decimal_rep);
     }
   }
   return builder.Finalize();
@@ -816,7 +801,7 @@ const char* IntToCString(int n, Vector<char> buffer) {
 
 
 char* DoubleToFixedCString(double value, int f) {
-  const int kMaxDigitsBeforePoint = 20;
+  const int kMaxDigitsBeforePoint = 21;
   const double kFirstNonFixed = 1e21;
   const int kMaxDigitsAfterPoint = 20;
   ASSERT(f >= 0);
@@ -840,16 +825,14 @@ char* DoubleToFixedCString(double value, int f) {
   // Find a sufficiently precise decimal representation of n.
   int decimal_point;
   int sign;
-  // Add space for the '.' and the '\0' byte.
+  // Add space for the '\0' byte.
   const int kDecimalRepCapacity =
-      kMaxDigitsBeforePoint + kMaxDigitsAfterPoint + 2;
+      kMaxDigitsBeforePoint + kMaxDigitsAfterPoint + 1;
   char decimal_rep[kDecimalRepCapacity];
   int decimal_rep_length;
-  bool status = DoubleToAscii(value, DTOA_FIXED, f,
-                              Vector<char>(decimal_rep, kDecimalRepCapacity),
-                              &sign, &decimal_rep_length, &decimal_point);
-  USE(status);
-  ASSERT(status);
+  DoubleToAscii(value, DTOA_FIXED, f,
+                Vector<char>(decimal_rep, kDecimalRepCapacity),
+                &sign, &decimal_rep_length, &decimal_point);
 
   // Create a representation that is padded with zeros if needed.
   int zero_prefix_length = 0;
@@ -935,8 +918,6 @@ char* DoubleToExponentialCString(double value, int f) {
   // Find a sufficiently precise decimal representation of n.
   int decimal_point;
   int sign;
-  char* decimal_rep = NULL;
-  bool used_gay_dtoa = false;
   // f corresponds to the digits after the point. There is always one digit
   // before the point. The number of requested_digits equals hence f + 1.
   // And we have to add one character for the null-terminator.
@@ -944,31 +925,18 @@ char* DoubleToExponentialCString(double value, int f) {
   // Make sure that the buffer is big enough, even if we fall back to the
   // shortest representation (which happens when f equals -1).
   ASSERT(kBase10MaximalLength <= kMaxDigitsAfterPoint + 1);
-  char v8_dtoa_buffer[kV8DtoaBufferCapacity];
+  char decimal_rep[kV8DtoaBufferCapacity];
   int decimal_rep_length;
 
   if (f == -1) {
-    if (DoubleToAscii(value, DTOA_SHORTEST, 0,
-                      Vector<char>(v8_dtoa_buffer, kV8DtoaBufferCapacity),
-                      &sign, &decimal_rep_length, &decimal_point)) {
-      f = decimal_rep_length - 1;
-      decimal_rep = v8_dtoa_buffer;
-    } else {
-      decimal_rep = dtoa(value, 0, 0, &decimal_point, &sign, NULL);
-      decimal_rep_length = StrLength(decimal_rep);
-      f = decimal_rep_length - 1;
-      used_gay_dtoa = true;
-    }
+    DoubleToAscii(value, DTOA_SHORTEST, 0,
+                  Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
+                  &sign, &decimal_rep_length, &decimal_point);
+    f = decimal_rep_length - 1;
   } else {
-    if (DoubleToAscii(value, DTOA_PRECISION, f + 1,
-                      Vector<char>(v8_dtoa_buffer, kV8DtoaBufferCapacity),
-                      &sign, &decimal_rep_length, &decimal_point)) {
-      decimal_rep = v8_dtoa_buffer;
-    } else {
-      decimal_rep = dtoa(value, 2, f + 1, &decimal_point, &sign, NULL);
-      decimal_rep_length = StrLength(decimal_rep);
-      used_gay_dtoa = true;
-    }
+    DoubleToAscii(value, DTOA_PRECISION, f + 1,
+                  Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
+                  &sign, &decimal_rep_length, &decimal_point);
   }
   ASSERT(decimal_rep_length > 0);
   ASSERT(decimal_rep_length <= f + 1);
@@ -977,10 +945,6 @@ char* DoubleToExponentialCString(double value, int f) {
   char* result =
       CreateExponentialRepresentation(decimal_rep, exponent, negative, f+1);
 
-  if (used_gay_dtoa) {
-    freedtoa(decimal_rep);
-  }
-
   return result;
 }
 
@@ -1000,22 +964,14 @@ char* DoubleToPrecisionCString(double value, int p) {
   // Find a sufficiently precise decimal representation of n.
   int decimal_point;
   int sign;
-  char* decimal_rep = NULL;
-  bool used_gay_dtoa = false;
   // Add one for the terminating null character.
   const int kV8DtoaBufferCapacity = kMaximalDigits + 1;
-  char v8_dtoa_buffer[kV8DtoaBufferCapacity];
+  char decimal_rep[kV8DtoaBufferCapacity];
   int decimal_rep_length;
 
-  if (DoubleToAscii(value, DTOA_PRECISION, p,
-                    Vector<char>(v8_dtoa_buffer, kV8DtoaBufferCapacity),
-                    &sign, &decimal_rep_length, &decimal_point)) {
-    decimal_rep = v8_dtoa_buffer;
-  } else {
-    decimal_rep = dtoa(value, 2, p, &decimal_point, &sign, NULL);
-    decimal_rep_length = StrLength(decimal_rep);
-    used_gay_dtoa = true;
-  }
+  DoubleToAscii(value, DTOA_PRECISION, p,
+                Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
+                &sign, &decimal_rep_length, &decimal_point);
   ASSERT(decimal_rep_length <= p);
 
   int exponent = decimal_point - 1;
@@ -1059,9 +1015,6 @@ char* DoubleToPrecisionCString(double value, int p) {
     result = builder.Finalize();
   }
 
-  if (used_gay_dtoa) {
-    freedtoa(decimal_rep);
-  }
   return result;
 }
 
index cae9b08d5b191b58ec55799c9ee3d4621a231d15..28053f46d1259546d10ce5ea9880e7c1efbb687e 100644 (file)
@@ -28,7 +28,8 @@
 #ifndef V8_DATEPARSER_H_
 #define V8_DATEPARSER_H_
 
-#include "scanner.h"
+#include "char-predicates-inl.h"
+#include "scanner-base.h"
 
 namespace v8 {
 namespace internal {
@@ -99,10 +100,20 @@ class DateParser : public AllStatic {
     }
 
     // The skip methods return whether they actually skipped something.
-    bool Skip(uint32_t c) { return ch_ == c ?  (Next(), true) : false; }
+    bool Skip(uint32_t c) {
+      if (ch_ == c) {
+        Next();
+        return true;
+      }
+      return false;
+    }
 
     bool SkipWhiteSpace() {
-      return Scanner::kIsWhiteSpace.get(ch_) ? (Next(), true) : false;
+      if (ScannerConstants::kIsWhiteSpace.get(ch_)) {
+        Next();
+        return true;
+      }
+      return false;
     }
 
     bool SkipParentheses() {
index 0eab8d1b831c562be092916a137bb601fe272455..d091991a1199eff1ebacd84894563657dd7e97db 100644 (file)
@@ -897,10 +897,6 @@ ExecutionState.prototype.frame = function(opt_index) {
   return new FrameMirror(this.break_id, opt_index);
 };
 
-ExecutionState.prototype.cframesValue = function(opt_from_index, opt_to_index) {
-  return %GetCFrames(this.break_id);
-};
-
 ExecutionState.prototype.setSelectedFrame = function(index) {
   var i = %ToNumber(index);
   if (i < 0 || i >= this.frameCount()) throw new Error('Illegal frame index.');
@@ -1751,11 +1747,6 @@ DebugCommandProcessor.prototype.backtraceRequest_ = function(request, response)
 };
 
 
-DebugCommandProcessor.prototype.backtracec = function(cmd, args) {
-  return this.exec_state_.cframesValue();
-};
-
-
 DebugCommandProcessor.prototype.frameRequest_ = function(request, response) {
   // No frames no source.
   if (this.exec_state_.frameCount() == 0) {
@@ -2205,29 +2196,6 @@ function NumberToHex8Str(n) {
   return r;
 };
 
-DebugCommandProcessor.prototype.formatCFrames = function(cframes_value) {
-  var result = "";
-  if (cframes_value == null || cframes_value.length == 0) {
-    result += "(stack empty)";
-  } else {
-    for (var i = 0; i < cframes_value.length; ++i) {
-      if (i != 0) result += "\n";
-      result += this.formatCFrame(cframes_value[i]);
-    }
-  }
-  return result;
-};
-
-
-DebugCommandProcessor.prototype.formatCFrame = function(cframe_value) {
-  var result = "";
-  result += "0x" + NumberToHex8Str(cframe_value.address);
-  if (!IS_UNDEFINED(cframe_value.text)) {
-    result += " " + cframe_value.text;
-  }
-  return result;
-}
-
 
 /**
  * Convert an Object to its debugger protocol representation. The representation
index 24f04098610aeec25b71a04bacbe5c1924a5eeac..f3bf954da9b8db6ea85006c74e50c50aece40351 100644 (file)
@@ -1839,6 +1839,7 @@ bool Debug::IsDebugGlobal(GlobalObject* global) {
 
 
 void Debug::ClearMirrorCache() {
+  PostponeInterruptsScope postpone;
   HandleScope scope;
   ASSERT(Top::context() == *Debug::debug_context());
 
index e805173e07e799249484df8f187c1c3ac61c05e5..65eded99893c80e8b0f0493b9156bc579d2b15e6 100644 (file)
@@ -54,18 +54,20 @@ class Double {
   explicit Double(DiyFp diy_fp)
     : d64_(DiyFpToUint64(diy_fp)) {}
 
+  // The value encoded by this Double must be greater or equal to +0.0.
+  // It must not be special (infinity, or NaN).
   DiyFp AsDiyFp() const {
+    ASSERT(Sign() > 0);
     ASSERT(!IsSpecial());
     return DiyFp(Significand(), Exponent());
   }
 
-  // this->Significand() must not be 0.
+  // The value encoded by this Double must be strictly greater than 0.
   DiyFp AsNormalizedDiyFp() const {
+    ASSERT(value() > 0.0);
     uint64_t f = Significand();
     int e = Exponent();
 
-    ASSERT(f != 0);
-
     // The current double could be a denormal.
     while ((f & kHiddenBit) == 0) {
       f <<= 1;
@@ -82,6 +84,20 @@ class Double {
     return d64_;
   }
 
+  // Returns the next greater double. Returns +infinity on input +infinity.
+  double NextDouble() const {
+    if (d64_ == kInfinity) return Double(kInfinity).value();
+    if (Sign() < 0 && Significand() == 0) {
+      // -0.0
+      return 0.0;
+    }
+    if (Sign() < 0) {
+      return Double(d64_ - 1).value();
+    } else {
+      return Double(d64_ + 1).value();
+    }
+  }
+
   int Exponent() const {
     if (IsDenormal()) return kDenormalExponent;
 
@@ -120,24 +136,30 @@ class Double {
         ((d64 & kSignificandMask) != 0);
   }
 
-
   bool IsInfinite() const {
     uint64_t d64 = AsUint64();
     return ((d64 & kExponentMask) == kExponentMask) &&
         ((d64 & kSignificandMask) == 0);
   }
 
-
   int Sign() const {
     uint64_t d64 = AsUint64();
     return (d64 & kSignMask) == 0? 1: -1;
   }
 
+  // Precondition: the value encoded by this Double must be greater or equal
+  // than +0.0.
+  DiyFp UpperBoundary() const {
+    ASSERT(Sign() > 0);
+    return DiyFp(Significand() * 2 + 1, Exponent() - 1);
+  }
 
   // Returns the two boundaries of this.
   // The bigger boundary (m_plus) is normalized. The lower boundary has the same
   // exponent as m_plus.
+  // Precondition: the value encoded by this Double must be greater than 0.
   void NormalizedBoundaries(DiyFp* out_m_minus, DiyFp* out_m_plus) const {
+    ASSERT(value() > 0.0);
     DiyFp v = this->AsDiyFp();
     bool significand_is_zero = (v.f() == kHiddenBit);
     DiyFp m_plus = DiyFp::Normalize(DiyFp((v.f() << 1) + 1, v.e() - 1));
index f4141eb619866118e6e17edb9ce18e8d3f1591b1..b857a5dc5997197465363efa547be19214722eb3 100644 (file)
@@ -30,6 +30,7 @@
 #include "v8.h"
 #include "dtoa.h"
 
+#include "bignum-dtoa.h"
 #include "double.h"
 #include "fast-dtoa.h"
 #include "fixed-dtoa.h"
 namespace v8 {
 namespace internal {
 
-bool DoubleToAscii(double v, DtoaMode mode, int requested_digits,
+static BignumDtoaMode DtoaToBignumDtoaMode(DtoaMode dtoa_mode) {
+  switch (dtoa_mode) {
+    case DTOA_SHORTEST:  return BIGNUM_DTOA_SHORTEST;
+    case DTOA_FIXED:     return BIGNUM_DTOA_FIXED;
+    case DTOA_PRECISION: return BIGNUM_DTOA_PRECISION;
+    default:
+      UNREACHABLE();
+      return BIGNUM_DTOA_SHORTEST;  // To silence compiler.
+  }
+}
+
+
+void DoubleToAscii(double v, DtoaMode mode, int requested_digits,
                    Vector<char> buffer, int* sign, int* length, int* point) {
   ASSERT(!Double(v).IsSpecial());
   ASSERT(mode == DTOA_SHORTEST || requested_digits >= 0);
@@ -54,25 +67,37 @@ bool DoubleToAscii(double v, DtoaMode mode, int requested_digits,
     buffer[1] = '\0';
     *length = 1;
     *point = 1;
-    return true;
+    return;
   }
 
   if (mode == DTOA_PRECISION && requested_digits == 0) {
     buffer[0] = '\0';
     *length = 0;
-    return true;
+    return;
   }
 
+  bool fast_worked;
   switch (mode) {
     case DTOA_SHORTEST:
-      return FastDtoa(v, FAST_DTOA_SHORTEST, 0, buffer, length, point);
+      fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST, 0, buffer, length, point);
+      break;
     case DTOA_FIXED:
-      return FastFixedDtoa(v, requested_digits, buffer, length, point);
+      fast_worked = FastFixedDtoa(v, requested_digits, buffer, length, point);
+      break;
     case DTOA_PRECISION:
-      return FastDtoa(v, FAST_DTOA_PRECISION, requested_digits,
-                      buffer, length, point);
+      fast_worked = FastDtoa(v, FAST_DTOA_PRECISION, requested_digits,
+                             buffer, length, point);
+      break;
+    default:
+      UNREACHABLE();
+      fast_worked = false;
   }
-  return false;
+  if (fast_worked) return;
+
+  // If the fast dtoa didn't succeed use the slower bignum version.
+  BignumDtoaMode bignum_mode = DtoaToBignumDtoaMode(mode);
+  BignumDtoa(v, bignum_mode, requested_digits, buffer, length, point);
+  buffer[*length] = '\0';
 }
 
 } }  // namespace v8::internal
index be0d5456b23e5b018e5153c0438d711e8c2bb955..b3e79afa4824d8379783132d091818ce18a45248 100644 (file)
@@ -32,13 +32,15 @@ namespace v8 {
 namespace internal {
 
 enum DtoaMode {
-  // 0.9999999999999999 becomes 0.1
+  // Return the shortest correct representation.
+  // For example the output of 0.299999999999999988897 is (the less accurate but
+  // correct) 0.3.
   DTOA_SHORTEST,
-  // Fixed number of digits after the decimal point.
+  // Return a fixed number of digits after the decimal point.
   // For instance fixed(0.1, 4) becomes 0.1000
   // If the input number is big, the output will be big.
   DTOA_FIXED,
-  // Fixed number of digits (independent of the decimal point).
+  // Return a fixed number of digits, no matter what the exponent is.
   DTOA_PRECISION
 };
 
@@ -72,8 +74,10 @@ static const int kBase10MaximalLength = 17;
 //   which case the caller has to fill the missing digits with '0's.
 //   Halfway cases are again rounded away from 0.
 // 'DoubleToAscii' expects the given buffer to be big enough to hold all digits
-// and a terminating null-character.
-bool DoubleToAscii(double v, DtoaMode mode, int requested_digits,
+// and a terminating null-character. In SHORTEST-mode it expects a buffer of
+// at least kBase10MaximalLength + 1. Otherwise, the size of the output is
+// limited to requested_digits digits plus the null terminator.
+void DoubleToAscii(double v, DtoaMode mode, int requested_digits,
                    Vector<char> buffer, int* sign, int* length, int* point);
 
 } }  // namespace v8::internal
index 885bf63cf1baf6050e70d00ae6bb15a8841c9900..691d56954a96b1997a957a1a3eaa47d53d2596b6 100644 (file)
@@ -700,135 +700,4 @@ MaybeObject* Execution::HandleStackGuardInterrupt() {
   return Heap::undefined_value();
 }
 
-// --- G C   E x t e n s i o n ---
-
-const char* const GCExtension::kSource = "native function gc();";
-
-
-v8::Handle<v8::FunctionTemplate> GCExtension::GetNativeFunction(
-    v8::Handle<v8::String> str) {
-  return v8::FunctionTemplate::New(GCExtension::GC);
-}
-
-
-v8::Handle<v8::Value> GCExtension::GC(const v8::Arguments& args) {
-  // All allocation spaces other than NEW_SPACE have the same effect.
-  Heap::CollectAllGarbage(false);
-  return v8::Undefined();
-}
-
-
-static GCExtension gc_extension;
-static v8::DeclareExtension gc_extension_declaration(&gc_extension);
-
-
-// --- E x t e r n a l i z e S t r i n g   E x t e n s i o n ---
-
-
-template <typename Char, typename Base>
-class SimpleStringResource : public Base {
- public:
-  // Takes ownership of |data|.
-  SimpleStringResource(Char* data, size_t length)
-      : data_(data),
-        length_(length) {}
-
-  virtual ~SimpleStringResource() { delete[] data_; }
-
-  virtual const Char* data() const { return data_; }
-
-  virtual size_t length() const { return length_; }
-
- private:
-  Char* const data_;
-  const size_t length_;
-};
-
-
-typedef SimpleStringResource<char, v8::String::ExternalAsciiStringResource>
-    SimpleAsciiStringResource;
-typedef SimpleStringResource<uc16, v8::String::ExternalStringResource>
-    SimpleTwoByteStringResource;
-
-
-const char* const ExternalizeStringExtension::kSource =
-    "native function externalizeString();"
-    "native function isAsciiString();";
-
-
-v8::Handle<v8::FunctionTemplate> ExternalizeStringExtension::GetNativeFunction(
-    v8::Handle<v8::String> str) {
-  if (strcmp(*v8::String::AsciiValue(str), "externalizeString") == 0) {
-    return v8::FunctionTemplate::New(ExternalizeStringExtension::Externalize);
-  } else {
-    ASSERT(strcmp(*v8::String::AsciiValue(str), "isAsciiString") == 0);
-    return v8::FunctionTemplate::New(ExternalizeStringExtension::IsAscii);
-  }
-}
-
-
-v8::Handle<v8::Value> ExternalizeStringExtension::Externalize(
-    const v8::Arguments& args) {
-  if (args.Length() < 1 || !args[0]->IsString()) {
-    return v8::ThrowException(v8::String::New(
-        "First parameter to externalizeString() must be a string."));
-  }
-  bool force_two_byte = false;
-  if (args.Length() >= 2) {
-    if (args[1]->IsBoolean()) {
-      force_two_byte = args[1]->BooleanValue();
-    } else {
-      return v8::ThrowException(v8::String::New(
-          "Second parameter to externalizeString() must be a boolean."));
-    }
-  }
-  bool result = false;
-  Handle<String> string = Utils::OpenHandle(*args[0].As<v8::String>());
-  if (string->IsExternalString()) {
-    return v8::ThrowException(v8::String::New(
-        "externalizeString() can't externalize twice."));
-  }
-  if (string->IsAsciiRepresentation() && !force_two_byte) {
-    char* data = new char[string->length()];
-    String::WriteToFlat(*string, data, 0, string->length());
-    SimpleAsciiStringResource* resource = new SimpleAsciiStringResource(
-        data, string->length());
-    result = string->MakeExternal(resource);
-    if (result && !string->IsSymbol()) {
-      i::ExternalStringTable::AddString(*string);
-    }
-    if (!result) delete resource;
-  } else {
-    uc16* data = new uc16[string->length()];
-    String::WriteToFlat(*string, data, 0, string->length());
-    SimpleTwoByteStringResource* resource = new SimpleTwoByteStringResource(
-        data, string->length());
-    result = string->MakeExternal(resource);
-    if (result && !string->IsSymbol()) {
-      i::ExternalStringTable::AddString(*string);
-    }
-    if (!result) delete resource;
-  }
-  if (!result) {
-    return v8::ThrowException(v8::String::New("externalizeString() failed."));
-  }
-  return v8::Undefined();
-}
-
-
-v8::Handle<v8::Value> ExternalizeStringExtension::IsAscii(
-    const v8::Arguments& args) {
-  if (args.Length() != 1 || !args[0]->IsString()) {
-    return v8::ThrowException(v8::String::New(
-        "isAsciiString() requires a single string argument."));
-  }
-  return Utils::OpenHandle(*args[0].As<v8::String>())->IsAsciiRepresentation() ?
-      v8::True() : v8::False();
-}
-
-
-static ExternalizeStringExtension externalize_extension;
-static v8::DeclareExtension externalize_extension_declaration(
-    &externalize_extension);
-
 } }  // namespace v8::internal
index 5547803be79d4d711c7d1a6d1fab3d1e3902eca9..a2ddc41a15f506fef49c41295c7a899ed0517195 100644 (file)
@@ -189,6 +189,9 @@ class StackGuard : public AllStatic {
   static uintptr_t climit() {
     return thread_local_.climit_;
   }
+  static uintptr_t real_climit() {
+    return thread_local_.real_climit_;
+  }
   static uintptr_t jslimit() {
     return thread_local_.jslimit_;
   }
@@ -313,29 +316,6 @@ class PostponeInterruptsScope BASE_EMBEDDED {
   }
 };
 
-
-class GCExtension : public v8::Extension {
- public:
-  GCExtension() : v8::Extension("v8/gc", kSource) {}
-  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
-      v8::Handle<v8::String> name);
-  static v8::Handle<v8::Value> GC(const v8::Arguments& args);
- private:
-  static const char* const kSource;
-};
-
-
-class ExternalizeStringExtension : public v8::Extension {
- public:
-  ExternalizeStringExtension() : v8::Extension("v8/externalize", kSource) {}
-  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
-      v8::Handle<v8::String> name);
-  static v8::Handle<v8::Value> Externalize(const v8::Arguments& args);
-  static v8::Handle<v8::Value> IsAscii(const v8::Arguments& args);
- private:
-  static const char* const kSource;
-};
-
 } }  // namespace v8::internal
 
 #endif  // V8_EXECUTION_H_
diff --git a/deps/v8/src/extensions/externalize-string-extension.cc b/deps/v8/src/extensions/externalize-string-extension.cc
new file mode 100644 (file)
index 0000000..8b4bdbd
--- /dev/null
@@ -0,0 +1,141 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "externalize-string-extension.h"
+
+namespace v8 {
+namespace internal {
+
+template <typename Char, typename Base>
+class SimpleStringResource : public Base {
+ public:
+  // Takes ownership of |data|.
+  SimpleStringResource(Char* data, size_t length)
+      : data_(data),
+        length_(length) {}
+
+  virtual ~SimpleStringResource() { delete[] data_; }
+
+  virtual const Char* data() const { return data_; }
+
+  virtual size_t length() const { return length_; }
+
+ private:
+  Char* const data_;
+  const size_t length_;
+};
+
+
+typedef SimpleStringResource<char, v8::String::ExternalAsciiStringResource>
+    SimpleAsciiStringResource;
+typedef SimpleStringResource<uc16, v8::String::ExternalStringResource>
+    SimpleTwoByteStringResource;
+
+
+const char* const ExternalizeStringExtension::kSource =
+    "native function externalizeString();"
+    "native function isAsciiString();";
+
+
+v8::Handle<v8::FunctionTemplate> ExternalizeStringExtension::GetNativeFunction(
+    v8::Handle<v8::String> str) {
+  if (strcmp(*v8::String::AsciiValue(str), "externalizeString") == 0) {
+    return v8::FunctionTemplate::New(ExternalizeStringExtension::Externalize);
+  } else {
+    ASSERT(strcmp(*v8::String::AsciiValue(str), "isAsciiString") == 0);
+    return v8::FunctionTemplate::New(ExternalizeStringExtension::IsAscii);
+  }
+}
+
+
+v8::Handle<v8::Value> ExternalizeStringExtension::Externalize(
+    const v8::Arguments& args) {
+  if (args.Length() < 1 || !args[0]->IsString()) {
+    return v8::ThrowException(v8::String::New(
+        "First parameter to externalizeString() must be a string."));
+  }
+  bool force_two_byte = false;
+  if (args.Length() >= 2) {
+    if (args[1]->IsBoolean()) {
+      force_two_byte = args[1]->BooleanValue();
+    } else {
+      return v8::ThrowException(v8::String::New(
+          "Second parameter to externalizeString() must be a boolean."));
+    }
+  }
+  bool result = false;
+  Handle<String> string = Utils::OpenHandle(*args[0].As<v8::String>());
+  if (string->IsExternalString()) {
+    return v8::ThrowException(v8::String::New(
+        "externalizeString() can't externalize twice."));
+  }
+  if (string->IsAsciiRepresentation() && !force_two_byte) {
+    char* data = new char[string->length()];
+    String::WriteToFlat(*string, data, 0, string->length());
+    SimpleAsciiStringResource* resource = new SimpleAsciiStringResource(
+        data, string->length());
+    result = string->MakeExternal(resource);
+    if (result && !string->IsSymbol()) {
+      i::ExternalStringTable::AddString(*string);
+    }
+    if (!result) delete resource;
+  } else {
+    uc16* data = new uc16[string->length()];
+    String::WriteToFlat(*string, data, 0, string->length());
+    SimpleTwoByteStringResource* resource = new SimpleTwoByteStringResource(
+        data, string->length());
+    result = string->MakeExternal(resource);
+    if (result && !string->IsSymbol()) {
+      i::ExternalStringTable::AddString(*string);
+    }
+    if (!result) delete resource;
+  }
+  if (!result) {
+    return v8::ThrowException(v8::String::New("externalizeString() failed."));
+  }
+  return v8::Undefined();
+}
+
+
+v8::Handle<v8::Value> ExternalizeStringExtension::IsAscii(
+    const v8::Arguments& args) {
+  if (args.Length() != 1 || !args[0]->IsString()) {
+    return v8::ThrowException(v8::String::New(
+        "isAsciiString() requires a single string argument."));
+  }
+  return Utils::OpenHandle(*args[0].As<v8::String>())->IsAsciiRepresentation() ?
+      v8::True() : v8::False();
+}
+
+
+void ExternalizeStringExtension::Register() {
+  static ExternalizeStringExtension externalize_extension;
+  static v8::DeclareExtension externalize_extension_declaration(
+      &externalize_extension);
+}
+
+} }  // namespace v8::internal
diff --git a/deps/v8/src/extensions/externalize-string-extension.h b/deps/v8/src/extensions/externalize-string-extension.h
new file mode 100644 (file)
index 0000000..b97b496
--- /dev/null
@@ -0,0 +1,50 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_EXTENSIONS_EXTERNALIZE_STRING_EXTENSION_H_
+#define V8_EXTENSIONS_EXTERNALIZE_STRING_EXTENSION_H_
+
+#include "v8.h"
+
+namespace v8 {
+namespace internal {
+
+class ExternalizeStringExtension : public v8::Extension {
+ public:
+  ExternalizeStringExtension() : v8::Extension("v8/externalize", kSource) {}
+  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
+      v8::Handle<v8::String> name);
+  static v8::Handle<v8::Value> Externalize(const v8::Arguments& args);
+  static v8::Handle<v8::Value> IsAscii(const v8::Arguments& args);
+  static void Register();
+ private:
+  static const char* const kSource;
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_EXTENSIONS_EXTERNALIZE_STRING_EXTENSION_H_
diff --git a/deps/v8/src/extensions/gc-extension.cc b/deps/v8/src/extensions/gc-extension.cc
new file mode 100644 (file)
index 0000000..b8f081c
--- /dev/null
@@ -0,0 +1,54 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "gc-extension.h"
+
+namespace v8 {
+namespace internal {
+
+const char* const GCExtension::kSource = "native function gc();";
+
+
+v8::Handle<v8::FunctionTemplate> GCExtension::GetNativeFunction(
+    v8::Handle<v8::String> str) {
+  return v8::FunctionTemplate::New(GCExtension::GC);
+}
+
+
+v8::Handle<v8::Value> GCExtension::GC(const v8::Arguments& args) {
+  // All allocation spaces other than NEW_SPACE have the same effect.
+  Heap::CollectAllGarbage(false);
+  return v8::Undefined();
+}
+
+
+void GCExtension::Register() {
+  static GCExtension gc_extension;
+  static v8::DeclareExtension gc_extension_declaration(&gc_extension);
+}
+
+} }  // namespace v8::internal
diff --git a/deps/v8/src/extensions/gc-extension.h b/deps/v8/src/extensions/gc-extension.h
new file mode 100644 (file)
index 0000000..06ea4ed
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_EXTENSIONS_GC_EXTENSION_H_
+#define V8_EXTENSIONS_GC_EXTENSION_H_
+
+#include "v8.h"
+
+namespace v8 {
+namespace internal {
+
+class GCExtension : public v8::Extension {
+ public:
+  GCExtension() : v8::Extension("v8/gc", kSource) {}
+  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
+      v8::Handle<v8::String> name);
+  static v8::Handle<v8::Value> GC(const v8::Arguments& args);
+  static void Register();
+ private:
+  static const char* const kSource;
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_EXTENSIONS_GC_EXTENSION_H_
index 54501ec95d99c397038a3753faf2704b5f88f8d2..46feea77ac273c358263ae3036fca0452ed29ed5 100644 (file)
@@ -186,6 +186,7 @@ DEFINE_bool(always_inline_smi_code, false,
 // heap.cc
 DEFINE_int(max_new_space_size, 0, "max size of the new generation (in kBytes)")
 DEFINE_int(max_old_space_size, 0, "max size of the old generation (in Mbytes)")
+DEFINE_int(max_executable_size, 0, "max size of executable memory (in Mbytes)")
 DEFINE_bool(gc_global, false, "always perform global GCs")
 DEFINE_int(gc_interval, -1, "garbage collect after <n> allocations")
 DEFINE_bool(trace_gc, false,
index 97987c27a80c7aae2c1349a12141fbcf171bad70..859247252456a102eded9228e0bc16757f08d961 100644 (file)
@@ -301,11 +301,6 @@ bool FullCodeGenerator::MakeCode(CompilationInfo* info) {
 }
 
 
-MemOperand FullCodeGenerator::ContextOperand(Register context, int index) {
-  return CodeGenerator::ContextOperand(context, index);
-}
-
-
 int FullCodeGenerator::SlotOffset(Slot* slot) {
   ASSERT(slot != NULL);
   // Offset is negative because higher indexes are at lower addresses.
@@ -563,9 +558,10 @@ void FullCodeGenerator::SetStatementPosition(int pos) {
 }
 
 
-void FullCodeGenerator::SetSourcePosition(int pos) {
+void FullCodeGenerator::SetSourcePosition(
+    int pos, PositionRecordingType recording_type) {
   if (FLAG_debug_info && pos != RelocInfo::kNoPosition) {
-    masm_->RecordPosition(pos);
+    masm_->positions_recorder()->RecordPosition(pos, recording_type);
   }
 }
 
@@ -1225,13 +1221,6 @@ int FullCodeGenerator::TryCatch::Exit(int stack_depth) {
 }
 
 
-void FullCodeGenerator::EmitRegExpCloneResult(ZoneList<Expression*>* args) {
-  ASSERT(args->length() == 1);
-  VisitForStackValue(args->at(0));
-  __ CallRuntime(Runtime::kRegExpCloneResult, 1);
-  context()->Plug(result_register());
-}
-
 #undef __
 
 
index 201507b2af338ea6e32b59d36c6a8cc145e22e0a..6a1def6ee1983833a92633489fe4b4d25ce01c1a 100644 (file)
@@ -423,7 +423,9 @@ class FullCodeGenerator: public AstVisitor {
   void SetStatementPosition(Statement* stmt);
   void SetExpressionPosition(Expression* expr, int pos);
   void SetStatementPosition(int pos);
-  void SetSourcePosition(int pos);
+  void SetSourcePosition(
+      int pos,
+      PositionRecordingType recording_type = NORMAL_POSITION);
 
   // Non-local control flow support.
   void EnterFinallyBlock();
@@ -462,9 +464,6 @@ class FullCodeGenerator: public AstVisitor {
   // in v8::internal::Context.
   void LoadContextField(Register dst, int context_index);
 
-  // Create an operand for a context field.
-  MemOperand ContextOperand(Register context, int context_index);
-
   // AST node visit functions.
 #define DECLARE_VISIT(type) virtual void Visit##type(type* node);
   AST_NODE_LIST(DECLARE_VISIT)
index 9ede90852831707059f5a3d174727236a0fb4b81..5339840988d4e6f3c719ef84e6e4b49867ef16d0 100644 (file)
@@ -372,13 +372,14 @@ void GlobalHandles::IdentifyWeakHandles(WeakSlotCallback f) {
 
 int post_gc_processing_count = 0;
 
-void GlobalHandles::PostGarbageCollectionProcessing() {
+bool GlobalHandles::PostGarbageCollectionProcessing() {
   // Process weak global handle callbacks. This must be done after the
   // GC is completely done, because the callbacks may invoke arbitrary
   // API functions.
   // At the same time deallocate all DESTROYED nodes.
   ASSERT(Heap::gc_state() == Heap::NOT_IN_GC);
   const int initial_post_gc_processing_count = ++post_gc_processing_count;
+  bool next_gc_likely_to_collect_more = false;
   Node** p = &head_;
   while (*p != NULL) {
     if ((*p)->PostGarbageCollectionProcessing()) {
@@ -399,6 +400,7 @@ void GlobalHandles::PostGarbageCollectionProcessing() {
       }
       node->set_next_free(first_deallocated());
       set_first_deallocated(node);
+      next_gc_likely_to_collect_more = true;
     } else {
       p = (*p)->next_addr();
     }
@@ -407,6 +409,8 @@ void GlobalHandles::PostGarbageCollectionProcessing() {
   if (first_deallocated()) {
     first_deallocated()->set_next(head());
   }
+
+  return next_gc_likely_to_collect_more;
 }
 
 
index 659f86eca70251687a009c585e4d59936e731edd..37b2b44522e55ea628a433f8546b5a5fd6e8da74 100644 (file)
@@ -96,7 +96,8 @@ class GlobalHandles : public AllStatic {
   static bool IsWeak(Object** location);
 
   // Process pending weak handles.
-  static void PostGarbageCollectionProcessing();
+  // Returns true if next major GC is likely to collect more garbage.
+  static bool PostGarbageCollectionProcessing();
 
   // Iterates over all strong handles.
   static void IterateStrongRoots(ObjectVisitor* v);
index c218f80dc11a701c048eeb957427243dc537c738..88c3e780d94e017b07b48f419dd7f07f78c1d6f0 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2006-2009 the V8 project authors. All rights reserved.
+// Copyright 2010 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
@@ -195,8 +195,8 @@ const int kCharSize     = sizeof(char);      // NOLINT
 const int kShortSize    = sizeof(short);     // NOLINT
 const int kIntSize      = sizeof(int);       // NOLINT
 const int kDoubleSize   = sizeof(double);    // NOLINT
-const int kPointerSize  = sizeof(void*);     // NOLINT
 const int kIntptrSize   = sizeof(intptr_t);  // NOLINT
+const int kPointerSize  = sizeof(void*);     // NOLINT
 
 #if V8_HOST_ARCH_64_BIT
 const int kPointerSizeLog2 = 3;
@@ -208,38 +208,6 @@ const intptr_t kIntptrSignBit = 0x80000000;
 const uintptr_t kUintptrAllBitsSet = 0xFFFFFFFFu;
 #endif
 
-// Mask for the sign bit in a smi.
-const intptr_t kSmiSignMask = kIntptrSignBit;
-
-const int kObjectAlignmentBits = kPointerSizeLog2;
-const intptr_t kObjectAlignment = 1 << kObjectAlignmentBits;
-const intptr_t kObjectAlignmentMask = kObjectAlignment - 1;
-
-// Desired alignment for pointers.
-const intptr_t kPointerAlignment = (1 << kPointerSizeLog2);
-const intptr_t kPointerAlignmentMask = kPointerAlignment - 1;
-
-// Desired alignment for maps.
-#if V8_HOST_ARCH_64_BIT
-const intptr_t kMapAlignmentBits = kObjectAlignmentBits;
-#else
-const intptr_t kMapAlignmentBits = kObjectAlignmentBits + 3;
-#endif
-const intptr_t kMapAlignment = (1 << kMapAlignmentBits);
-const intptr_t kMapAlignmentMask = kMapAlignment - 1;
-
-// Desired alignment for generated code is 32 bytes (to improve cache line
-// utilization).
-const int kCodeAlignmentBits = 5;
-const intptr_t kCodeAlignment = 1 << kCodeAlignmentBits;
-const intptr_t kCodeAlignmentMask = kCodeAlignment - 1;
-
-// Tag information for Failure.
-const int kFailureTag = 3;
-const int kFailureTagSize = 2;
-const intptr_t kFailureTagMask = (1 << kFailureTagSize) - 1;
-
-
 const int kBitsPerByte = 8;
 const int kBitsPerByteLog2 = 3;
 const int kBitsPerPointer = kPointerSize * kBitsPerByte;
@@ -255,364 +223,6 @@ const int kBinary32MinExponent  = 0x01;
 const int kBinary32MantissaBits = 23;
 const int kBinary32ExponentShift = 23;
 
-// Zap-value: The value used for zapping dead objects.
-// Should be a recognizable hex value tagged as a heap object pointer.
-#ifdef V8_HOST_ARCH_64_BIT
-const Address kZapValue =
-    reinterpret_cast<Address>(V8_UINT64_C(0xdeadbeedbeadbeed));
-const Address kHandleZapValue =
-    reinterpret_cast<Address>(V8_UINT64_C(0x1baddead0baddead));
-const Address kFromSpaceZapValue =
-    reinterpret_cast<Address>(V8_UINT64_C(0x1beefdad0beefdad));
-const uint64_t kDebugZapValue = 0xbadbaddbbadbaddb;
-#else
-const Address kZapValue = reinterpret_cast<Address>(0xdeadbeed);
-const Address kHandleZapValue = reinterpret_cast<Address>(0xbaddead);
-const Address kFromSpaceZapValue = reinterpret_cast<Address>(0xbeefdad);
-const uint32_t kDebugZapValue = 0xbadbaddb;
-#endif
-
-
-// Number of bits to represent the page size for paged spaces. The value of 13
-// gives 8K bytes per page.
-const int kPageSizeBits = 13;
-
-// On Intel architecture, cache line size is 64 bytes.
-// On ARM it may be less (32 bytes), but as far this constant is
-// used for aligning data, it doesn't hurt to align on a greater value.
-const int kProcessorCacheLineSize = 64;
-
-// Constants relevant to double precision floating point numbers.
-
-// Quiet NaNs have bits 51 to 62 set, possibly the sign bit, and no
-// other bits set.
-const uint64_t kQuietNaNMask = static_cast<uint64_t>(0xfff) << 51;
-// If looking only at the top 32 bits, the QNaN mask is bits 19 to 30.
-const uint32_t kQuietNaNHighBitsMask = 0xfff << (51 - 32);
-
-
-// -----------------------------------------------------------------------------
-// Forward declarations for frequently used classes
-// (sorted alphabetically)
-
-class AccessorInfo;
-class Allocation;
-class Arguments;
-class Assembler;
-class AssertNoAllocation;
-class BreakableStatement;
-class Code;
-class CodeGenerator;
-class CodeStub;
-class Context;
-class Debug;
-class Debugger;
-class DebugInfo;
-class Descriptor;
-class DescriptorArray;
-class Expression;
-class ExternalReference;
-class FixedArray;
-class FunctionEntry;
-class FunctionLiteral;
-class FunctionTemplateInfo;
-class NumberDictionary;
-class StringDictionary;
-class FreeStoreAllocationPolicy;
-template <typename T> class Handle;
-class Heap;
-class HeapObject;
-class IC;
-class InterceptorInfo;
-class IterationStatement;
-class JSArray;
-class JSFunction;
-class JSObject;
-class LargeObjectSpace;
-template <typename T, class P = FreeStoreAllocationPolicy> class List;
-class LookupResult;
-class MacroAssembler;
-class Map;
-class MapSpace;
-class MarkCompactCollector;
-class NewSpace;
-class NodeVisitor;
-class Object;
-class MaybeObject;
-class OldSpace;
-class Property;
-class Proxy;
-class RegExpNode;
-struct RegExpCompileData;
-class RegExpTree;
-class RegExpCompiler;
-class RegExpVisitor;
-class Scope;
-template<class Allocator = FreeStoreAllocationPolicy> class ScopeInfo;
-class SerializedScopeInfo;
-class Script;
-class Slot;
-class Smi;
-template <typename Config, class Allocator = FreeStoreAllocationPolicy>
-    class SplayTree;
-class Statement;
-class String;
-class Struct;
-class SwitchStatement;
-class AstVisitor;
-class Variable;
-class VariableProxy;
-class RelocInfo;
-class Deserializer;
-class MessageLocation;
-class ObjectGroup;
-class TickSample;
-class VirtualMemory;
-class Mutex;
-
-typedef bool (*WeakSlotCallback)(Object** pointer);
-
-// -----------------------------------------------------------------------------
-// Miscellaneous
-
-// NOTE: SpaceIterator depends on AllocationSpace enumeration values being
-// consecutive.
-enum AllocationSpace {
-  NEW_SPACE,            // Semispaces collected with copying collector.
-  OLD_POINTER_SPACE,    // May contain pointers to new space.
-  OLD_DATA_SPACE,       // Must not have pointers to new space.
-  CODE_SPACE,           // No pointers to new space, marked executable.
-  MAP_SPACE,            // Only and all map objects.
-  CELL_SPACE,           // Only and all cell objects.
-  LO_SPACE,             // Promoted large objects.
-
-  FIRST_SPACE = NEW_SPACE,
-  LAST_SPACE = LO_SPACE,
-  FIRST_PAGED_SPACE = OLD_POINTER_SPACE,
-  LAST_PAGED_SPACE = CELL_SPACE
-};
-const int kSpaceTagSize = 3;
-const int kSpaceTagMask = (1 << kSpaceTagSize) - 1;
-
-
-// A flag that indicates whether objects should be pretenured when
-// allocated (allocated directly into the old generation) or not
-// (allocated in the young generation if the object size and type
-// allows).
-enum PretenureFlag { NOT_TENURED, TENURED };
-
-enum GarbageCollector { SCAVENGER, MARK_COMPACTOR };
-
-enum Executability { NOT_EXECUTABLE, EXECUTABLE };
-
-enum VisitMode { VISIT_ALL, VISIT_ALL_IN_SCAVENGE, VISIT_ONLY_STRONG };
-
-// Flag indicating whether code is built into the VM (one of the natives files).
-enum NativesFlag { NOT_NATIVES_CODE, NATIVES_CODE };
-
-
-// A CodeDesc describes a buffer holding instructions and relocation
-// information. The instructions start at the beginning of the buffer
-// and grow forward, the relocation information starts at the end of
-// the buffer and grows backward.
-//
-//  |<--------------- buffer_size ---------------->|
-//  |<-- instr_size -->|        |<-- reloc_size -->|
-//  +==================+========+==================+
-//  |   instructions   |  free  |    reloc info    |
-//  +==================+========+==================+
-//  ^
-//  |
-//  buffer
-
-struct CodeDesc {
-  byte* buffer;
-  int buffer_size;
-  int instr_size;
-  int reloc_size;
-  Assembler* origin;
-};
-
-
-// Callback function on object slots, used for iterating heap object slots in
-// HeapObjects, global pointers to heap objects, etc. The callback allows the
-// callback function to change the value of the slot.
-typedef void (*ObjectSlotCallback)(HeapObject** pointer);
-
-
-// Callback function used for iterating objects in heap spaces,
-// for example, scanning heap objects.
-typedef int (*HeapObjectCallback)(HeapObject* obj);
-
-
-// Callback function used for checking constraints when copying/relocating
-// objects. Returns true if an object can be copied/relocated from its
-// old_addr to a new_addr.
-typedef bool (*ConstraintCallback)(Address new_addr, Address old_addr);
-
-
-// Callback function on inline caches, used for iterating over inline caches
-// in compiled code.
-typedef void (*InlineCacheCallback)(Code* code, Address ic);
-
-
-// State for inline cache call sites. Aliased as IC::State.
-enum InlineCacheState {
-  // Has never been executed.
-  UNINITIALIZED,
-  // Has been executed but monomorhic state has been delayed.
-  PREMONOMORPHIC,
-  // Has been executed and only one receiver type has been seen.
-  MONOMORPHIC,
-  // Like MONOMORPHIC but check failed due to prototype.
-  MONOMORPHIC_PROTOTYPE_FAILURE,
-  // Multiple receiver types have been seen.
-  MEGAMORPHIC,
-  // Special states for debug break or step in prepare stubs.
-  DEBUG_BREAK,
-  DEBUG_PREPARE_STEP_IN
-};
-
-
-enum InLoopFlag {
-  NOT_IN_LOOP,
-  IN_LOOP
-};
-
-
-enum CallFunctionFlags {
-  NO_CALL_FUNCTION_FLAGS = 0,
-  RECEIVER_MIGHT_BE_VALUE = 1 << 0  // Receiver might not be a JSObject.
-};
-
-
-enum InlineCacheHolderFlag {
-  OWN_MAP,  // For fast properties objects.
-  PROTOTYPE_MAP  // For slow properties objects (except GlobalObjects).
-};
-
-
-// Type of properties.
-// Order of properties is significant.
-// Must fit in the BitField PropertyDetails::TypeField.
-// A copy of this is in mirror-debugger.js.
-enum PropertyType {
-  NORMAL              = 0,  // only in slow mode
-  FIELD               = 1,  // only in fast mode
-  CONSTANT_FUNCTION   = 2,  // only in fast mode
-  CALLBACKS           = 3,
-  INTERCEPTOR         = 4,  // only in lookup results, not in descriptors.
-  MAP_TRANSITION      = 5,  // only in fast mode
-  CONSTANT_TRANSITION = 6,  // only in fast mode
-  NULL_DESCRIPTOR     = 7,  // only in fast mode
-  // All properties before MAP_TRANSITION are real.
-  FIRST_PHANTOM_PROPERTY_TYPE = MAP_TRANSITION,
-  // There are no IC stubs for NULL_DESCRIPTORS. Therefore,
-  // NULL_DESCRIPTOR can be used as the type flag for IC stubs for
-  // nonexistent properties.
-  NONEXISTENT = NULL_DESCRIPTOR
-};
-
-
-// Whether to remove map transitions and constant transitions from a
-// DescriptorArray.
-enum TransitionFlag {
-  REMOVE_TRANSITIONS,
-  KEEP_TRANSITIONS
-};
-
-
-// Union used for fast testing of specific double values.
-union DoubleRepresentation {
-  double  value;
-  int64_t bits;
-  DoubleRepresentation(double x) { value = x; }
-};
-
-
-// Union used for customized checking of the IEEE double types
-// inlined within v8 runtime, rather than going to the underlying
-// platform headers and libraries
-union IeeeDoubleLittleEndianArchType {
-  double d;
-  struct {
-    unsigned int man_low  :32;
-    unsigned int man_high :20;
-    unsigned int exp      :11;
-    unsigned int sign     :1;
-  } bits;
-};
-
-
-union IeeeDoubleBigEndianArchType {
-  double d;
-  struct {
-    unsigned int sign     :1;
-    unsigned int exp      :11;
-    unsigned int man_high :20;
-    unsigned int man_low  :32;
-  } bits;
-};
-
-
-// AccessorCallback
-struct AccessorDescriptor {
-  MaybeObject* (*getter)(Object* object, void* data);
-  MaybeObject* (*setter)(JSObject* object, Object* value, void* data);
-  void* data;
-};
-
-
-// Logging and profiling.
-// A StateTag represents a possible state of the VM.  When compiled with
-// ENABLE_VMSTATE_TRACKING, the logger maintains a stack of these.
-// Creating a VMState object enters a state by pushing on the stack, and
-// destroying a VMState object leaves a state by popping the current state
-// from the stack.
-
-#define STATE_TAG_LIST(V) \
-  V(JS)                   \
-  V(GC)                   \
-  V(COMPILER)             \
-  V(OTHER)                \
-  V(EXTERNAL)
-
-enum StateTag {
-#define DEF_STATE_TAG(name) name,
-  STATE_TAG_LIST(DEF_STATE_TAG)
-#undef DEF_STATE_TAG
-  // Pseudo-types.
-  state_tag_count
-};
-
-
-// -----------------------------------------------------------------------------
-// Macros
-
-// Testers for test.
-
-#define HAS_SMI_TAG(value) \
-  ((reinterpret_cast<intptr_t>(value) & kSmiTagMask) == kSmiTag)
-
-#define HAS_FAILURE_TAG(value) \
-  ((reinterpret_cast<intptr_t>(value) & kFailureTagMask) == kFailureTag)
-
-// OBJECT_POINTER_ALIGN returns the value aligned as a HeapObject pointer
-#define OBJECT_POINTER_ALIGN(value)                             \
-  (((value) + kObjectAlignmentMask) & ~kObjectAlignmentMask)
-
-// POINTER_SIZE_ALIGN returns the value aligned as a pointer.
-#define POINTER_SIZE_ALIGN(value)                               \
-  (((value) + kPointerAlignmentMask) & ~kPointerAlignmentMask)
-
-// MAP_POINTER_ALIGN returns the value aligned as a map pointer.
-#define MAP_POINTER_ALIGN(value)                                \
-  (((value) + kMapAlignmentMask) & ~kMapAlignmentMask)
-
-// CODE_POINTER_ALIGN returns the value aligned as a generated code segment.
-#define CODE_POINTER_ALIGN(value)                               \
-  (((value) + kCodeAlignmentMask) & ~kCodeAlignmentMask)
-
 // The expression OFFSET_OF(type, field) computes the byte-offset
 // of the specified field relative to the containing type. This
 // corresponds to 'offsetof' (in stddef.h), except that it doesn't
@@ -669,26 +279,6 @@ F FUNCTION_CAST(Address addr) {
   DISALLOW_COPY_AND_ASSIGN(TypeName)
 
 
-// Support for tracking C++ memory allocation.  Insert TRACK_MEMORY("Fisk")
-// inside a C++ class and new and delete will be overloaded so logging is
-// performed.
-// This file (globals.h) is included before log.h, so we use direct calls to
-// the Logger rather than the LOG macro.
-#ifdef DEBUG
-#define TRACK_MEMORY(name) \
-  void* operator new(size_t size) { \
-    void* result = ::operator new(size); \
-    Logger::NewEvent(name, result, size); \
-    return result; \
-  } \
-  void operator delete(void* object) { \
-    Logger::DeleteEvent(name, object); \
-    ::operator delete(object); \
-  }
-#else
-#define TRACK_MEMORY(name)
-#endif
-
 // Define used for helping GCC to make better inlining. Don't bother for debug
 // builds. On GCC 3.4.5 using __attribute__((always_inline)) causes compilation
 // errors in debug build.
@@ -712,20 +302,12 @@ F FUNCTION_CAST(Address addr) {
 #define MUST_USE_RESULT
 #endif
 
+// -----------------------------------------------------------------------------
+// Forward declarations for frequently used classes
+// (sorted alphabetically)
 
-// Feature flags bit positions. They are mostly based on the CPUID spec.
-// (We assign CPUID itself to one of the currently reserved bits --
-// feel free to change this if needed.)
-// On X86/X64, values below 32 are bits in EDX, values above 32 are bits in ECX.
-enum CpuFeature { SSE4_1 = 32 + 19,  // x86
-                  SSE3 = 32 + 0,     // x86
-                  SSE2 = 26,   // x86
-                  CMOV = 15,   // x86
-                  RDTSC = 4,   // x86
-                  CPUID = 10,  // x86
-                  VFP3 = 1,    // ARM
-                  ARMv7 = 2,   // ARM
-                  SAHF = 0};   // x86
+class FreeStoreAllocationPolicy;
+template <typename T, class P = FreeStoreAllocationPolicy> class List;
 
 } }  // namespace v8::internal
 
index 7a46bc3ea251fc6232b769ee0c4232c279306ae2..1364951b714ceb2c87731312f77ff1427ad98f5f 100644 (file)
@@ -499,6 +499,10 @@ void InitScriptLineEnds(Handle<Script> script) {
 
   Handle<FixedArray> array = CalculateLineEnds(src, true);
 
+  if (*array != Heap::empty_fixed_array()) {
+    array->set_map(Heap::fixed_cow_array_map());
+  }
+
   script->set_line_ends(*array);
   ASSERT(script->line_ends()->IsFixedArray());
 }
index 15feb9d5fb9ccceace38f05e9a695c9bdbc64acd..ba50c0f7358eaedf1d940a078357e591fe9b0782 100644 (file)
@@ -330,6 +330,11 @@ void Heap::ScavengeObject(HeapObject** p, HeapObject* object) {
 }
 
 
+bool Heap::CollectGarbage(AllocationSpace space) {
+  return CollectGarbage(space, SelectGarbageCollector(space));
+}
+
+
 MaybeObject* Heap::PrepareForCompare(String* str) {
   // Always flatten small strings and force flattening of long strings
   // after we have accumulated a certain amount we failed to flatten.
@@ -413,7 +418,7 @@ void Heap::SetLastScriptId(Object* last_script_id) {
     }                                                                     \
     if (!__maybe_object__->IsRetryAfterGC()) RETURN_EMPTY;                \
     Counters::gc_last_resort_from_handles.Increment();                    \
-    Heap::CollectAllGarbage(false);                                       \
+    Heap::CollectAllAvailableGarbage();                                   \
     {                                                                     \
       AlwaysAllocateScope __scope__;                                      \
       __maybe_object__ = FUNCTION_CALL;                                   \
index e47d66f984805def59210f6920d7618fcd1dce01..d3cc4ab9106f7e62bbd8f0f77f09cdd2a8694cf0 100644 (file)
@@ -788,15 +788,13 @@ void AggregatedHeapSnapshotGenerator::CalculateStringsStats() {
 void AggregatedHeapSnapshotGenerator::CollectStats(HeapObject* obj) {
   InstanceType type = obj->map()->instance_type();
   ASSERT(0 <= type && type <= LAST_TYPE);
-  if (!FreeListNode::IsFreeListNode(obj)) {
-    agg_snapshot_->info()[type].increment_number(1);
-    agg_snapshot_->info()[type].increment_bytes(obj->Size());
-  }
+  agg_snapshot_->info()[type].increment_number(1);
+  agg_snapshot_->info()[type].increment_bytes(obj->Size());
 }
 
 
 void AggregatedHeapSnapshotGenerator::GenerateSnapshot() {
-  HeapIterator iterator;
+  HeapIterator iterator(HeapIterator::kPreciseFiltering);
   for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
     CollectStats(obj);
     agg_snapshot_->js_cons_profile()->CollectStats(obj);
index b037efd80450e1df3aae746d286eb9068b4e4b39..26859d7c07fc43e1622dfd92288bbe3fde5e9a78 100644 (file)
@@ -38,7 +38,7 @@
 #include "mark-compact.h"
 #include "natives.h"
 #include "objects-visiting.h"
-#include "scanner.h"
+#include "scanner-base.h"
 #include "scopeinfo.h"
 #include "snapshot.h"
 #include "v8threads.h"
@@ -79,20 +79,32 @@ int Heap::amount_of_external_allocated_memory_at_last_global_gc_ = 0;
 // semispace_size_ should be a power of 2 and old_generation_size_ should be
 // a multiple of Page::kPageSize.
 #if defined(ANDROID)
-int Heap::max_semispace_size_  = 2*MB;
+static const int default_max_semispace_size_  = 2*MB;
 intptr_t Heap::max_old_generation_size_ = 192*MB;
 int Heap::initial_semispace_size_ = 128*KB;
 intptr_t Heap::code_range_size_ = 0;
+intptr_t Heap::max_executable_size_ = max_old_generation_size_;
 #elif defined(V8_TARGET_ARCH_X64)
-int Heap::max_semispace_size_  = 16*MB;
+static const int default_max_semispace_size_  = 16*MB;
 intptr_t Heap::max_old_generation_size_ = 1*GB;
 int Heap::initial_semispace_size_ = 1*MB;
 intptr_t Heap::code_range_size_ = 512*MB;
+intptr_t Heap::max_executable_size_ = 256*MB;
 #else
-int Heap::max_semispace_size_  = 8*MB;
+static const int default_max_semispace_size_  = 8*MB;
 intptr_t Heap::max_old_generation_size_ = 512*MB;
 int Heap::initial_semispace_size_ = 512*KB;
 intptr_t Heap::code_range_size_ = 0;
+intptr_t Heap::max_executable_size_ = 128*MB;
+#endif
+
+// Allow build-time customization of the max semispace size. Building
+// V8 with snapshots and a non-default max semispace size is much
+// easier if you can define it as part of the build environment.
+#if defined(V8_MAX_SEMISPACE_SIZE)
+int Heap::max_semispace_size_ = V8_MAX_SEMISPACE_SIZE;
+#else
+int Heap::max_semispace_size_ = default_max_semispace_size_;
 #endif
 
 // The snapshot semispace size will be the default semispace size if
@@ -172,6 +184,12 @@ intptr_t Heap::CommittedMemory() {
       lo_space_->Size();
 }
 
+intptr_t Heap::CommittedMemoryExecutable() {
+  if (!HasBeenSetup()) return 0;
+
+  return MemoryAllocator::SizeExecutable();
+}
+
 
 intptr_t Heap::Available() {
   if (!HasBeenSetup()) return 0;
@@ -386,7 +404,7 @@ intptr_t Heap::SizeOfObjects() {
   intptr_t total = 0;
   AllSpaces spaces;
   for (Space* space = spaces.next(); space != NULL; space = spaces.next()) {
-    total += space->Size();
+    total += space->SizeOfObjects();
   }
   return total;
 }
@@ -429,7 +447,31 @@ void Heap::CollectAllGarbage(bool force_compaction) {
 }
 
 
-void Heap::CollectGarbage(AllocationSpace space) {
+void Heap::CollectAllAvailableGarbage() {
+  // Since we are ignoring the return value, the exact choice of space does
+  // not matter, so long as we do not specify NEW_SPACE, which would not
+  // cause a full GC.
+  MarkCompactCollector::SetForceCompaction(true);
+
+  // Major GC would invoke weak handle callbacks on weakly reachable
+  // handles, but won't collect weakly reachable objects until next
+  // major GC.  Therefore if we collect aggressively and weak handle callback
+  // has been invoked, we rerun major GC to release objects which become
+  // garbage.
+  // Note: as weak callbacks can execute arbitrary code, we cannot
+  // hope that eventually there will be no weak callbacks invocations.
+  // Therefore stop recollecting after several attempts.
+  const int kMaxNumberOfAttempts = 7;
+  for (int attempt = 0; attempt < kMaxNumberOfAttempts; attempt++) {
+    if (!CollectGarbage(OLD_POINTER_SPACE, MARK_COMPACTOR)) {
+      break;
+    }
+  }
+  MarkCompactCollector::SetForceCompaction(false);
+}
+
+
+bool Heap::CollectGarbage(AllocationSpace space, GarbageCollector collector) {
   // The VM is in the GC state until exiting this function.
   VMState state(GC);
 
@@ -442,13 +484,14 @@ void Heap::CollectGarbage(AllocationSpace space) {
   allocation_timeout_ = Max(6, FLAG_gc_interval);
 #endif
 
+  bool next_gc_likely_to_collect_more = false;
+
   { GCTracer tracer;
     GarbageCollectionPrologue();
     // The GC count was incremented in the prologue.  Tell the tracer about
     // it.
     tracer.set_gc_count(gc_count_);
 
-    GarbageCollector collector = SelectGarbageCollector(space);
     // Tell the tracer which collector we've selected.
     tracer.set_collector(collector);
 
@@ -456,7 +499,8 @@ void Heap::CollectGarbage(AllocationSpace space) {
         ? &Counters::gc_scavenger
         : &Counters::gc_compactor;
     rate->Start();
-    PerformGarbageCollection(collector, &tracer);
+    next_gc_likely_to_collect_more =
+        PerformGarbageCollection(collector, &tracer);
     rate->Stop();
 
     GarbageCollectionEpilogue();
@@ -467,6 +511,8 @@ void Heap::CollectGarbage(AllocationSpace space) {
   if (FLAG_log_gc) HeapProfiler::WriteSample();
   if (CpuProfiler::is_profiling()) CpuProfiler::ProcessMovedFunctions();
 #endif
+
+  return next_gc_likely_to_collect_more;
 }
 
 
@@ -653,8 +699,10 @@ void Heap::UpdateSurvivalRateTrend(int start_new_space_size) {
   survival_rate_ = survival_rate;
 }
 
-void Heap::PerformGarbageCollection(GarbageCollector collector,
+bool Heap::PerformGarbageCollection(GarbageCollector collector,
                                     GCTracer* tracer) {
+  bool next_gc_likely_to_collect_more = false;
+
   if (collector != SCAVENGER) {
     PROFILE(CodeMovingGCEvent());
   }
@@ -720,7 +768,8 @@ void Heap::PerformGarbageCollection(GarbageCollector collector,
   if (collector == MARK_COMPACTOR) {
     DisableAssertNoAllocation allow_allocation;
     GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
-    GlobalHandles::PostGarbageCollectionProcessing();
+    next_gc_likely_to_collect_more =
+        GlobalHandles::PostGarbageCollectionProcessing();
   }
 
   // Update relocatables.
@@ -747,6 +796,8 @@ void Heap::PerformGarbageCollection(GarbageCollector collector,
     global_gc_epilogue_callback_();
   }
   VerifySymbolTable();
+
+  return next_gc_likely_to_collect_more;
 }
 
 
@@ -3198,7 +3249,8 @@ MaybeObject* Heap::AllocateStringFromUtf8(Vector<const char> string,
   const uc32 kMaxSupportedChar = 0xFFFF;
   // Count the number of characters in the UTF-8 string and check if
   // it is an ASCII string.
-  Access<Scanner::Utf8Decoder> decoder(Scanner::utf8_decoder());
+  Access<ScannerConstants::Utf8Decoder>
+      decoder(ScannerConstants::utf8_decoder());
   decoder->Reset(string.start(), string.length());
   int chars = 0;
   bool is_ascii = true;
@@ -4280,7 +4332,9 @@ static bool heap_configured = false;
 // TODO(1236194): Since the heap size is configurable on the command line
 // and through the API, we should gracefully handle the case that the heap
 // size is not big enough to fit all the initial objects.
-bool Heap::ConfigureHeap(int max_semispace_size, int max_old_gen_size) {
+bool Heap::ConfigureHeap(int max_semispace_size,
+                         int max_old_gen_size,
+                         int max_executable_size) {
   if (HasBeenSetup()) return false;
 
   if (max_semispace_size > 0) max_semispace_size_ = max_semispace_size;
@@ -4301,6 +4355,15 @@ bool Heap::ConfigureHeap(int max_semispace_size, int max_old_gen_size) {
   }
 
   if (max_old_gen_size > 0) max_old_generation_size_ = max_old_gen_size;
+  if (max_executable_size > 0) {
+    max_executable_size_ = RoundUp(max_executable_size, Page::kPageSize);
+  }
+
+  // The max executable size must be less than or equal to the max old
+  // generation size.
+  if (max_executable_size_ > max_old_generation_size_) {
+    max_executable_size_ = max_old_generation_size_;
+  }
 
   // The new space size must be a power of two to support single-bit testing
   // for containment.
@@ -4318,8 +4381,9 @@ bool Heap::ConfigureHeap(int max_semispace_size, int max_old_gen_size) {
 
 
 bool Heap::ConfigureHeapDefault() {
-  return ConfigureHeap(
-      FLAG_max_new_space_size * (KB / 2), FLAG_max_old_space_size * MB);
+  return ConfigureHeap(FLAG_max_new_space_size / 2 * KB,
+                       FLAG_max_old_space_size * MB,
+                       FLAG_max_executable_size * MB);
 }
 
 
@@ -4345,13 +4409,10 @@ void Heap::RecordStats(HeapStats* stats, bool take_snapshot) {
       MemoryAllocator::Size() + MemoryAllocator::Available();
   *stats->os_error = OS::GetLastError();
   if (take_snapshot) {
-    HeapIterator iterator;
+    HeapIterator iterator(HeapIterator::kPreciseFiltering);
     for (HeapObject* obj = iterator.next();
          obj != NULL;
          obj = iterator.next()) {
-      // Note: snapshot won't be precise because IsFreeListNode returns true
-      // for any bytearray.
-      if (FreeListNode::IsFreeListNode(obj)) continue;
       InstanceType type = obj->map()->instance_type();
       ASSERT(0 <= type && type <= LAST_TYPE);
       stats->objects_per_type[type]++;
@@ -4402,7 +4463,7 @@ bool Heap::Setup(bool create_heap_objects) {
   // space.  The chunk is double the size of the requested reserved
   // new space size to ensure that we can find a pair of semispaces that
   // are contiguous and aligned to their size.
-  if (!MemoryAllocator::Setup(MaxReserved())) return false;
+  if (!MemoryAllocator::Setup(MaxReserved(), MaxExecutableSize())) return false;
   void* chunk =
       MemoryAllocator::ReserveInitialChunk(4 * reserved_semispace_size_);
   if (chunk == NULL) return false;
@@ -4706,7 +4767,17 @@ OldSpace* OldSpaces::next() {
 }
 
 
-SpaceIterator::SpaceIterator() : current_space_(FIRST_SPACE), iterator_(NULL) {
+SpaceIterator::SpaceIterator()
+    : current_space_(FIRST_SPACE),
+      iterator_(NULL),
+      size_func_(NULL) {
+}
+
+
+SpaceIterator::SpaceIterator(HeapObjectCallback size_func)
+    : current_space_(FIRST_SPACE),
+      iterator_(NULL),
+      size_func_(size_func) {
 }
 
 
@@ -4744,25 +4815,25 @@ ObjectIterator* SpaceIterator::CreateIterator() {
 
   switch (current_space_) {
     case NEW_SPACE:
-      iterator_ = new SemiSpaceIterator(Heap::new_space());
+      iterator_ = new SemiSpaceIterator(Heap::new_space(), size_func_);
       break;
     case OLD_POINTER_SPACE:
-      iterator_ = new HeapObjectIterator(Heap::old_pointer_space());
+      iterator_ = new HeapObjectIterator(Heap::old_pointer_space(), size_func_);
       break;
     case OLD_DATA_SPACE:
-      iterator_ = new HeapObjectIterator(Heap::old_data_space());
+      iterator_ = new HeapObjectIterator(Heap::old_data_space(), size_func_);
       break;
     case CODE_SPACE:
-      iterator_ = new HeapObjectIterator(Heap::code_space());
+      iterator_ = new HeapObjectIterator(Heap::code_space(), size_func_);
       break;
     case MAP_SPACE:
-      iterator_ = new HeapObjectIterator(Heap::map_space());
+      iterator_ = new HeapObjectIterator(Heap::map_space(), size_func_);
       break;
     case CELL_SPACE:
-      iterator_ = new HeapObjectIterator(Heap::cell_space());
+      iterator_ = new HeapObjectIterator(Heap::cell_space(), size_func_);
       break;
     case LO_SPACE:
-      iterator_ = new LargeObjectIterator(Heap::lo_space());
+      iterator_ = new LargeObjectIterator(Heap::lo_space(), size_func_);
       break;
   }
 
@@ -4772,7 +4843,54 @@ ObjectIterator* SpaceIterator::CreateIterator() {
 }
 
 
-HeapIterator::HeapIterator() {
+class FreeListNodesFilter {
+ public:
+  FreeListNodesFilter() {
+    MarkFreeListNodes();
+  }
+
+  inline bool IsFreeListNode(HeapObject* object) {
+    if (object->IsMarked()) {
+      object->ClearMark();
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+ private:
+  void MarkFreeListNodes() {
+    Heap::old_pointer_space()->MarkFreeListNodes();
+    Heap::old_data_space()->MarkFreeListNodes();
+    MarkCodeSpaceFreeListNodes();
+    Heap::map_space()->MarkFreeListNodes();
+    Heap::cell_space()->MarkFreeListNodes();
+  }
+
+  void MarkCodeSpaceFreeListNodes() {
+    // For code space, using FreeListNode::IsFreeListNode is OK.
+    HeapObjectIterator iter(Heap::code_space());
+    for (HeapObject* obj = iter.next_object();
+         obj != NULL;
+         obj = iter.next_object()) {
+      if (FreeListNode::IsFreeListNode(obj)) obj->SetMark();
+    }
+  }
+
+  AssertNoAllocation no_alloc;
+};
+
+
+HeapIterator::HeapIterator()
+    : filtering_(HeapIterator::kNoFiltering),
+      filter_(NULL) {
+  Init();
+}
+
+
+HeapIterator::HeapIterator(HeapIterator::FreeListNodesFiltering filtering)
+    : filtering_(filtering),
+      filter_(NULL) {
   Init();
 }
 
@@ -4784,20 +4902,44 @@ HeapIterator::~HeapIterator() {
 
 void HeapIterator::Init() {
   // Start the iteration.
-  space_iterator_ = new SpaceIterator();
+  if (filtering_ == kPreciseFiltering) {
+    filter_ = new FreeListNodesFilter;
+    space_iterator_ =
+        new SpaceIterator(MarkCompactCollector::SizeOfMarkedObject);
+  } else {
+    space_iterator_ = new SpaceIterator;
+  }
   object_iterator_ = space_iterator_->next();
 }
 
 
 void HeapIterator::Shutdown() {
+#ifdef DEBUG
+  // Assert that in precise mode we have iterated through all
+  // objects. Otherwise, heap will be left in an inconsistent state.
+  if (filtering_ == kPreciseFiltering) {
+    ASSERT(object_iterator_ == NULL);
+  }
+#endif
   // Make sure the last iterator is deallocated.
   delete space_iterator_;
   space_iterator_ = NULL;
   object_iterator_ = NULL;
+  delete filter_;
+  filter_ = NULL;
 }
 
 
 HeapObject* HeapIterator::next() {
+  if (filter_ == NULL) return NextObject();
+
+  HeapObject* obj = NextObject();
+  while (obj != NULL && filter_->IsFreeListNode(obj)) obj = NextObject();
+  return obj;
+}
+
+
+HeapObject* HeapIterator::NextObject() {
   // No iterator means we are done.
   if (object_iterator_ == NULL) return NULL;
 
index 8ff2f5f3413511f831d8b8e199879c2711922c5e..93caf3bd4e43cc29069667d7a51ebf32ddf462e7 100644 (file)
@@ -222,7 +222,9 @@ class Heap : public AllStatic {
  public:
   // Configure heap size before setup. Return false if the heap has been
   // setup already.
-  static bool ConfigureHeap(int max_semispace_size, int max_old_gen_size);
+  static bool ConfigureHeap(int max_semispace_size,
+                            int max_old_gen_size,
+                            int max_executable_size);
   static bool ConfigureHeapDefault();
 
   // Initializes the global object heap. If create_heap_objects is true,
@@ -253,6 +255,7 @@ class Heap : public AllStatic {
   static int ReservedSemiSpaceSize() { return reserved_semispace_size_; }
   static int InitialSemiSpaceSize() { return initial_semispace_size_; }
   static intptr_t MaxOldGenerationSize() { return max_old_generation_size_; }
+  static intptr_t MaxExecutableSize() { return max_executable_size_; }
 
   // Returns the capacity of the heap in bytes w/o growing. Heap grows when
   // more spaces are needed until it reaches the limit.
@@ -261,6 +264,9 @@ class Heap : public AllStatic {
   // Returns the amount of memory currently committed for the heap.
   static intptr_t CommittedMemory();
 
+  // Returns the amount of executable memory currently committed for the heap.
+  static intptr_t CommittedMemoryExecutable();
+
   // Returns the available bytes in space w/o growing.
   // Heap doesn't guarantee that it can allocate an object that requires
   // all available bytes. Check MaxHeapObjectSize() instead.
@@ -705,13 +711,22 @@ class Heap : public AllStatic {
   static void GarbageCollectionEpilogue();
 
   // Performs garbage collection operation.
-  // Returns whether required_space bytes are available after the collection.
-  static void CollectGarbage(AllocationSpace space);
+  // Returns whether there is a chance that another major GC could
+  // collect more garbage.
+  static bool CollectGarbage(AllocationSpace space, GarbageCollector collector);
+
+  // Performs garbage collection operation.
+  // Returns whether there is a chance that another major GC could
+  // collect more garbage.
+  inline static bool CollectGarbage(AllocationSpace space);
 
   // Performs a full garbage collection. Force compaction if the
   // parameter is true.
   static void CollectAllGarbage(bool force_compaction);
 
+  // Last hope GC, should try to squeeze as much as possible.
+  static void CollectAllAvailableGarbage();
+
   // Notify the heap that a context has been disposed.
   static int NotifyContextDisposed() { return ++contexts_disposed_; }
 
@@ -1087,6 +1102,7 @@ class Heap : public AllStatic {
   static int max_semispace_size_;
   static int initial_semispace_size_;
   static intptr_t max_old_generation_size_;
+  static intptr_t max_executable_size_;
   static intptr_t code_range_size_;
 
   // For keeping track of how much data has survived
@@ -1246,7 +1262,9 @@ class Heap : public AllStatic {
   static GarbageCollector SelectGarbageCollector(AllocationSpace space);
 
   // Performs garbage collection
-  static void PerformGarbageCollection(GarbageCollector collector,
+  // Returns whether there is a chance another major GC could
+  // collect more garbage.
+  static bool PerformGarbageCollection(GarbageCollector collector,
                                        GCTracer* tracer);
 
   // Allocate an uninitialized object in map space.  The behavior is identical
@@ -1540,6 +1558,7 @@ class PagedSpaces BASE_EMBEDDED {
 class SpaceIterator : public Malloced {
  public:
   SpaceIterator();
+  explicit SpaceIterator(HeapObjectCallback size_func);
   virtual ~SpaceIterator();
 
   bool has_next();
@@ -1550,17 +1569,31 @@ class SpaceIterator : public Malloced {
 
   int current_space_;  // from enum AllocationSpace.
   ObjectIterator* iterator_;  // object iterator for the current space.
+  HeapObjectCallback size_func_;
 };
 
 
-// A HeapIterator provides iteration over the whole heap It aggregates a the
-// specific iterators for the different spaces as these can only iterate over
-// one space only.
+// A HeapIterator provides iteration over the whole heap. It
+// aggregates the specific iterators for the different spaces as
+// these can only iterate over one space only.
+//
+// HeapIterator can skip free list nodes (that is, de-allocated heap
+// objects that still remain in the heap). As implementation of free
+// nodes filtering uses GC marks, it can't be used during MS/MC GC
+// phases. Also, it is forbidden to interrupt iteration in this mode,
+// as this will leave heap objects marked (and thus, unusable).
+class FreeListNodesFilter;
 
 class HeapIterator BASE_EMBEDDED {
  public:
-  explicit HeapIterator();
-  virtual ~HeapIterator();
+  enum FreeListNodesFiltering {
+    kNoFiltering,
+    kPreciseFiltering
+  };
+
+  HeapIterator();
+  explicit HeapIterator(FreeListNodesFiltering filtering);
+  ~HeapIterator();
 
   HeapObject* next();
   void reset();
@@ -1568,10 +1601,12 @@ class HeapIterator BASE_EMBEDDED {
  private:
   // Perform the initialization.
   void Init();
-
   // Perform all necessary shutdown (destruction) work.
   void Shutdown();
+  HeapObject* NextObject();
 
+  FreeListNodesFiltering filtering_;
+  FreeListNodesFilter* filter_;
   // Space iterator for iterating all the spaces.
   SpaceIterator* space_iterator_;
   // Object iterator for the space currently being iterated.
index 019f478adc5c1575a9c515a6de4b852bfd04a5e0..125f503bec33109adfd606d5a26720d92d0efa31 100644 (file)
@@ -298,7 +298,8 @@ static void InitCoverageLog();
 // Spare buffer.
 byte* Assembler::spare_buffer_ = NULL;
 
-Assembler::Assembler(void* buffer, int buffer_size) {
+Assembler::Assembler(void* buffer, int buffer_size)
+    : positions_recorder_(this) {
   if (buffer == NULL) {
     // Do our own buffer management.
     if (buffer_size <= kMinimalBufferSize) {
@@ -339,10 +340,6 @@ Assembler::Assembler(void* buffer, int buffer_size) {
   reloc_info_writer.Reposition(buffer_ + buffer_size, pc_);
 
   last_pc_ = NULL;
-  current_statement_position_ = RelocInfo::kNoPosition;
-  current_position_ = RelocInfo::kNoPosition;
-  written_statement_position_ = current_statement_position_;
-  written_position_ = current_position_;
 #ifdef GENERATED_CODE_COVERAGE
   InitCoverageLog();
 #endif
@@ -1581,7 +1578,7 @@ void Assembler::call(const Operand& adr) {
 
 
 void Assembler::call(Handle<Code> code, RelocInfo::Mode rmode) {
-  WriteRecordedPositions();
+  positions_recorder()->WriteRecordedPositions();
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
   ASSERT(RelocInfo::IsCodeTarget(rmode));
@@ -2464,14 +2461,14 @@ void Assembler::Print() {
 
 
 void Assembler::RecordJSReturn() {
-  WriteRecordedPositions();
+  positions_recorder()->WriteRecordedPositions();
   EnsureSpace ensure_space(this);
   RecordRelocInfo(RelocInfo::JS_RETURN);
 }
 
 
 void Assembler::RecordDebugBreakSlot() {
-  WriteRecordedPositions();
+  positions_recorder()->WriteRecordedPositions();
   EnsureSpace ensure_space(this);
   RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
 }
@@ -2485,47 +2482,6 @@ void Assembler::RecordComment(const char* msg) {
 }
 
 
-void Assembler::RecordPosition(int pos) {
-  ASSERT(pos != RelocInfo::kNoPosition);
-  ASSERT(pos >= 0);
-  current_position_ = pos;
-}
-
-
-void Assembler::RecordStatementPosition(int pos) {
-  ASSERT(pos != RelocInfo::kNoPosition);
-  ASSERT(pos >= 0);
-  current_statement_position_ = pos;
-}
-
-
-bool Assembler::WriteRecordedPositions() {
-  bool written = false;
-
-  // Write the statement position if it is different from what was written last
-  // time.
-  if (current_statement_position_ != written_statement_position_) {
-    EnsureSpace ensure_space(this);
-    RecordRelocInfo(RelocInfo::STATEMENT_POSITION, current_statement_position_);
-    written_statement_position_ = current_statement_position_;
-    written = true;
-  }
-
-  // Write the position if it is different from what was written last time and
-  // also different from the written statement position.
-  if (current_position_ != written_position_ &&
-      current_position_ != written_statement_position_) {
-    EnsureSpace ensure_space(this);
-    RecordRelocInfo(RelocInfo::POSITION, current_position_);
-    written_position_ = current_position_;
-    written = true;
-  }
-
-  // Return whether something was written.
-  return written;
-}
-
-
 void Assembler::GrowBuffer() {
   ASSERT(overflow());
   if (!own_buffer_) FATAL("external code buffer is too small");
index 5286788fa72da108f0e1a7bfe22650def98a54ba..79637a1901044acf6944037d2ac6aa9d505876c2 100644 (file)
@@ -521,7 +521,6 @@ class Assembler : public Malloced {
   void push(const Immediate& x);
   void push(Register src);
   void push(const Operand& src);
-  void push(Label* label, RelocInfo::Mode relocation_mode);
 
   void pop(Register dst);
   void pop(const Operand& dst);
@@ -847,17 +846,11 @@ class Assembler : public Malloced {
   // Use --debug_code to enable.
   void RecordComment(const char* msg);
 
-  void RecordPosition(int pos);
-  void RecordStatementPosition(int pos);
-  bool WriteRecordedPositions();
-
   // Writes a single word of data in the code stream.
   // Used for inline tables, e.g., jump-tables.
   void dd(uint32_t data, RelocInfo::Mode reloc_info);
 
   int pc_offset() const { return pc_ - buffer_; }
-  int current_statement_position() const { return current_statement_position_; }
-  int current_position() const { return current_position_; }
 
   // Check if there is less than kGap bytes available in the buffer.
   // If this is the case, we need to grow the buffer before emitting
@@ -869,6 +862,8 @@ class Assembler : public Malloced {
 
   static bool IsNop(Address addr) { return *addr == 0x90; }
 
+  PositionsRecorder* positions_recorder() { return &positions_recorder_; }
+
   // Avoid overflows for displacements etc.
   static const int kMaximalBufferSize = 512*MB;
   static const int kMinimalBufferSize = 4*KB;
@@ -947,11 +942,9 @@ class Assembler : public Malloced {
   // push-pop elimination
   byte* last_pc_;
 
-  // source position information
-  int current_statement_position_;
-  int current_position_;
-  int written_statement_position_;
-  int written_position_;
+  PositionsRecorder positions_recorder_;
+
+  friend class PositionsRecorder;
 };
 
 
index b2b73926b9a473be53cdc0951903de792388e69e..6ac89bfbac0da3500266828c1c8187203b7333c3 100644 (file)
@@ -3058,15 +3058,6 @@ void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
 }
 
 
-void ApiGetterEntryStub::Generate(MacroAssembler* masm) {
-  __ PrepareCallApiFunction(kStackSpace, kArgc);
-  STATIC_ASSERT(kArgc == 2);
-  __ mov(ApiParameterOperand(0), ebx);  // name.
-  __ mov(ApiParameterOperand(1), eax);  // arguments pointer.
-  __ CallApiFunctionAndReturn(fun(), kArgc);
-}
-
-
 void CEntryStub::GenerateCore(MacroAssembler* masm,
                               Label* throw_normal_exception,
                               Label* throw_termination_exception,
index 6d23dd7df999f732d28654c6af0c7bf071f92f8b..fb7a138d5cba12313e4dd30780c5c11b29e6084b 100644 (file)
@@ -154,7 +154,7 @@ CodeGenerator::CodeGenerator(MacroAssembler* masm)
       safe_int32_mode_enabled_(true),
       function_return_is_shadowed_(false),
       in_spilled_code_(false),
-      jit_cookie_((FLAG_mask_constants_with_cookie) ? V8::Random() : 0) {
+      jit_cookie_((FLAG_mask_constants_with_cookie) ? V8::RandomPrivate() : 0) {
 }
 
 
@@ -686,10 +686,10 @@ void CodeGenerator::Load(Expression* expr) {
 
 void CodeGenerator::LoadGlobal() {
   if (in_spilled_code()) {
-    frame_->EmitPush(GlobalObject());
+    frame_->EmitPush(GlobalObjectOperand());
   } else {
     Result temp = allocator_->Allocate();
-    __ mov(temp.reg(), GlobalObject());
+    __ mov(temp.reg(), GlobalObjectOperand());
     frame_->Push(&temp);
   }
 }
@@ -698,7 +698,7 @@ void CodeGenerator::LoadGlobal() {
 void CodeGenerator::LoadGlobalReceiver() {
   Result temp = allocator_->Allocate();
   Register reg = temp.reg();
-  __ mov(reg, GlobalObject());
+  __ mov(reg, GlobalObjectOperand());
   __ mov(reg, FieldOperand(reg, GlobalObject::kGlobalReceiverOffset));
   frame_->Push(&temp);
 }
@@ -3734,7 +3734,7 @@ void CodeGenerator::VisitReturnStatement(ReturnStatement* node) {
   CodeForStatementPosition(node);
   Load(node->expression());
   Result return_value = frame_->Pop();
-  masm()->WriteRecordedPositions();
+  masm()->positions_recorder()->WriteRecordedPositions();
   if (function_return_is_shadowed_) {
     function_return_.Jump(&return_value);
   } else {
@@ -6294,6 +6294,18 @@ void CodeGenerator::VisitCall(Call* node) {
         // Push the receiver onto the frame.
         Load(property->obj());
 
+        // Load the name of the function.
+        Load(property->key());
+
+        // Swap the name of the function and the receiver on the stack to follow
+        // the calling convention for call ICs.
+        Result key = frame_->Pop();
+        Result receiver = frame_->Pop();
+        frame_->Push(&key);
+        frame_->Push(&receiver);
+        key.Unuse();
+        receiver.Unuse();
+
         // Load the arguments.
         int arg_count = args->length();
         for (int i = 0; i < arg_count; i++) {
@@ -6301,15 +6313,14 @@ void CodeGenerator::VisitCall(Call* node) {
           frame_->SpillTop();
         }
 
-        // Load the name of the function.
-        Load(property->key());
-
-        // Call the IC initialization code.
+        // Place the key on top of stack and call the IC initialization code.
+        frame_->PushElementAt(arg_count + 1);
         CodeForSourcePosition(node->position());
         Result result =
             frame_->CallKeyedCallIC(RelocInfo::CODE_TARGET,
                                     arg_count,
                                     loop_nesting());
+        frame_->Drop();  // Drop the key still on the stack.
         frame_->RestoreContextRegister();
         frame_->Push(&result);
       }
@@ -6778,8 +6789,8 @@ class DeferredIsStringWrapperSafeForDefaultValueOf : public DeferredCode {
     __ mov(scratch2_,
            FieldOperand(scratch2_, GlobalObject::kGlobalContextOffset));
     __ cmp(scratch1_,
-           CodeGenerator::ContextOperand(
-               scratch2_, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
+           ContextOperand(scratch2_,
+                          Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
     __ j(not_equal, &false_result);
     // Set the bit in the map to indicate that it has been checked safe for
     // default valueOf and set true result.
@@ -7292,88 +7303,6 @@ void CodeGenerator::GenerateRegExpConstructResult(ZoneList<Expression*>* args) {
 }
 
 
-void CodeGenerator::GenerateRegExpCloneResult(ZoneList<Expression*>* args) {
-  ASSERT_EQ(1, args->length());
-
-  Load(args->at(0));
-  Result object_result = frame_->Pop();
-  object_result.ToRegister(eax);
-  object_result.Unuse();
-  {
-    VirtualFrame::SpilledScope spilled_scope;
-
-    Label done;
-
-    __ test(eax, Immediate(kSmiTagMask));
-    __ j(zero, &done);
-
-    // Load JSRegExpResult map into edx.
-    // Arguments to this function should be results of calling RegExp exec,
-    // which is either an unmodified JSRegExpResult or null. Anything not having
-    // the unmodified JSRegExpResult map is returned unmodified.
-    // This also ensures that elements are fast.
-    __ mov(edx, ContextOperand(esi, Context::GLOBAL_INDEX));
-    __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalContextOffset));
-    __ mov(edx, ContextOperand(edx, Context::REGEXP_RESULT_MAP_INDEX));
-    __ cmp(edx, FieldOperand(eax, HeapObject::kMapOffset));
-    __ j(not_equal, &done);
-
-    if (FLAG_debug_code) {
-      // Check that object really has empty properties array, as the map
-      // should guarantee.
-      __ cmp(FieldOperand(eax, JSObject::kPropertiesOffset),
-             Immediate(Factory::empty_fixed_array()));
-      __ Check(equal, "JSRegExpResult: default map but non-empty properties.");
-    }
-
-    DeferredAllocateInNewSpace* allocate_fallback =
-        new DeferredAllocateInNewSpace(JSRegExpResult::kSize,
-                                       ebx,
-                                       edx.bit() | eax.bit());
-
-    // All set, copy the contents to a new object.
-    __ AllocateInNewSpace(JSRegExpResult::kSize,
-                          ebx,
-                          ecx,
-                          no_reg,
-                          allocate_fallback->entry_label(),
-                          TAG_OBJECT);
-    __ bind(allocate_fallback->exit_label());
-
-    // Copy all fields from eax to ebx.
-    STATIC_ASSERT(JSRegExpResult::kSize % (2 * kPointerSize) == 0);
-    // There is an even number of fields, so unroll the loop once
-    // for efficiency.
-    for (int i = 0; i < JSRegExpResult::kSize; i += 2 * kPointerSize) {
-      STATIC_ASSERT(JSObject::kMapOffset % (2 * kPointerSize) == 0);
-      if (i != JSObject::kMapOffset) {
-        // The map was already loaded into edx.
-        __ mov(edx, FieldOperand(eax, i));
-      }
-      __ mov(ecx, FieldOperand(eax, i + kPointerSize));
-
-      STATIC_ASSERT(JSObject::kElementsOffset % (2 * kPointerSize) == 0);
-      if (i == JSObject::kElementsOffset) {
-        // If the elements array isn't empty, make it copy-on-write
-        // before copying it.
-        Label empty;
-        __ cmp(Operand(edx), Immediate(Factory::empty_fixed_array()));
-        __ j(equal, &empty);
-        __ mov(FieldOperand(edx, HeapObject::kMapOffset),
-               Immediate(Factory::fixed_cow_array_map()));
-        __ bind(&empty);
-      }
-      __ mov(FieldOperand(ebx, i), edx);
-      __ mov(FieldOperand(ebx, i + kPointerSize), ecx);
-    }
-    __ mov(eax, ebx);
-
-    __ bind(&done);
-  }
-  frame_->Push(eax);
-}
-
-
 class DeferredSearchCache: public DeferredCode {
  public:
   DeferredSearchCache(Register dst, Register cache, Register key)
@@ -8016,7 +7945,7 @@ void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
     // Push the builtins object found in the current global object.
     Result temp = allocator()->Allocate();
     ASSERT(temp.is_valid());
-    __ mov(temp.reg(), GlobalObject());
+    __ mov(temp.reg(), GlobalObjectOperand());
     __ mov(temp.reg(), FieldOperand(temp.reg(), GlobalObject::kBuiltinsOffset));
     frame_->Push(&temp);
   }
@@ -8660,9 +8589,11 @@ void CodeGenerator::Int32BinaryOperation(BinaryOperation* node) {
       }
       right.Unuse();
       frame_->Push(&left);
-      if (!node->to_int32()) {
-        // If ToInt32 is called on the result of ADD, SUB, or MUL, we don't
+      if (!node->to_int32() || op == Token::MUL) {
+        // If ToInt32 is called on the result of ADD, SUB, we don't
         // care about overflows.
+        // Result of MUL can be non-representable precisely in double so
+        // we have to check for overflow.
         unsafe_bailout_->Branch(overflow);
       }
       break;
index 4594b19ddd29615fd8389b98c2ab1897f6cf27e9..a945e217ab7ceb71556921bdcccdd5f214e046c4 100644 (file)
@@ -352,10 +352,6 @@ class CodeGenerator: public AstVisitor {
     return FieldOperand(array, index_as_smi, times_half_pointer_size, offset);
   }
 
-  static Operand ContextOperand(Register context, int index) {
-    return Operand(context, Context::SlotOffset(index));
-  }
-
  private:
   // Type of a member function that generates inline code for a native function.
   typedef void (CodeGenerator::*InlineFunctionGenerator)
@@ -441,10 +437,6 @@ class CodeGenerator: public AstVisitor {
                                             JumpTarget* slow);
 
   // Expressions
-  static Operand GlobalObject() {
-    return ContextOperand(esi, Context::GLOBAL_INDEX);
-  }
-
   void LoadCondition(Expression* expr,
                      ControlDestination* destination,
                      bool force_control);
@@ -628,10 +620,6 @@ class CodeGenerator: public AstVisitor {
 
   void ProcessDeclarations(ZoneList<Declaration*>* declarations);
 
-  static Handle<Code> ComputeCallInitialize(int argc, InLoopFlag in_loop);
-
-  static Handle<Code> ComputeKeyedCallInitialize(int argc, InLoopFlag in_loop);
-
   // Declare global variables and functions in the given array of
   // name/value pairs.
   void DeclareGlobals(Handle<FixedArray> pairs);
@@ -697,11 +685,6 @@ class CodeGenerator: public AstVisitor {
   // Construct a RegExp exec result with two in-object properties.
   void GenerateRegExpConstructResult(ZoneList<Expression*>* args);
 
-  // Clone the result of a regexp function.
-  // Must be an object created by GenerateRegExpConstructResult with
-  // no extra properties.
-  void GenerateRegExpCloneResult(ZoneList<Expression*>* args);
-
   // Support for fast native caches.
   void GenerateGetFromCache(ZoneList<Expression*>* args);
 
index ee4e6458ae381bb56c7e5ec22aba13cf74c9f2fa..ad32dc85bedcabf8855598a1d44fbfbf8697991d 100644 (file)
@@ -36,6 +36,7 @@
 #include "full-codegen.h"
 #include "parser.h"
 #include "scopes.h"
+#include "stub-cache.h"
 
 namespace v8 {
 namespace internal {
@@ -954,7 +955,7 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
 
   // All extension objects were empty and it is safe to use a global
   // load IC call.
-  __ mov(eax, CodeGenerator::GlobalObject());
+  __ mov(eax, GlobalObjectOperand());
   __ mov(ecx, slot->var()->name());
   Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
   RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
@@ -1057,7 +1058,7 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var) {
     Comment cmnt(masm_, "Global variable");
     // Use inline caching. Variable name is passed in ecx and the global
     // object on the stack.
-    __ mov(eax, CodeGenerator::GlobalObject());
+    __ mov(eax, GlobalObjectOperand());
     __ mov(ecx, var->name());
     Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
     EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
@@ -1834,7 +1835,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
     // assignment.  Right-hand-side value is passed in eax, variable name in
     // ecx, and the global object on the stack.
     __ mov(ecx, var->name());
-    __ mov(edx, CodeGenerator::GlobalObject());
+    __ mov(edx, GlobalObjectOperand());
     Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
     EmitCallIC(ic, RelocInfo::CODE_TARGET);
 
@@ -1996,14 +1997,16 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
   // Code common for calls using the IC.
   ZoneList<Expression*>* args = expr->arguments();
   int arg_count = args->length();
-  for (int i = 0; i < arg_count; i++) {
-    VisitForStackValue(args->at(i));
+  { PreserveStatementPositionScope scope(masm()->positions_recorder());
+    for (int i = 0; i < arg_count; i++) {
+      VisitForStackValue(args->at(i));
+    }
+    __ Set(ecx, Immediate(name));
   }
-  __ Set(ecx, Immediate(name));
   // Record source position of the IC call.
-  SetSourcePosition(expr->position());
+  SetSourcePosition(expr->position(), FORCED_POSITION);
   InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
-  Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop);
+  Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, in_loop);
   EmitCallIC(ic, mode);
   // Restore context register.
   __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
@@ -2014,23 +2017,32 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
                                             Expression* key,
                                             RelocInfo::Mode mode) {
-  // Code common for calls using the IC.
+  // Load the key.
+  VisitForAccumulatorValue(key);
+
+  // Swap the name of the function and the receiver on the stack to follow
+  // the calling convention for call ICs.
+  __ pop(ecx);
+  __ push(eax);
+  __ push(ecx);
+
+  // Load the arguments.
   ZoneList<Expression*>* args = expr->arguments();
   int arg_count = args->length();
-  for (int i = 0; i < arg_count; i++) {
-    VisitForStackValue(args->at(i));
+  { PreserveStatementPositionScope scope(masm()->positions_recorder());
+    for (int i = 0; i < arg_count; i++) {
+      VisitForStackValue(args->at(i));
+    }
   }
-  VisitForAccumulatorValue(key);
-  __ mov(ecx, eax);
   // Record source position of the IC call.
-  SetSourcePosition(expr->position());
+  SetSourcePosition(expr->position(), FORCED_POSITION);
   InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
-  Handle<Code> ic = CodeGenerator::ComputeKeyedCallInitialize(
-      arg_count, in_loop);
+  Handle<Code> ic = StubCache::ComputeKeyedCallInitialize(arg_count, in_loop);
+  __ mov(ecx, Operand(esp, (arg_count + 1) * kPointerSize));  // Key.
   EmitCallIC(ic, mode);
   // Restore context register.
   __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
-  context()->Plug(eax);
+  context()->DropAndPlug(1, eax);  // Drop the key still on the stack.
 }
 
 
@@ -2038,11 +2050,13 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr) {
   // Code common for calls using the call stub.
   ZoneList<Expression*>* args = expr->arguments();
   int arg_count = args->length();
-  for (int i = 0; i < arg_count; i++) {
-    VisitForStackValue(args->at(i));
+  { PreserveStatementPositionScope scope(masm()->positions_recorder());
+    for (int i = 0; i < arg_count; i++) {
+      VisitForStackValue(args->at(i));
+    }
   }
   // Record source position for debugger.
-  SetSourcePosition(expr->position());
+  SetSourcePosition(expr->position(), FORCED_POSITION);
   InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
   CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
   __ CallStub(&stub);
@@ -2062,37 +2076,39 @@ void FullCodeGenerator::VisitCall(Call* expr) {
     // resolve the function we need to call and the receiver of the
     // call.  Then we call the resolved function using the given
     // arguments.
-    VisitForStackValue(fun);
-    __ push(Immediate(Factory::undefined_value()));  // Reserved receiver slot.
-
-    // Push the arguments.
     ZoneList<Expression*>* args = expr->arguments();
     int arg_count = args->length();
-    for (int i = 0; i < arg_count; i++) {
-      VisitForStackValue(args->at(i));
-    }
+    { PreserveStatementPositionScope pos_scope(masm()->positions_recorder());
+      VisitForStackValue(fun);
+      // Reserved receiver slot.
+      __ push(Immediate(Factory::undefined_value()));
 
-    // Push copy of the function - found below the arguments.
-    __ push(Operand(esp, (arg_count + 1) * kPointerSize));
+      // Push the arguments.
+      for (int i = 0; i < arg_count; i++) {
+        VisitForStackValue(args->at(i));
+      }
 
-    // Push copy of the first argument or undefined if it doesn't exist.
-    if (arg_count > 0) {
-      __ push(Operand(esp, arg_count * kPointerSize));
-    } else {
-      __ push(Immediate(Factory::undefined_value()));
-    }
+      // Push copy of the function - found below the arguments.
+      __ push(Operand(esp, (arg_count + 1) * kPointerSize));
 
-    // Push the receiver of the enclosing function and do runtime call.
-    __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize));
-    __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
+      // Push copy of the first argument or undefined if it doesn't exist.
+      if (arg_count > 0) {
+        __ push(Operand(esp, arg_count * kPointerSize));
+      } else {
+        __ push(Immediate(Factory::undefined_value()));
+      }
 
-    // The runtime call returns a pair of values in eax (function) and
-    // edx (receiver). Touch up the stack with the right values.
-    __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
-    __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
+      // Push the receiver of the enclosing function and do runtime call.
+      __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize));
+      __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
 
+      // The runtime call returns a pair of values in eax (function) and
+      // edx (receiver). Touch up the stack with the right values.
+      __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
+      __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
+    }
     // Record source position for debugger.
-    SetSourcePosition(expr->position());
+    SetSourcePosition(expr->position(), FORCED_POSITION);
     InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
     CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
     __ CallStub(&stub);
@@ -2101,19 +2117,21 @@ void FullCodeGenerator::VisitCall(Call* expr) {
     context()->DropAndPlug(1, eax);
   } else if (var != NULL && !var->is_this() && var->is_global()) {
     // Push global object as receiver for the call IC.
-    __ push(CodeGenerator::GlobalObject());
+    __ push(GlobalObjectOperand());
     EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
   } else if (var != NULL && var->AsSlot() != NULL &&
              var->AsSlot()->type() == Slot::LOOKUP) {
     // Call to a lookup slot (dynamically introduced variable).
     Label slow, done;
 
-    // Generate code for loading from variables potentially shadowed
-    // by eval-introduced variables.
-    EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
-                                    NOT_INSIDE_TYPEOF,
-                                    &slow,
-                                    &done);
+    { PreserveStatementPositionScope scope(masm()->positions_recorder());
+      // Generate code for loading from variables potentially shadowed
+      // by eval-introduced variables.
+      EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
+                                      NOT_INSIDE_TYPEOF,
+                                      &slow,
+                                      &done);
+    }
 
     __ bind(&slow);
     // Call the runtime to find the function to call (returned in eax)
@@ -2134,7 +2152,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
       // Push function.
       __ push(eax);
       // Push global receiver.
-      __ mov(ebx, CodeGenerator::GlobalObject());
+      __ mov(ebx, GlobalObjectOperand());
       __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
       __ bind(&call);
     }
@@ -2152,11 +2170,15 @@ void FullCodeGenerator::VisitCall(Call* expr) {
       // Call to a keyed property.
       // For a synthetic property use keyed load IC followed by function call,
       // for a regular property use keyed EmitCallIC.
-      VisitForStackValue(prop->obj());
+      { PreserveStatementPositionScope scope(masm()->positions_recorder());
+        VisitForStackValue(prop->obj());
+      }
       if (prop->is_synthetic()) {
-        VisitForAccumulatorValue(prop->key());
+        { PreserveStatementPositionScope scope(masm()->positions_recorder());
+          VisitForAccumulatorValue(prop->key());
+        }
         // Record source code position for IC call.
-        SetSourcePosition(prop->position());
+        SetSourcePosition(prop->position(), FORCED_POSITION);
         __ pop(edx);  // We do not need to keep the receiver.
 
         Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
@@ -2164,7 +2186,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
         // Push result (function).
         __ push(eax);
         // Push Global receiver.
-        __ mov(ecx, CodeGenerator::GlobalObject());
+        __ mov(ecx, GlobalObjectOperand());
         __ push(FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset));
         EmitCallWithStub(expr);
       } else {
@@ -2181,9 +2203,11 @@ void FullCodeGenerator::VisitCall(Call* expr) {
         loop_depth() == 0) {
       lit->set_try_full_codegen(true);
     }
-    VisitForStackValue(fun);
+    { PreserveStatementPositionScope scope(masm()->positions_recorder());
+      VisitForStackValue(fun);
+    }
     // Load global receiver object.
-    __ mov(ebx, CodeGenerator::GlobalObject());
+    __ mov(ebx, GlobalObjectOperand());
     __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
     // Emit function call.
     EmitCallWithStub(expr);
@@ -3073,7 +3097,7 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
 
   if (expr->is_jsruntime()) {
     // Prepare for calling JS runtime function.
-    __ mov(eax, CodeGenerator::GlobalObject());
+    __ mov(eax, GlobalObjectOperand());
     __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset));
   }
 
@@ -3087,7 +3111,7 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
     // Call the JS runtime function via a call IC.
     __ Set(ecx, Immediate(expr->name()));
     InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
-    Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop);
+    Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, in_loop);
     EmitCallIC(ic, RelocInfo::CODE_TARGET);
     // Restore context register.
     __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
@@ -3124,7 +3148,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
           VisitForStackValue(prop->obj());
           VisitForStackValue(prop->key());
         } else if (var->is_global()) {
-          __ push(CodeGenerator::GlobalObject());
+          __ push(GlobalObjectOperand());
           __ push(Immediate(var->name()));
         } else {
           // Non-global variable.  Call the runtime to look up the context
@@ -3402,7 +3426,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
 
   if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) {
     Comment cmnt(masm_, "Global variable");
-    __ mov(eax, CodeGenerator::GlobalObject());
+    __ mov(eax, GlobalObjectOperand());
     __ mov(ecx, Immediate(proxy->name()));
     Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
     // Use a regular load, not a contextual load, to avoid a reference
index b5f4deefeb906b5caa74a458676536fec46e4d07..a0bc086d871b85d3604542b1be6f415a4dde0176 100644 (file)
@@ -33,7 +33,6 @@
 #include "ic-inl.h"
 #include "runtime.h"
 #include "stub-cache.h"
-#include "utils.h"
 
 namespace v8 {
 namespace internal {
index b72f4df0e7ef2c0838bf1b36db23a79468e84d8b..db26c104257e890f10e7d4db7de74d7e0a571d47 100644 (file)
@@ -392,13 +392,8 @@ void MacroAssembler::EnterExitFrame() {
 }
 
 
-void MacroAssembler::EnterApiExitFrame(int stack_space,
-                                       int argc) {
+void MacroAssembler::EnterApiExitFrame(int argc) {
   EnterExitFramePrologue();
-
-  int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
-  lea(esi, Operand(ebp, (stack_space * kPointerSize) + offset));
-
   EnterExitFrameEpilogue(argc);
 }
 
@@ -411,6 +406,13 @@ void MacroAssembler::LeaveExitFrame() {
   // Pop the arguments and the receiver from the caller stack.
   lea(esp, Operand(esi, 1 * kPointerSize));
 
+  // Push the return address to get ready to return.
+  push(ecx);
+
+  LeaveExitFrameEpilogue();
+}
+
+void MacroAssembler::LeaveExitFrameEpilogue() {
   // Restore current context from top and clear it in debug mode.
   ExternalReference context_address(Top::k_context_address);
   mov(esi, Operand::StaticVariable(context_address));
@@ -418,15 +420,20 @@ void MacroAssembler::LeaveExitFrame() {
   mov(Operand::StaticVariable(context_address), Immediate(0));
 #endif
 
-  // Push the return address to get ready to return.
-  push(ecx);
-
   // Clear the top frame.
   ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
   mov(Operand::StaticVariable(c_entry_fp_address), Immediate(0));
 }
 
 
+void MacroAssembler::LeaveApiExitFrame() {
+  mov(esp, Operand(ebp));
+  pop(ebp);
+
+  LeaveExitFrameEpilogue();
+}
+
+
 void MacroAssembler::PushTryHandler(CodeLocation try_location,
                                     HandlerType type) {
   // Adjust this code if not the case.
@@ -1110,6 +1117,17 @@ void MacroAssembler::TailCallExternalReference(const ExternalReference& ext,
 }
 
 
+MaybeObject* MacroAssembler::TryTailCallExternalReference(
+    const ExternalReference& ext, int num_arguments, int result_size) {
+  // TODO(1236192): Most runtime routines don't need the number of
+  // arguments passed in because it is constant. At some point we
+  // should remove this need and make the runtime routine entry code
+  // smarter.
+  Set(eax, Immediate(num_arguments));
+  return TryJumpToExternalReference(ext);
+}
+
+
 void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
                                      int num_arguments,
                                      int result_size) {
@@ -1117,6 +1135,14 @@ void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
 }
 
 
+MaybeObject* MacroAssembler::TryTailCallRuntime(Runtime::FunctionId fid,
+                                                int num_arguments,
+                                                int result_size) {
+  return TryTailCallExternalReference(
+      ExternalReference(fid), num_arguments, result_size);
+}
+
+
 // If true, a Handle<T> passed by value is passed and returned by
 // using the location_ field directly.  If false, it is passed and
 // returned as a pointer to a handle.
@@ -1132,20 +1158,15 @@ Operand ApiParameterOperand(int index) {
 }
 
 
-void MacroAssembler::PrepareCallApiFunction(int stack_space, int argc) {
+void MacroAssembler::PrepareCallApiFunction(int argc, Register scratch) {
   if (kPassHandlesDirectly) {
-    EnterApiExitFrame(stack_space, argc);
+    EnterApiExitFrame(argc);
     // When handles as passed directly we don't have to allocate extra
     // space for and pass an out parameter.
   } else {
     // We allocate two additional slots: return value and pointer to it.
-    EnterApiExitFrame(stack_space, argc + 2);
-  }
-}
-
+    EnterApiExitFrame(argc + 2);
 
-void MacroAssembler::CallApiFunctionAndReturn(ApiFunction* function, int argc) {
-  if (!kPassHandlesDirectly) {
     // The argument slots are filled as follows:
     //
     //   n + 1: output cell
@@ -1157,11 +1178,19 @@ void MacroAssembler::CallApiFunctionAndReturn(ApiFunction* function, int argc) {
     // Note that this is one more "argument" than the function expects
     // so the out cell will have to be popped explicitly after returning
     // from the function. The out cell contains Handle.
-    lea(eax, Operand(esp, (argc + 1) * kPointerSize));  // pointer to out cell.
-    mov(Operand(esp, 0 * kPointerSize), eax);  // output.
-    mov(Operand(esp, (argc + 1) * kPointerSize), Immediate(0));  // out cell.
+
+    // pointer to out cell.
+    lea(scratch, Operand(esp, (argc + 1) * kPointerSize));
+    mov(Operand(esp, 0 * kPointerSize), scratch);  // output.
+    if (FLAG_debug_code) {
+      mov(Operand(esp, (argc + 1) * kPointerSize), Immediate(0));  // out cell.
+    }
   }
+}
 
+
+MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(ApiFunction* function,
+                                                         int stack_space) {
   ExternalReference next_address =
       ExternalReference::handle_scope_next_address();
   ExternalReference limit_address =
@@ -1210,10 +1239,14 @@ void MacroAssembler::CallApiFunctionAndReturn(ApiFunction* function, int argc) {
   cmp(Operand::StaticVariable(scheduled_exception_address),
          Immediate(Factory::the_hole_value()));
   j(not_equal, &promote_scheduled_exception, not_taken);
-  LeaveExitFrame();
-  ret(0);
+  LeaveApiExitFrame();
+  ret(stack_space * kPointerSize);
   bind(&promote_scheduled_exception);
-  TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
+  MaybeObject* result =
+      TryTailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
+  if (result->IsFailure()) {
+    return result;
+  }
   bind(&empty_handle);
   // It was zero; the result is undefined.
   mov(eax, Factory::undefined_value());
@@ -1227,6 +1260,8 @@ void MacroAssembler::CallApiFunctionAndReturn(ApiFunction* function, int argc) {
   call(Operand(eax));
   mov(eax, edi);
   jmp(&leave_exit_frame);
+
+  return result;
 }
 
 
@@ -1238,6 +1273,15 @@ void MacroAssembler::JumpToExternalReference(const ExternalReference& ext) {
 }
 
 
+MaybeObject* MacroAssembler::TryJumpToExternalReference(
+    const ExternalReference& ext) {
+  // Set the entry point and jump to the C entry runtime stub.
+  mov(ebx, Immediate(ext));
+  CEntryStub ces(1);
+  return TryTailCallStub(&ces);
+}
+
+
 void MacroAssembler::InvokePrologue(const ParameterCount& expected,
                                     const ParameterCount& actual,
                                     Handle<Code> code_constant,
index 7b9b843939e992bfc0a69163344a4e28dee60ea3..0a6e0ee35b68aff971e13113e6d93d92525b6f45 100644 (file)
@@ -123,13 +123,17 @@ class MacroAssembler: public Assembler {
   // to the first argument in register esi.
   void EnterExitFrame();
 
-  void EnterApiExitFrame(int stack_space, int argc);
+  void EnterApiExitFrame(int argc);
 
   // Leave the current exit frame. Expects the return value in
   // register eax:edx (untouched) and the pointer to the first
   // argument in register esi.
   void LeaveExitFrame();
 
+  // Leave the current exit frame. Expects the return value in
+  // register eax (untouched).
+  void LeaveApiExitFrame();
+
   // Find the function context up the context chain.
   void LoadContext(Register dst, int context_chain_length);
 
@@ -460,11 +464,23 @@ class MacroAssembler: public Assembler {
                                  int num_arguments,
                                  int result_size);
 
+  // Tail call of a runtime routine (jump). Try to generate the code if
+  // necessary. Do not perform a GC but instead return a retry after GC failure.
+  MUST_USE_RESULT MaybeObject* TryTailCallExternalReference(
+      const ExternalReference& ext, int num_arguments, int result_size);
+
   // Convenience function: tail call a runtime routine (jump).
   void TailCallRuntime(Runtime::FunctionId fid,
                        int num_arguments,
                        int result_size);
 
+  // Convenience function: tail call a runtime routine (jump). Try to generate
+  // the code if necessary. Do not perform a GC but instead return a retry after
+  // GC failure.
+  MUST_USE_RESULT MaybeObject* TryTailCallRuntime(Runtime::FunctionId fid,
+                                                  int num_arguments,
+                                                  int result_size);
+
   // Before calling a C-function from generated code, align arguments on stack.
   // After aligning the frame, arguments must be stored in esp[0], esp[4],
   // etc., not pushed. The argument count assumes all arguments are word sized.
@@ -485,17 +501,22 @@ class MacroAssembler: public Assembler {
   // Prepares stack to put arguments (aligns and so on). Reserves
   // space for return value if needed (assumes the return value is a handle).
   // Uses callee-saved esi to restore stack state after call. Arguments must be
-  // stored in ApiParameterOperand(0), ApiParameterOperand(1) etc.
-  void PrepareCallApiFunction(int stack_space, int argc);
+  // stored in ApiParameterOperand(0), ApiParameterOperand(1) etc. Saves
+  // context (esi).
+  void PrepareCallApiFunction(int argc, Register scratch);
 
-  // Tail call an API function (jump). Allocates HandleScope, extracts
+  // Calls an API function. Allocates HandleScope, extracts
   // returned value from handle and propagates exceptions.
-  // Clobbers ebx, esi, edi and caller-save registers.
-  void CallApiFunctionAndReturn(ApiFunction* function, int argc);
+  // Clobbers ebx, edi and caller-save registers. Restores context.
+  // On return removes stack_space * kPointerSize (GCed).
+  MaybeObject* TryCallApiFunctionAndReturn(ApiFunction* function,
+                                           int stack_space);
 
   // Jump to a runtime routine.
   void JumpToExternalReference(const ExternalReference& ext);
 
+  MaybeObject* TryJumpToExternalReference(const ExternalReference& ext);
+
 
   // ---------------------------------------------------------------------------
   // Utilities
@@ -589,6 +610,8 @@ class MacroAssembler: public Assembler {
   void EnterExitFramePrologue();
   void EnterExitFrameEpilogue(int argc);
 
+  void LeaveExitFrameEpilogue();
+
   // Allocation support helpers.
   void LoadAllocationTopHelper(Register result,
                                Register result_end,
@@ -642,6 +665,17 @@ static inline Operand FieldOperand(Register object,
   return Operand(object, index, scale, offset - kHeapObjectTag);
 }
 
+
+static inline Operand ContextOperand(Register context, int index) {
+  return Operand(context, Context::SlotOffset(index));
+}
+
+
+static inline Operand GlobalObjectOperand() {
+  return ContextOperand(esi, Context::GLOBAL_INDEX);
+}
+
+
 // Generates an Operand for saving parameters after PrepareCallApiFunction.
 Operand ApiParameterOperand(int index);
 
index e38708835995565b5aedd0916defe31619ad2683..4184d4cde30518d8a77530a43e8ac23e5b5a499c 100644 (file)
@@ -413,6 +413,10 @@ static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
 }
 
 
+// Number of pointers to be reserved on stack for fast API call.
+static const int kFastApiCallArguments = 3;
+
+
 // Reserves space for the extra arguments to FastHandleApiCall in the
 // caller's frame.
 //
@@ -423,10 +427,9 @@ static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
   //  -- esp[4] : last argument in the internal frame of the caller
   // -----------------------------------
   __ pop(scratch);
-  __ push(Immediate(Smi::FromInt(0)));
-  __ push(Immediate(Smi::FromInt(0)));
-  __ push(Immediate(Smi::FromInt(0)));
-  __ push(Immediate(Smi::FromInt(0)));
+  for (int i = 0; i < kFastApiCallArguments; i++) {
+    __ push(Immediate(Smi::FromInt(0)));
+  }
   __ push(scratch);
 }
 
@@ -434,75 +437,92 @@ static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
 // Undoes the effects of ReserveSpaceForFastApiCall.
 static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
   // ----------- S t a t e -------------
-  //  -- esp[0]  : return address
-  //  -- esp[4]  : last fast api call extra argument
+  //  -- esp[0]  : return address.
+  //  -- esp[4]  : last fast api call extra argument.
   //  -- ...
-  //  -- esp[16] : first fast api call extra argument
-  //  -- esp[20] : last argument in the internal frame
+  //  -- esp[kFastApiCallArguments * 4] : first fast api call extra argument.
+  //  -- esp[kFastApiCallArguments * 4 + 4] : last argument in the internal
+  //                                          frame.
   // -----------------------------------
   __ pop(scratch);
-  __ add(Operand(esp), Immediate(kPointerSize * 4));
+  __ add(Operand(esp), Immediate(kPointerSize * kFastApiCallArguments));
   __ push(scratch);
 }
 
 
 // Generates call to FastHandleApiCall builtin.
-static void GenerateFastApiCall(MacroAssembler* masm,
+static bool GenerateFastApiCall(MacroAssembler* masm,
                                 const CallOptimization& optimization,
-                                int argc) {
+                                int argc,
+                                Failure** failure) {
   // ----------- S t a t e -------------
   //  -- esp[0]              : return address
   //  -- esp[4]              : object passing the type check
   //                           (last fast api call extra argument,
   //                            set by CheckPrototypes)
-  //  -- esp[8]              : api call data
-  //  -- esp[12]             : api callback
-  //  -- esp[16]             : api function
+  //  -- esp[8]              : api function
   //                           (first fast api call extra argument)
-  //  -- esp[20]             : last argument
+  //  -- esp[12]             : api call data
+  //  -- esp[16]             : last argument
   //  -- ...
-  //  -- esp[(argc + 5) * 4] : first argument
-  //  -- esp[(argc + 6) * 4] : receiver
+  //  -- esp[(argc + 3) * 4] : first argument
+  //  -- esp[(argc + 4) * 4] : receiver
   // -----------------------------------
-
   // Get the function and setup the context.
   JSFunction* function = optimization.constant_function();
   __ mov(edi, Immediate(Handle<JSFunction>(function)));
   __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
 
   // Pass the additional arguments FastHandleApiCall expects.
-  __ mov(Operand(esp, 4 * kPointerSize), edi);
-  bool info_loaded = false;
-  Object* callback = optimization.api_call_info()->callback();
-  if (Heap::InNewSpace(callback)) {
-    info_loaded = true;
-    __ mov(ecx, Handle<CallHandlerInfo>(optimization.api_call_info()));
-    __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kCallbackOffset));
-    __ mov(Operand(esp, 3 * kPointerSize), ebx);
-  } else {
-    __ mov(Operand(esp, 3 * kPointerSize), Immediate(Handle<Object>(callback)));
-  }
+  __ mov(Operand(esp, 2 * kPointerSize), edi);
   Object* call_data = optimization.api_call_info()->data();
+  Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info());
   if (Heap::InNewSpace(call_data)) {
-    if (!info_loaded) {
-      __ mov(ecx, Handle<CallHandlerInfo>(optimization.api_call_info()));
-    }
+    __ mov(ecx, api_call_info_handle);
     __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset));
-    __ mov(Operand(esp, 2 * kPointerSize), ebx);
+    __ mov(Operand(esp, 3 * kPointerSize), ebx);
   } else {
-    __ mov(Operand(esp, 2 * kPointerSize),
+    __ mov(Operand(esp, 3 * kPointerSize),
            Immediate(Handle<Object>(call_data)));
   }
 
-  // Set the number of arguments.
-  __ mov(eax, Immediate(argc + 4));
+  // Prepare arguments.
+  __ lea(eax, Operand(esp, 3 * kPointerSize));
 
-  // Jump to the fast api call builtin (tail call).
-  Handle<Code> code = Handle<Code>(
-      Builtins::builtin(Builtins::FastHandleApiCall));
-  ParameterCount expected(0);
-  __ InvokeCode(code, expected, expected,
-                RelocInfo::CODE_TARGET, JUMP_FUNCTION);
+  Object* callback = optimization.api_call_info()->callback();
+  Address api_function_address = v8::ToCData<Address>(callback);
+  ApiFunction fun(api_function_address);
+
+  const int kApiArgc = 1;  // API function gets reference to the v8::Arguments.
+
+  // Allocate the v8::Arguments structure in the arguments' space since
+  // it's not controlled by GC.
+  const int kApiStackSpace = 4;
+
+  __ PrepareCallApiFunction(kApiArgc + kApiStackSpace, ebx);
+
+  __ mov(ApiParameterOperand(1), eax);  // v8::Arguments::implicit_args_.
+  __ add(Operand(eax), Immediate(argc * kPointerSize));
+  __ mov(ApiParameterOperand(2), eax);  // v8::Arguments::values_.
+  __ Set(ApiParameterOperand(3), Immediate(argc));  // v8::Arguments::length_.
+  // v8::Arguments::is_construct_call_.
+  __ Set(ApiParameterOperand(4), Immediate(0));
+
+  // v8::InvocationCallback's argument.
+  __ lea(eax, ApiParameterOperand(1));
+  __ mov(ApiParameterOperand(0), eax);
+
+  // Emitting a stub call may try to allocate (if the code is not
+  // already generated).  Do not allow the assembler to perform a
+  // garbage collection but instead return the allocation failure
+  // object.
+  MaybeObject* result =
+      masm->TryCallApiFunctionAndReturn(&fun, argc + kFastApiCallArguments + 1);
+  if (result->IsFailure()) {
+    *failure = Failure::cast(result);
+    return false;
+  }
+  return true;
 }
 
 
@@ -515,7 +535,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
         arguments_(arguments),
         name_(name) {}
 
-  void Compile(MacroAssembler* masm,
+  bool Compile(MacroAssembler* masm,
                JSObject* object,
                JSObject* holder,
                String* name,
@@ -524,7 +544,8 @@ class CallInterceptorCompiler BASE_EMBEDDED {
                Register scratch1,
                Register scratch2,
                Register scratch3,
-               Label* miss) {
+               Label* miss,
+               Failure** failure) {
     ASSERT(holder->HasNamedInterceptor());
     ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
 
@@ -535,17 +556,18 @@ class CallInterceptorCompiler BASE_EMBEDDED {
     CallOptimization optimization(lookup);
 
     if (optimization.is_constant_call()) {
-      CompileCacheable(masm,
-                       object,
-                       receiver,
-                       scratch1,
-                       scratch2,
-                       scratch3,
-                       holder,
-                       lookup,
-                       name,
-                       optimization,
-                       miss);
+      return CompileCacheable(masm,
+                              object,
+                              receiver,
+                              scratch1,
+                              scratch2,
+                              scratch3,
+                              holder,
+                              lookup,
+                              name,
+                              optimization,
+                              miss,
+                              failure);
     } else {
       CompileRegular(masm,
                      object,
@@ -556,11 +578,12 @@ class CallInterceptorCompiler BASE_EMBEDDED {
                      name,
                      holder,
                      miss);
+      return true;
     }
   }
 
  private:
-  void CompileCacheable(MacroAssembler* masm,
+  bool CompileCacheable(MacroAssembler* masm,
                         JSObject* object,
                         Register receiver,
                         Register scratch1,
@@ -570,7 +593,8 @@ class CallInterceptorCompiler BASE_EMBEDDED {
                         LookupResult* lookup,
                         String* name,
                         const CallOptimization& optimization,
-                        Label* miss_label) {
+                        Label* miss_label,
+                        Failure** failure) {
     ASSERT(optimization.is_constant_call());
     ASSERT(!lookup->holder()->IsGlobalObject());
 
@@ -632,7 +656,11 @@ class CallInterceptorCompiler BASE_EMBEDDED {
 
     // Invoke function.
     if (can_do_fast_api_call) {
-      GenerateFastApiCall(masm, optimization, arguments_.immediate());
+      bool success = GenerateFastApiCall(masm, optimization,
+                                         arguments_.immediate(), failure);
+      if (!success) {
+        return false;
+      }
     } else {
       __ InvokeFunction(optimization.constant_function(), arguments_,
                         JUMP_FUNCTION);
@@ -650,6 +678,8 @@ class CallInterceptorCompiler BASE_EMBEDDED {
     if (can_do_fast_api_call) {
       FreeSpaceForFastApiCall(masm, scratch1);
     }
+
+    return true;
   }
 
   void CompileRegular(MacroAssembler* masm,
@@ -905,7 +935,7 @@ Register StubCompiler::CheckPrototypes(JSObject* object,
         MaybeObject* maybe_lookup_result = Heap::LookupSymbol(name);
         Object* lookup_result = NULL;  // Initialization to please compiler.
         if (!maybe_lookup_result->ToObject(&lookup_result)) {
-          set_failure(Failure::cast(lookup_result));
+          set_failure(Failure::cast(maybe_lookup_result));
           return reg;
         }
         name = String::cast(lookup_result);
@@ -1044,46 +1074,55 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object,
 
   Handle<AccessorInfo> callback_handle(callback);
 
-  __ EnterInternalFrame();
-  // Push the stack address where the list of arguments ends.
-  __ mov(scratch2, esp);
-  __ sub(Operand(scratch2), Immediate(2 * kPointerSize));
-  __ push(scratch2);
+  // Insert additional parameters into the stack frame above return address.
+  ASSERT(!scratch3.is(reg));
+  __ pop(scratch3);  // Get return address to place it below.
+
   __ push(receiver);  // receiver
+  __ mov(scratch2, Operand(esp));
+  ASSERT(!scratch2.is(reg));
   __ push(reg);  // holder
   // Push data from AccessorInfo.
   if (Heap::InNewSpace(callback_handle->data())) {
-    __ mov(scratch2, Immediate(callback_handle));
-    __ push(FieldOperand(scratch2, AccessorInfo::kDataOffset));
+    __ mov(scratch1, Immediate(callback_handle));
+    __ push(FieldOperand(scratch1, AccessorInfo::kDataOffset));
   } else {
     __ push(Immediate(Handle<Object>(callback_handle->data())));
   }
-  __ push(name_reg);  // name
+
   // Save a pointer to where we pushed the arguments pointer.
   // This will be passed as the const AccessorInfo& to the C++ callback.
-  __ mov(eax, esp);
-  __ add(Operand(eax), Immediate(4 * kPointerSize));
-  __ mov(ebx, esp);
+  __ push(scratch2);
+
+  __ push(name_reg);  // name
+  __ mov(ebx, esp);  // esp points to reference to name (handler).
+
+  __ push(scratch3);  // Restore return address.
 
   // Do call through the api.
-  ASSERT_EQ(5, ApiGetterEntryStub::kStackSpace);
   Address getter_address = v8::ToCData<Address>(callback->getter());
   ApiFunction fun(getter_address);
-  ApiGetterEntryStub stub(callback_handle, &fun);
+
+  // 3 elements array for v8::Agruments::values_, handler for name and pointer
+  // to the values (it considered as smi in GC).
+  const int kStackSpace = 5;
+  const int kApiArgc = 2;
+
+  __ PrepareCallApiFunction(kApiArgc, eax);
+  __ mov(ApiParameterOperand(0), ebx);  // name.
+  __ add(Operand(ebx), Immediate(kPointerSize));
+  __ mov(ApiParameterOperand(1), ebx);  // arguments pointer.
+
   // Emitting a stub call may try to allocate (if the code is not
   // already generated).  Do not allow the assembler to perform a
   // garbage collection but instead return the allocation failure
   // object.
-  Object* result = NULL;  // Initialization to please compiler.
-  { MaybeObject* try_call_result = masm()->TryCallStub(&stub);
-    if (!try_call_result->ToObject(&result)) {
-      *failure = Failure::cast(result);
-      return false;
-    }
+  MaybeObject* result = masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace);
+  if (result->IsFailure()) {
+    *failure = Failure::cast(result);
+    return false;
   }
-  __ LeaveInternalFrame();
 
-  __ ret(0);
   return true;
 }
 
@@ -2129,7 +2168,10 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
 
       if (depth != kInvalidProtoDepth) {
         __ IncrementCounter(&Counters::call_const_fast_api, 1);
-        ReserveSpaceForFastApiCall(masm(), eax);
+
+        // Allocate space for v8::Arguments implicit values. Must be initialized
+        // before to call any runtime function.
+        __ sub(Operand(esp), Immediate(kFastApiCallArguments * kPointerSize));
       }
 
       // Check that the maps haven't changed.
@@ -2208,7 +2250,17 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
   }
 
   if (depth != kInvalidProtoDepth) {
-    GenerateFastApiCall(masm(), optimization, argc);
+    Failure* failure;
+    // Move the return address on top of the stack.
+    __ mov(eax, Operand(esp, 3 * kPointerSize));
+    __ mov(Operand(esp, 0 * kPointerSize), eax);
+
+    // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains
+    // duplicate of return address and will be overwritten.
+    bool success = GenerateFastApiCall(masm(), optimization, argc, &failure);
+    if (!success) {
+      return failure;
+    }
   } else {
     __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
   }
@@ -2216,7 +2268,7 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
   // Handle call cache miss.
   __ bind(&miss);
   if (depth != kInvalidProtoDepth) {
-    FreeSpaceForFastApiCall(masm(), eax);
+    __ add(Operand(esp), Immediate(kFastApiCallArguments * kPointerSize));
   }
   __ bind(&miss_in_smi_check);
   Object* obj;
@@ -2253,16 +2305,21 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
 
   CallInterceptorCompiler compiler(this, arguments(), ecx);
-  compiler.Compile(masm(),
-                   object,
-                   holder,
-                   name,
-                   &lookup,
-                   edx,
-                   ebx,
-                   edi,
-                   eax,
-                   &miss);
+  Failure* failure;
+  bool success = compiler.Compile(masm(),
+                                  object,
+                                  holder,
+                                  name,
+                                  &lookup,
+                                  edx,
+                                  ebx,
+                                  edi,
+                                  eax,
+                                  &miss,
+                                  &failure);
+  if (!success) {
+    return false;
+  }
 
   // Restore receiver.
   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
index a31f6e836004dd0d196a2aeb11af7510e43c138e..11e1aaf2b387ec1d0818782b8391f460e667f30b 100644 (file)
@@ -33,6 +33,7 @@
 #include "register-allocator-inl.h"
 #include "scopes.h"
 #include "virtual-frame-inl.h"
+#include "stub-cache.h"
 
 namespace v8 {
 namespace internal {
@@ -1108,7 +1109,7 @@ Result VirtualFrame::CallCallIC(RelocInfo::Mode mode,
   // The IC expects the name in ecx and the rest on the stack and
   // drops them all.
   InLoopFlag in_loop = loop_nesting > 0 ? IN_LOOP : NOT_IN_LOOP;
-  Handle<Code> ic = cgen()->ComputeCallInitialize(arg_count, in_loop);
+  Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, in_loop);
   // Spill args, receiver, and function.  The call will drop args and
   // receiver.
   Result name = Pop();
@@ -1126,7 +1127,7 @@ Result VirtualFrame::CallKeyedCallIC(RelocInfo::Mode mode,
   // The IC expects the name in ecx and the rest on the stack and
   // drops them all.
   InLoopFlag in_loop = loop_nesting > 0 ? IN_LOOP : NOT_IN_LOOP;
-  Handle<Code> ic = cgen()->ComputeKeyedCallInitialize(arg_count, in_loop);
+  Handle<Code> ic = StubCache::ComputeKeyedCallInitialize(arg_count, in_loop);
   // Spill args, receiver, and function.  The call will drop args and
   // receiver.
   Result name = Pop();
index e0585e7942900bcaa7d3a56ef3a5b58c39931144..c3c22f1ac63abfb6b9647912b045754d449717c0 100644 (file)
@@ -414,8 +414,9 @@ void BreakTarget::Branch(Condition cc, Hint hint) {
 
 DeferredCode::DeferredCode()
     : masm_(CodeGeneratorScope::Current()->masm()),
-      statement_position_(masm_->current_statement_position()),
-      position_(masm_->current_position()),
+      statement_position_(masm_->positions_recorder()->
+                          current_statement_position()),
+      position_(masm_->positions_recorder()->current_position()),
       frame_state_(CodeGeneratorScope::Current()->frame()) {
   ASSERT(statement_position_ != RelocInfo::kNoPosition);
   ASSERT(position_ != RelocInfo::kNoPosition);
index 19f7bfec0a6f5290b86b221b79cbdb9a9adb66bb..36dc176bce7faa4b4edeb9847fdaa74de2e20eb9 100644 (file)
@@ -36,8 +36,9 @@ namespace internal {
 
 DeferredCode::DeferredCode()
     : masm_(CodeGeneratorScope::Current()->masm()),
-      statement_position_(masm_->current_statement_position()),
-      position_(masm_->current_position()),
+      statement_position_(masm_->positions_recorder()->
+                          current_statement_position()),
+      position_(masm_->positions_recorder()->current_position()),
       frame_state_(*CodeGeneratorScope::Current()->frame()) {
   ASSERT(statement_position_ != RelocInfo::kNoPosition);
   ASSERT(position_ != RelocInfo::kNoPosition);
index 5a08212b1e048f772bcda57db26bfd768d1ef245..24f34945b54d2fb7f90de95bac1ecf701ecc6d5d 100644 (file)
@@ -148,14 +148,6 @@ class List {
   DISALLOW_COPY_AND_ASSIGN(List);
 };
 
-class FrameElement;
-
-// Add() is inlined, ResizeAdd() called by Add() is inlined except for
-// Lists of FrameElements, and ResizeAddInternal() is inlined in ResizeAdd().
-template <>
-void List<FrameElement,
-          FreeStoreAllocationPolicy>::ResizeAdd(const FrameElement& element);
-
 } }  // namespace v8::internal
 
 #endif  // V8_LIST_H_
index 484497f087f418c5fb40f51679568d1bbf99bd13..40194e36125618b85cd50125da628b76d1edf712 100644 (file)
@@ -1099,13 +1099,6 @@ void MarkCompactCollector::MarkLiveObjects() {
 }
 
 
-static int CountMarkedCallback(HeapObject* obj) {
-  MapWord map_word = obj->map_word();
-  map_word.ClearMark();
-  return obj->SizeFromMap(map_word.ToMap());
-}
-
-
 #ifdef DEBUG
 void MarkCompactCollector::UpdateLiveObjectCount(HeapObject* obj) {
   live_bytes_ += obj->Size();
@@ -1152,7 +1145,7 @@ bool MarkCompactCollector::SafeIsMap(HeapObject* object) {
 
 
 void MarkCompactCollector::ClearNonLiveTransitions() {
-  HeapObjectIterator map_iterator(Heap::map_space(), &CountMarkedCallback);
+  HeapObjectIterator map_iterator(Heap::map_space(), &SizeOfMarkedObject);
   // Iterate over the map space, setting map transitions that go from
   // a marked map to an unmarked map to null transitions.  At the same time,
   // set all the prototype fields of maps back to their original value,
@@ -2673,6 +2666,13 @@ void MarkCompactCollector::ReportDeleteIfNeeded(HeapObject* obj) {
 }
 
 
+int MarkCompactCollector::SizeOfMarkedObject(HeapObject* obj) {
+  MapWord map_word = obj->map_word();
+  map_word.ClearMark();
+  return obj->SizeFromMap(map_word.ToMap());
+}
+
+
 void MarkCompactCollector::Initialize() {
   StaticPointersToNewGenUpdatingVisitor::Initialize();
   StaticMarkingVisitor::Initialize();
index 7444c5bf3c27d2f36266ef99e9ec7d052d7a3f1c..1b7e60022e57674093ab5b87a1e53da542759b9a 100644 (file)
@@ -119,6 +119,9 @@ class MarkCompactCollector: public AllStatic {
   // Determine type of object and emit deletion log event.
   static void ReportDeleteIfNeeded(HeapObject* obj);
 
+  // Returns size of a possibly marked object.
+  static int SizeOfMarkedObject(HeapObject* obj);
+
   // Distinguishable invalid map encodings (for single word and multiple words)
   // that indicate free regions.
   static const uint32_t kSingleFreeEncoding = 0;
index c0e5610abaf33f1332bd33e2543c1bda75aa3bfa..69219ee364796fc7b0853552b454147fdd2d81df 100644 (file)
@@ -982,7 +982,6 @@ void AccessorInfo::AccessorInfoVerify() {
   VerifyPointer(name());
   VerifyPointer(data());
   VerifyPointer(flag());
-  VerifyPointer(load_stub_cache());
 }
 
 void AccessorInfo::AccessorInfoPrint() {
@@ -1054,6 +1053,7 @@ void CallHandlerInfo::CallHandlerInfoPrint() {
   callback()->ShortPrint();
   PrintF("\n - data: ");
   data()->ShortPrint();
+  PrintF("\n - call_stub_cache: ");
 }
 
 void TemplateInfo::TemplateInfoVerify() {
index 1852b549bf1802c351297f3363ddac401386e66c..499cb91dde8960fbf4c45ee738be5cecbd6c663d 100644 (file)
@@ -2542,7 +2542,6 @@ ACCESSORS(AccessorInfo, setter, Object, kSetterOffset)
 ACCESSORS(AccessorInfo, data, Object, kDataOffset)
 ACCESSORS(AccessorInfo, name, Object, kNameOffset)
 ACCESSORS(AccessorInfo, flag, Smi, kFlagOffset)
-ACCESSORS(AccessorInfo, load_stub_cache, Object, kLoadStubCacheOffset)
 
 ACCESSORS(AccessCheckInfo, named_callback, Object, kNamedCallbackOffset)
 ACCESSORS(AccessCheckInfo, indexed_callback, Object, kIndexedCallbackOffset)
@@ -2671,6 +2670,7 @@ SMI_ACCESSORS(SharedFunctionInfo, this_property_assignments_count,
 #else
 
 #define PSEUDO_SMI_ACCESSORS_LO(holder, name, offset)             \
+  STATIC_ASSERT(holder::offset % kPointerSize == 0);              \
   int holder::name() {                                            \
     int value = READ_INT_FIELD(this, offset);                     \
     ASSERT(kHeapObjectTag == 1);                                  \
@@ -2686,30 +2686,36 @@ SMI_ACCESSORS(SharedFunctionInfo, this_property_assignments_count,
                     (value << 1) & ~kHeapObjectTag);              \
   }
 
-#define PSEUDO_SMI_ACCESSORS_HI(holder, name, offset) \
+#define PSEUDO_SMI_ACCESSORS_HI(holder, name, offset)             \
+  STATIC_ASSERT(holder::offset % kPointerSize == kIntSize);       \
   INT_ACCESSORS(holder, name, offset)
 
 
-
 PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, length, kLengthOffset)
-PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo, formal_parameter_count,
-              kFormalParameterCountOffset)
+PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo,
+                        formal_parameter_count,
+                        kFormalParameterCountOffset)
 
-PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, expected_nof_properties,
-              kExpectedNofPropertiesOffset)
+PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo,
+                        expected_nof_properties,
+                        kExpectedNofPropertiesOffset)
 PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo, num_literals, kNumLiteralsOffset)
 
-PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, start_position_and_type,
-              kStartPositionAndTypeOffset)
-PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo, end_position, kEndPositionOffset)
-
-PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, function_token_position,
-              kFunctionTokenPositionOffset)
-PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo, compiler_hints,
-              kCompilerHintsOffset)
-
-PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, this_property_assignments_count,
-              kThisPropertyAssignmentsCountOffset)
+PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, end_position, kEndPositionOffset)
+PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo,
+                        start_position_and_type,
+                        kStartPositionAndTypeOffset)
+
+PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo,
+                        function_token_position,
+                        kFunctionTokenPositionOffset)
+PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo,
+                        compiler_hints,
+                        kCompilerHintsOffset)
+
+PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo,
+                        this_property_assignments_count,
+                        kThisPropertyAssignmentsCountOffset)
 #endif
 
 
index c1cb922de55bf831cad9deb8a5a83876d05b65ad..8efb0daae6a8bb52d4655a51a155e71c188e716e 100644 (file)
@@ -35,7 +35,7 @@
 #include "objects-inl.h"
 #include "objects-visiting.h"
 #include "macro-assembler.h"
-#include "scanner.h"
+#include "scanner-base.h"
 #include "scopeinfo.h"
 #include "string-stream.h"
 #include "utils.h"
@@ -1208,7 +1208,8 @@ MaybeObject* JSObject::AddFastProperty(String* name,
   // Normalize the object if the name is an actual string (not the
   // hidden symbols) and is not a real identifier.
   StringInputBuffer buffer(name);
-  if (!Scanner::IsIdentifier(&buffer) && name != Heap::hidden_symbol()) {
+  if (!ScannerConstants::IsIdentifier(&buffer)
+      && name != Heap::hidden_symbol()) {
     Object* obj;
     { MaybeObject* maybe_obj =
           NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
@@ -5088,7 +5089,8 @@ bool String::MarkAsUndetectable() {
 
 bool String::IsEqualTo(Vector<const char> str) {
   int slen = length();
-  Access<Scanner::Utf8Decoder> decoder(Scanner::utf8_decoder());
+  Access<ScannerConstants::Utf8Decoder>
+      decoder(ScannerConstants::utf8_decoder());
   decoder->Reset(str.start(), str.length());
   int i;
   for (i = 0; i < slen && decoder->has_more(); i++) {
index 6029ad545b4a68c08945b9a2b1ad66e5a058b1f4..b52bac27be94158bb50b37a9dc11516a4b2b8ba6 100644 (file)
@@ -5327,7 +5327,6 @@ class AccessorInfo: public Struct {
   DECL_ACCESSORS(data, Object)
   DECL_ACCESSORS(name, Object)
   DECL_ACCESSORS(flag, Smi)
-  DECL_ACCESSORS(load_stub_cache, Object)
 
   inline bool all_can_read();
   inline void set_all_can_read(bool value);
@@ -5353,8 +5352,7 @@ class AccessorInfo: public Struct {
   static const int kDataOffset = kSetterOffset + kPointerSize;
   static const int kNameOffset = kDataOffset + kPointerSize;
   static const int kFlagOffset = kNameOffset + kPointerSize;
-  static const int kLoadStubCacheOffset = kFlagOffset + kPointerSize;
-  static const int kSize = kLoadStubCacheOffset + kPointerSize;
+  static const int kSize = kFlagOffset + kPointerSize;
 
  private:
   // Bit positions in flag.
index aad7a615a514bd3427d18d8f1504b2acfdf514c4..a9ba0e716914fc5ff215efaf0dcdad43337c3dd8 100644 (file)
 #include "messages.h"
 #include "parser.h"
 #include "platform.h"
+#include "preparser.h"
+#include "prescanner.h"
 #include "runtime.h"
 #include "scopeinfo.h"
-#include "scopes.h"
 #include "string-stream.h"
 
 #include "ast-inl.h"
@@ -323,302 +324,96 @@ TemporaryScope::~TemporaryScope() {
 }
 
 
-// A zone list wrapper lets code either access a access a zone list
-// or appear to do so while actually ignoring all operations.
-template <typename T>
-class ZoneListWrapper {
- public:
-  ZoneListWrapper() : list_(NULL) { }
-  explicit ZoneListWrapper(int size) : list_(new ZoneList<T*>(size)) { }
-  void Add(T* that) { if (list_) list_->Add(that); }
-  int length() { return list_->length(); }
-  ZoneList<T*>* elements() { return list_; }
-  T* at(int index) { return list_->at(index); }
- private:
-  ZoneList<T*>* list_;
-};
-
-
-// Allocation macro that should be used to allocate objects that must
-// only be allocated in real parsing mode.  Note that in preparse mode
-// not only is the syntax tree not created but the constructor
-// arguments are not evaluated.
-#define NEW(expr) (is_pre_parsing_ ? NULL : new expr)
-
-
-class ParserFactory BASE_EMBEDDED {
- public:
-  explicit ParserFactory(bool is_pre_parsing) :
-      is_pre_parsing_(is_pre_parsing) { }
-
-  virtual ~ParserFactory() { }
-
-  virtual Scope* NewScope(Scope* parent, Scope::Type type, bool inside_with);
-
-  virtual Handle<String> LookupSymbol(int index, Vector<const char> string) {
-    return Handle<String>();
-  }
-
-  virtual Handle<String> EmptySymbol() {
-    return Handle<String>();
-  }
-
-  virtual Expression* NewProperty(Expression* obj, Expression* key, int pos) {
-    if (obj == VariableProxySentinel::this_proxy()) {
-      return Property::this_property();
-    } else {
-      return ValidLeftHandSideSentinel::instance();
-    }
-  }
-
-  virtual Expression* NewCall(Expression* expression,
-                              ZoneList<Expression*>* arguments,
-                              int pos) {
-    return Call::sentinel();
-  }
-
-  virtual Statement* EmptyStatement() {
-    return NULL;
-  }
-
-  template <typename T> ZoneListWrapper<T> NewList(int size) {
-    return is_pre_parsing_ ? ZoneListWrapper<T>() : ZoneListWrapper<T>(size);
-  }
-
- private:
-  bool is_pre_parsing_;
-};
-
-
-class ParserLog BASE_EMBEDDED {
- public:
-  virtual ~ParserLog() { }
-
-  // Records the occurrence of a function.
-  virtual FunctionEntry LogFunction(int start) { return FunctionEntry(); }
-  virtual void LogSymbol(int start, Vector<const char> symbol) {}
-  virtual void LogError() { }
-  // Return the current position in the function entry log.
-  virtual int function_position() { return 0; }
-  virtual int symbol_position() { return 0; }
-  virtual int symbol_ids() { return 0; }
-  virtual void PauseRecording() {}
-  virtual void ResumeRecording() {}
-  virtual Vector<unsigned> ExtractData() {
-    return Vector<unsigned>();
-  };
-};
-
-
-
-class ConditionalLogPauseScope {
- public:
-  ConditionalLogPauseScope(bool pause, ParserLog* log)
-      : log_(log), pause_(pause) {
-    if (pause) log->PauseRecording();
-  }
-  ~ConditionalLogPauseScope() {
-    if (pause_) log_->ResumeRecording();
-  }
- private:
-  ParserLog* log_;
-  bool pause_;
-};
-
-
-class AstBuildingParserFactory : public ParserFactory {
- public:
-  explicit AstBuildingParserFactory(int expected_symbols)
-      : ParserFactory(false), symbol_cache_(expected_symbols) { }
-
-  virtual Scope* NewScope(Scope* parent, Scope::Type type, bool inside_with);
-
-  virtual Handle<String> LookupSymbol(int symbol_id,
-                                      Vector<const char> string) {
-    // Length of symbol cache is the number of identified symbols.
-    // If we are larger than that, or negative, it's not a cached symbol.
-    // This might also happen if there is no preparser symbol data, even
-    // if there is some preparser data.
-    if (static_cast<unsigned>(symbol_id)
-        >= static_cast<unsigned>(symbol_cache_.length())) {
-      return Factory::LookupSymbol(string);
-    }
-    return LookupCachedSymbol(symbol_id, string);
-  }
-
-  Handle<String> LookupCachedSymbol(int symbol_id,
+Handle<String> Parser::LookupSymbol(int symbol_id,
                                     Vector<const char> string) {
-    // Make sure the cache is large enough to hold the symbol identifier.
-    if (symbol_cache_.length() <= symbol_id) {
-      // Increase length to index + 1.
-      symbol_cache_.AddBlock(Handle<String>::null(),
-                             symbol_id + 1 - symbol_cache_.length());
-    }
-    Handle<String> result = symbol_cache_.at(symbol_id);
-    if (result.is_null()) {
-      result = Factory::LookupSymbol(string);
-      symbol_cache_.at(symbol_id) = result;
-      return result;
-    }
-    Counters::total_preparse_symbols_skipped.Increment();
+  // Length of symbol cache is the number of identified symbols.
+  // If we are larger than that, or negative, it's not a cached symbol.
+  // This might also happen if there is no preparser symbol data, even
+  // if there is some preparser data.
+  if (static_cast<unsigned>(symbol_id)
+      >= static_cast<unsigned>(symbol_cache_.length())) {
+    return Factory::LookupSymbol(string);
+  }
+  return LookupCachedSymbol(symbol_id, string);
+}
+
+
+Handle<String> Parser::LookupCachedSymbol(int symbol_id,
+                                          Vector<const char> string) {
+  // Make sure the cache is large enough to hold the symbol identifier.
+  if (symbol_cache_.length() <= symbol_id) {
+    // Increase length to index + 1.
+    symbol_cache_.AddBlock(Handle<String>::null(),
+                           symbol_id + 1 - symbol_cache_.length());
+  }
+  Handle<String> result = symbol_cache_.at(symbol_id);
+  if (result.is_null()) {
+    result = Factory::LookupSymbol(string);
+    symbol_cache_.at(symbol_id) = result;
     return result;
   }
-
-  virtual Handle<String> EmptySymbol() {
-    return Factory::empty_symbol();
-  }
-
-  virtual Expression* NewProperty(Expression* obj, Expression* key, int pos) {
-    return new Property(obj, key, pos);
-  }
-
-  virtual Expression* NewCall(Expression* expression,
-                              ZoneList<Expression*>* arguments,
-                              int pos) {
-    return new Call(expression, arguments, pos);
-  }
-
-  virtual Statement* EmptyStatement();
- private:
-  List<Handle<String> > symbol_cache_;
-};
+  Counters::total_preparse_symbols_skipped.Increment();
+  return result;
+}
 
 
-// Record only functions.
-class PartialParserRecorder: public ParserLog {
- public:
-  PartialParserRecorder();
-  virtual FunctionEntry LogFunction(int start);
-
-  virtual int function_position() { return function_store_.size(); }
-
-  virtual void LogError() { }
-
-  virtual void LogMessage(Scanner::Location loc,
-                          const char* message,
-                          Vector<const char*> args);
-
-  virtual Vector<unsigned> ExtractData() {
-    int function_size = function_store_.size();
-    int total_size = ScriptDataImpl::kHeaderSize + function_size;
-    Vector<unsigned> data = Vector<unsigned>::New(total_size);
-    preamble_[ScriptDataImpl::kFunctionsSizeOffset] = function_size;
-    preamble_[ScriptDataImpl::kSymbolCountOffset] = 0;
-    memcpy(data.start(), preamble_, sizeof(preamble_));
-    int symbol_start = ScriptDataImpl::kHeaderSize + function_size;
-    if (function_size > 0) {
-      function_store_.WriteTo(data.SubVector(ScriptDataImpl::kHeaderSize,
-                                             symbol_start));
-    }
-    return data;
+Vector<unsigned> PartialParserRecorder::ExtractData() {
+  int function_size = function_store_.size();
+  int total_size = ScriptDataImpl::kHeaderSize + function_size;
+  Vector<unsigned> data = Vector<unsigned>::New(total_size);
+  preamble_[ScriptDataImpl::kFunctionsSizeOffset] = function_size;
+  preamble_[ScriptDataImpl::kSymbolCountOffset] = 0;
+  memcpy(data.start(), preamble_, sizeof(preamble_));
+  int symbol_start = ScriptDataImpl::kHeaderSize + function_size;
+  if (function_size > 0) {
+    function_store_.WriteTo(data.SubVector(ScriptDataImpl::kHeaderSize,
+                                           symbol_start));
   }
+  return data;
+}
 
-  virtual void PauseRecording() {
-    pause_count_++;
-    is_recording_ = false;
-  }
 
-  virtual void ResumeRecording() {
-    ASSERT(pause_count_ > 0);
-    if (--pause_count_ == 0) is_recording_ = !has_error();
-  }
+void CompleteParserRecorder::LogSymbol(int start, Vector<const char> literal) {
+  if (!is_recording_) return;
 
- protected:
-  bool has_error() {
-    return static_cast<bool>(preamble_[ScriptDataImpl::kHasErrorOffset]);
+  int hash = vector_hash(literal);
+  HashMap::Entry* entry = symbol_table_.Lookup(&literal, hash, true);
+  int id = static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
+  if (id == 0) {
+    // Put (symbol_id_ + 1) into entry and increment it.
+    id = ++symbol_id_;
+    entry->value = reinterpret_cast<void*>(id);
+    Vector<Vector<const char> > symbol = symbol_entries_.AddBlock(1, literal);
+    entry->key = &symbol[0];
   }
-  bool is_recording() {
-    return is_recording_;
-  }
-
-  void WriteString(Vector<const char> str);
-
-  Collector<unsigned> function_store_;
-  unsigned preamble_[ScriptDataImpl::kHeaderSize];
-  bool is_recording_;
-  int pause_count_;
-
-#ifdef DEBUG
-  int prev_start;
-#endif
-};
-
+  WriteNumber(id - 1);
+}
 
-// Record both functions and symbols.
-class CompleteParserRecorder: public PartialParserRecorder {
- public:
-  CompleteParserRecorder();
-
-  virtual void LogSymbol(int start, Vector<const char> literal) {
-    if (!is_recording_) return;
-    int hash = vector_hash(literal);
-    HashMap::Entry* entry = symbol_table_.Lookup(&literal, hash, true);
-    int id = static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
-    if (id == 0) {
-      // Put (symbol_id_ + 1) into entry and increment it.
-      id = ++symbol_id_;
-      entry->value = reinterpret_cast<void*>(id);
-      Vector<Vector<const char> > symbol = symbol_entries_.AddBlock(1, literal);
-      entry->key = &symbol[0];
-    }
-    WriteNumber(id - 1);
-  }
-
-  virtual Vector<unsigned> ExtractData() {
-    int function_size = function_store_.size();
-    // Add terminator to symbols, then pad to unsigned size.
-    int symbol_size = symbol_store_.size();
-    int padding = sizeof(unsigned) - (symbol_size % sizeof(unsigned));
-    symbol_store_.AddBlock(padding, ScriptDataImpl::kNumberTerminator);
-    symbol_size += padding;
-    int total_size = ScriptDataImpl::kHeaderSize + function_size
-        + (symbol_size / sizeof(unsigned));
-    Vector<unsigned> data = Vector<unsigned>::New(total_size);
-    preamble_[ScriptDataImpl::kFunctionsSizeOffset] = function_size;
-    preamble_[ScriptDataImpl::kSymbolCountOffset] = symbol_id_;
-    memcpy(data.start(), preamble_, sizeof(preamble_));
-    int symbol_start = ScriptDataImpl::kHeaderSize + function_size;
-    if (function_size > 0) {
-      function_store_.WriteTo(data.SubVector(ScriptDataImpl::kHeaderSize,
-                                             symbol_start));
-    }
-    if (!has_error()) {
-      symbol_store_.WriteTo(
-          Vector<byte>::cast(data.SubVector(symbol_start, total_size)));
-    }
-    return data;
-  }
 
-  virtual int symbol_position() { return symbol_store_.size(); }
-  virtual int symbol_ids() { return symbol_id_; }
- private:
-    static int vector_hash(Vector<const char> string) {
-    int hash = 0;
-    for (int i = 0; i < string.length(); i++) {
-      int c = string[i];
-      hash += c;
-      hash += (hash << 10);
-      hash ^= (hash >> 6);
-    }
-    return hash;
+Vector<unsigned> CompleteParserRecorder::ExtractData() {
+  int function_size = function_store_.size();
+  // Add terminator to symbols, then pad to unsigned size.
+  int symbol_size = symbol_store_.size();
+  int padding = sizeof(unsigned) - (symbol_size % sizeof(unsigned));
+  symbol_store_.AddBlock(padding, ScriptDataImpl::kNumberTerminator);
+  symbol_size += padding;
+  int total_size = ScriptDataImpl::kHeaderSize + function_size
+      + (symbol_size / sizeof(unsigned));
+  Vector<unsigned> data = Vector<unsigned>::New(total_size);
+  preamble_[ScriptDataImpl::kFunctionsSizeOffset] = function_size;
+  preamble_[ScriptDataImpl::kSymbolCountOffset] = symbol_id_;
+  memcpy(data.start(), preamble_, sizeof(preamble_));
+  int symbol_start = ScriptDataImpl::kHeaderSize + function_size;
+  if (function_size > 0) {
+    function_store_.WriteTo(data.SubVector(ScriptDataImpl::kHeaderSize,
+                                           symbol_start));
   }
-
-  static bool vector_compare(void* a, void* b) {
-    Vector<const char>* string1 = reinterpret_cast<Vector<const char>* >(a);
-    Vector<const char>* string2 = reinterpret_cast<Vector<const char>* >(b);
-    int length = string1->length();
-    if (string2->length() != length) return false;
-    return memcmp(string1->start(), string2->start(), length) == 0;
+  if (!has_error()) {
+    symbol_store_.WriteTo(
+        Vector<byte>::cast(data.SubVector(symbol_start, total_size)));
   }
-
-  // Write a non-negative number to the symbol store.
-  void WriteNumber(int number);
-
-  Collector<byte> symbol_store_;
-  Collector<Vector<const char> > symbol_entries_;
-  HashMap symbol_table_;
-  int symbol_id_;
-};
+  return data;
+}
 
 
 FunctionEntry ScriptDataImpl::GetFunctionEntry(int start) {
@@ -691,7 +486,7 @@ PartialParserRecorder::PartialParserRecorder()
   preamble_[ScriptDataImpl::kSizeOffset] = 0;
   ASSERT_EQ(6, ScriptDataImpl::kHeaderSize);
 #ifdef DEBUG
-  prev_start = -1;
+  prev_start_ = -1;
 #endif
 }
 
@@ -742,8 +537,8 @@ const char* ScriptDataImpl::ReadString(unsigned* start, int* chars) {
 
 
 void PartialParserRecorder::LogMessage(Scanner::Location loc,
-                                      const char* message,
-                                      Vector<const char*> args) {
+                                       const char* message,
+                                       Vector<const char*> args) {
   if (has_error()) return;
   preamble_[ScriptDataImpl::kHasErrorOffset] = true;
   function_store_.Reset();
@@ -800,120 +595,12 @@ unsigned* ScriptDataImpl::ReadAddress(int position) {
 }
 
 
-FunctionEntry PartialParserRecorder::LogFunction(int start) {
-#ifdef DEBUG
-  ASSERT(start > prev_start);
-  prev_start = start;
-#endif
-  if (!is_recording_) return FunctionEntry();
-  FunctionEntry result(function_store_.AddBlock(FunctionEntry::kSize, 0));
-  result.set_start_pos(start);
-  return result;
-}
-
-
-class AstBuildingParser : public Parser {
- public:
-  AstBuildingParser(Handle<Script> script, bool allow_natives_syntax,
-                    v8::Extension* extension, ScriptDataImpl* pre_data)
-      : Parser(script,
-               allow_natives_syntax,
-               extension,
-               PARSE,
-               factory(),
-               log(),
-               pre_data),
-        factory_(pre_data ? pre_data->symbol_count() : 0) { }
-  virtual void ReportMessageAt(Scanner::Location loc, const char* message,
-                               Vector<const char*> args);
-  virtual VariableProxy* Declare(Handle<String> name, Variable::Mode mode,
-                                 FunctionLiteral* fun, bool resolve, bool* ok);
-  AstBuildingParserFactory* factory() { return &factory_; }
-  ParserLog* log() { return &log_; }
-
- private:
-  ParserLog log_;
-  AstBuildingParserFactory factory_;
-};
-
-
-class PreParser : public Parser {
- public:
-  PreParser(Handle<Script> script, bool allow_natives_syntax,
-            v8::Extension* extension, ParserLog* recorder)
-      : Parser(script, allow_natives_syntax, extension, PREPARSE,
-               factory(), recorder, NULL),
-        factory_(true) { }
-  virtual void ReportMessageAt(Scanner::Location loc, const char* message,
-                               Vector<const char*> args);
-  virtual VariableProxy* Declare(Handle<String> name, Variable::Mode mode,
-                                 FunctionLiteral* fun, bool resolve, bool* ok);
-  ParserFactory* factory() { return &factory_; }
-  virtual PartialParserRecorder* recorder() = 0;
-
- private:
-  ParserFactory factory_;
-};
-
-
-class CompletePreParser : public PreParser {
- public:
-  CompletePreParser(Handle<Script> script, bool allow_natives_syntax,
-                    v8::Extension* extension)
-      : PreParser(script, allow_natives_syntax, extension, &recorder_),
-        recorder_()  { }
-  virtual PartialParserRecorder* recorder() { return &recorder_; }
- private:
-  CompleteParserRecorder recorder_;
-};
-
-
-class PartialPreParser : public PreParser {
- public:
-  PartialPreParser(Handle<Script> script, bool allow_natives_syntax,
-                   v8::Extension* extension)
-      : PreParser(script, allow_natives_syntax, extension, &recorder_),
-        recorder_() { }
-  virtual PartialParserRecorder* recorder() { return &recorder_; }
- private:
-  PartialParserRecorder recorder_;
-};
-
-
-Scope* AstBuildingParserFactory::NewScope(Scope* parent, Scope::Type type,
-                                          bool inside_with) {
+Scope* Parser::NewScope(Scope* parent, Scope::Type type, bool inside_with) {
   Scope* result = new Scope(parent, type);
   result->Initialize(inside_with);
   return result;
 }
 
-
-Statement* AstBuildingParserFactory::EmptyStatement() {
-  // Use a statically allocated empty statement singleton to avoid
-  // allocating lots and lots of empty statements.
-  static v8::internal::EmptyStatement empty;
-  return &empty;
-}
-
-
-Scope* ParserFactory::NewScope(Scope* parent, Scope::Type type,
-                               bool inside_with) {
-  ASSERT(parent != NULL);
-  parent->type_ = type;
-  // Initialize function is hijacked by DummyScope to increment scope depth.
-  parent->Initialize(inside_with);
-  return parent;
-}
-
-
-VariableProxy* PreParser::Declare(Handle<String> name, Variable::Mode mode,
-                                  FunctionLiteral* fun, bool resolve,
-                                  bool* ok) {
-  return NULL;
-}
-
-
-
 // ----------------------------------------------------------------------------
 // Target is a support class to facilitate manipulation of the
 // Parser's target_stack_ (the stack of potential 'break' and
@@ -1016,11 +703,9 @@ class LexicalScope BASE_EMBEDDED {
 Parser::Parser(Handle<Script> script,
                bool allow_natives_syntax,
                v8::Extension* extension,
-               ParserMode is_pre_parsing,
-               ParserFactory* factory,
-               ParserLog* log,
                ScriptDataImpl* pre_data)
-    : script_(script),
+    : symbol_cache_(pre_data ? pre_data->symbol_count() : 0),
+      script_(script),
       scanner_(),
       top_scope_(NULL),
       with_nesting_level_(0),
@@ -1028,34 +713,11 @@ Parser::Parser(Handle<Script> script,
       target_stack_(NULL),
       allow_natives_syntax_(allow_natives_syntax),
       extension_(extension),
-      factory_(factory),
-      log_(log),
-      is_pre_parsing_(is_pre_parsing == PREPARSE),
       pre_data_(pre_data),
       fni_(NULL) {
 }
 
 
-bool Parser::PreParseProgram(Handle<String> source,
-                             unibrow::CharacterStream* stream) {
-  HistogramTimerScope timer(&Counters::pre_parse);
-  AssertNoZoneAllocation assert_no_zone_allocation;
-  AssertNoAllocation assert_no_allocation;
-  NoHandleAllocation no_handle_allocation;
-  scanner_.Initialize(source, stream, JAVASCRIPT);
-  ASSERT(target_stack_ == NULL);
-  mode_ = FLAG_lazy ? PARSE_LAZILY : PARSE_EAGERLY;
-  if (allow_natives_syntax_ || extension_ != NULL) mode_ = PARSE_EAGERLY;
-  DummyScope top_scope;
-  LexicalScope scope(&this->top_scope_, &this->with_nesting_level_, &top_scope);
-  TemporaryScope temp_scope(&this->temp_scope_);
-  ZoneListWrapper<Statement> processor;
-  bool ok = true;
-  ParseSourceElements(&processor, Token::EOS, &ok);
-  return !scanner().stack_overflow();
-}
-
-
 FunctionLiteral* Parser::ParseProgram(Handle<String> source,
                                       bool in_global_context) {
   CompilationZoneScope zone_scope(DONT_DELETE_ON_EXIT);
@@ -1078,21 +740,21 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source,
     in_global_context
       ? Scope::GLOBAL_SCOPE
       : Scope::EVAL_SCOPE;
-  Handle<String> no_name = factory()->EmptySymbol();
+  Handle<String> no_name = Factory::empty_symbol();
 
   FunctionLiteral* result = NULL;
-  { Scope* scope = factory()->NewScope(top_scope_, type, inside_with());
+  { Scope* scope = NewScope(top_scope_, type, inside_with());
     LexicalScope lexical_scope(&this->top_scope_, &this->with_nesting_level_,
                                scope);
     TemporaryScope temp_scope(&this->temp_scope_);
-    ZoneListWrapper<Statement> body(16);
+    ZoneList<Statement*>* body = new ZoneList<Statement*>(16);
     bool ok = true;
-    ParseSourceElements(&body, Token::EOS, &ok);
+    ParseSourceElements(body, Token::EOS, &ok);
     if (ok) {
-      result = NEW(FunctionLiteral(
+      result = new FunctionLiteral(
           no_name,
           top_scope_,
-          body.elements(),
+          body,
           temp_scope.materialized_literal_count(),
           temp_scope.expected_property_count(),
           temp_scope.only_simple_this_property_assignments(),
@@ -1101,7 +763,7 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source,
           0,
           source->length(),
           false,
-          temp_scope.ContainsLoops()));
+          temp_scope.ContainsLoops());
     } else if (scanner().stack_overflow()) {
       Top::StackOverflow();
     }
@@ -1139,9 +801,9 @@ FunctionLiteral* Parser::ParseLazy(Handle<SharedFunctionInfo> info) {
 
   {
     // Parse the function literal.
-    Handle<String> no_name = factory()->EmptySymbol();
+    Handle<String> no_name = Factory::empty_symbol();
     Scope* scope =
-        factory()->NewScope(top_scope_, Scope::GLOBAL_SCOPE, inside_with());
+        NewScope(top_scope_, Scope::GLOBAL_SCOPE, inside_with());
     LexicalScope lexical_scope(&this->top_scope_, &this->with_nesting_level_,
                                scope);
     TemporaryScope temp_scope(&this->temp_scope_);
@@ -1169,28 +831,24 @@ FunctionLiteral* Parser::ParseLazy(Handle<SharedFunctionInfo> info) {
 }
 
 
-void Parser::ReportMessage(const char* type, Vector<const char*> args) {
-  Scanner::Location source_location = scanner_.location();
-  ReportMessageAt(source_location, type, args);
-}
-
-
 Handle<String> Parser::GetSymbol(bool* ok) {
-  if (is_pre_parsing_) {
-    log()->LogSymbol(scanner_.location().beg_pos, scanner_.literal());
-    return Handle<String>::null();
-  }
   int symbol_id = -1;
   if (pre_data() != NULL) {
     symbol_id = pre_data()->GetSymbolIdentifier();
   }
-  return factory()->LookupSymbol(symbol_id, scanner_.literal());
+  return LookupSymbol(symbol_id, scanner_.literal());
+}
+
+
+void Parser::ReportMessage(const char* type, Vector<const char*> args) {
+  Scanner::Location source_location = scanner_.location();
+  ReportMessageAt(source_location, type, args);
 }
 
 
-void AstBuildingParser::ReportMessageAt(Scanner::Location source_location,
-                                        const char* type,
-                                        Vector<const char*> args) {
+void Parser::ReportMessageAt(Scanner::Location source_location,
+                             const char* type,
+                             Vector<const char*> args) {
   MessageLocation location(script_,
                            source_location.beg_pos, source_location.end_pos);
   Handle<JSArray> array = Factory::NewJSArray(args.length());
@@ -1202,13 +860,6 @@ void AstBuildingParser::ReportMessageAt(Scanner::Location source_location,
 }
 
 
-void PreParser::ReportMessageAt(Scanner::Location source_location,
-                                const char* type,
-                                Vector<const char*> args) {
-  recorder()->LogMessage(source_location, type, args);
-}
-
-
 // Base class containing common code for the different finder classes used by
 // the parser.
 class ParserFinder {
@@ -1250,6 +901,11 @@ class InitializationBlockFinder : public ParserFinder {
   }
 
  private:
+  // The minimum number of contiguous assignment that will
+  // be treated as an initialization block. Benchmarks show that
+  // the overhead exceeds the savings below this limit.
+  static const int kMinInitializationBlock = 3;
+
   // Returns true if the expressions appear to denote the same object.
   // In the context of initialization blocks, we only consider expressions
   // of the form 'expr.x' or expr["x"].
@@ -1302,7 +958,7 @@ class InitializationBlockFinder : public ParserFinder {
   }
 
   void EndBlock() {
-    if (block_size_ >= Parser::kMinInitializationBlock) {
+    if (block_size_ >= kMinInitializationBlock) {
       first_in_block_->mark_block_start();
       last_in_block_->mark_block_end();
     }
@@ -1460,7 +1116,7 @@ class ThisNamedPropertyAssigmentFinder : public ParserFinder {
 };
 
 
-void* Parser::ParseSourceElements(ZoneListWrapper<Statement>* processor,
+void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
                                   int end_token,
                                   bool* ok) {
   // SourceElements ::
@@ -1492,7 +1148,7 @@ void* Parser::ParseSourceElements(ZoneListWrapper<Statement>* processor,
   }
 
   // Propagate the collected information on this property assignments.
-  if (!is_pre_parsing_ && top_scope_->is_function_scope()) {
+  if (top_scope_->is_function_scope()) {
     bool only_simple_this_property_assignments =
         this_property_assignment_finder.only_simple_this_property_assignments()
         && top_scope_->declarations()->length() == 0;
@@ -1545,7 +1201,7 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) {
 
     case Token::SEMICOLON:
       Next();
-      return factory()->EmptyStatement();
+      return EmptyStatement();
 
     case Token::IF:
       stmt = ParseIfStatement(labels, ok);
@@ -1593,7 +1249,7 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) {
       // one must take great care not to treat it as a
       // fall-through. It is much easier just to wrap the entire
       // try-statement in a statement block and put the labels there
-      Block* result = NEW(Block(labels, 1, false));
+      Block* result = new Block(labels, 1, false);
       Target target(&this->target_stack_, result);
       TryStatement* statement = ParseTryStatement(CHECK_OK);
       if (statement) {
@@ -1623,11 +1279,11 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) {
 }
 
 
-VariableProxy* AstBuildingParser::Declare(Handle<String> name,
-                                          Variable::Mode mode,
-                                          FunctionLiteral* fun,
-                                          bool resolve,
-                                          bool* ok) {
+VariableProxy* Parser::Declare(Handle<String> name,
+                               Variable::Mode mode,
+                               FunctionLiteral* fun,
+                               bool resolve,
+                               bool* ok) {
   Variable* var = NULL;
   // If we are inside a function, a declaration of a variable
   // is a truly local variable, and the scope of the variable
@@ -1682,13 +1338,13 @@ VariableProxy* AstBuildingParser::Declare(Handle<String> name,
   // a performance issue since it may lead to repeated
   // Runtime::DeclareContextSlot() calls.
   VariableProxy* proxy = top_scope_->NewUnresolved(name, inside_with());
-  top_scope_->AddDeclaration(NEW(Declaration(proxy, mode, fun)));
+  top_scope_->AddDeclaration(new Declaration(proxy, mode, fun));
 
   // For global const variables we bind the proxy to a variable.
   if (mode == Variable::CONST && top_scope_->is_global_scope()) {
     ASSERT(resolve);  // should be set by all callers
     Variable::Kind kind = Variable::NORMAL;
-    var = NEW(Variable(top_scope_, name, Variable::CONST, true, kind));
+    var = new Variable(top_scope_, name, Variable::CONST, true, kind);
   }
 
   // If requested and we have a local variable, bind the proxy to the variable
@@ -1740,13 +1396,13 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) {
   while (!done) {
     ParseIdentifier(CHECK_OK);
     done = (peek() == Token::RPAREN);
-    if (!done) Expect(Token::COMMA, CHECK_OK);
+    if (!done) {
+      Expect(Token::COMMA, CHECK_OK);
+    }
   }
   Expect(Token::RPAREN, CHECK_OK);
   Expect(Token::SEMICOLON, CHECK_OK);
 
-  if (is_pre_parsing_) return NULL;
-
   // Make sure that the function containing the native declaration
   // isn't lazily compiled. The extension structures are only
   // accessible while parsing the first time not when reparsing
@@ -1776,10 +1432,10 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) {
   // TODO(1240846): It's weird that native function declarations are
   // introduced dynamically when we meet their declarations, whereas
   // other functions are setup when entering the surrounding scope.
-  SharedFunctionInfoLiteral* lit = NEW(SharedFunctionInfoLiteral(shared));
+  SharedFunctionInfoLiteral* lit = new SharedFunctionInfoLiteral(shared);
   VariableProxy* var = Declare(name, Variable::VAR, NULL, true, CHECK_OK);
-  return NEW(ExpressionStatement(
-      new Assignment(Token::INIT_VAR, var, lit, RelocInfo::kNoPosition)));
+  return new ExpressionStatement(
+      new Assignment(Token::INIT_VAR, var, lit, RelocInfo::kNoPosition));
 }
 
 
@@ -1797,7 +1453,7 @@ Statement* Parser::ParseFunctionDeclaration(bool* ok) {
   // scope, we treat is as such and introduce the function with it's
   // initial value upon entering the corresponding scope.
   Declare(name, Variable::VAR, fun, true, CHECK_OK);
-  return factory()->EmptyStatement();
+  return EmptyStatement();
 }
 
 
@@ -1809,7 +1465,7 @@ Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) {
   // (ECMA-262, 3rd, 12.2)
   //
   // Construct block expecting 16 statements.
-  Block* result = NEW(Block(labels, 16, false));
+  Block* result = new Block(labels, 16, false);
   Target target(&this->target_stack_, result);
   Expect(Token::LBRACE, CHECK_OK);
   while (peek() != Token::RBRACE) {
@@ -1868,7 +1524,7 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
   // is inside an initializer block, it is ignored.
   //
   // Create new block with one expected declaration.
-  Block* block = NEW(Block(NULL, 1, true));
+  Block* block = new Block(NULL, 1, true);
   VariableProxy* last_var = NULL;  // the last variable declared
   int nvars = 0;  // the number of variables declared
   do {
@@ -1959,14 +1615,14 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
     // browsers where the global object (window) has lots of
     // properties defined in prototype objects.
 
-    if (!is_pre_parsing_ && top_scope_->is_global_scope()) {
+    if (top_scope_->is_global_scope()) {
       // Compute the arguments for the runtime call.
       ZoneList<Expression*>* arguments = new ZoneList<Expression*>(2);
       // Be careful not to assign a value to the global variable if
       // we're in a with. The initialization value should not
       // necessarily be stored in the global object in that case,
       // which is why we need to generate a separate assignment node.
-      arguments->Add(NEW(Literal(name)));  // we have at least 1 parameter
+      arguments->Add(new Literal(name));  // we have at least 1 parameter
       if (is_const || (value != NULL && !inside_with())) {
         arguments->Add(value);
         value = NULL;  // zap the value to avoid the unnecessary assignment
@@ -1978,18 +1634,18 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
       CallRuntime* initialize;
       if (is_const) {
         initialize =
-          NEW(CallRuntime(
+          new CallRuntime(
             Factory::InitializeConstGlobal_symbol(),
             Runtime::FunctionForId(Runtime::kInitializeConstGlobal),
-            arguments));
+            arguments);
       } else {
         initialize =
-          NEW(CallRuntime(
+          new CallRuntime(
             Factory::InitializeVarGlobal_symbol(),
             Runtime::FunctionForId(Runtime::kInitializeVarGlobal),
-            arguments));
+            arguments);
       }
-      block->AddStatement(NEW(ExpressionStatement(initialize)));
+      block->AddStatement(new ExpressionStatement(initialize));
     }
 
     // Add an assignment node to the initialization statement block if
@@ -2004,8 +1660,8 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
     // the top context for variables). Sigh...
     if (value != NULL) {
       Token::Value op = (is_const ? Token::INIT_CONST : Token::INIT_VAR);
-      Assignment* assignment = NEW(Assignment(op, last_var, value, position));
-      if (block) block->AddStatement(NEW(ExpressionStatement(assignment)));
+      Assignment* assignment = new Assignment(op, last_var, value, position);
+      if (block) block->AddStatement(new ExpressionStatement(assignment));
     }
 
     if (fni_ != NULL) fni_->Leave();
@@ -2013,14 +1669,8 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
 
   if (!is_const && nvars == 1) {
     // We have a single, non-const variable.
-    if (is_pre_parsing_) {
-      // If we're preparsing then we need to set the var to something
-      // in order for for-in loops to parse correctly.
-      *var = ValidLeftHandSideSentinel::instance();
-    } else {
-      ASSERT(last_var != NULL);
-      *var = last_var;
-    }
+    ASSERT(last_var != NULL);
+    *var = last_var;
   }
 
   return block;
@@ -2043,11 +1693,13 @@ Statement* Parser::ParseExpressionOrLabelledStatement(ZoneStringList* labels,
   // ExpressionStatement | LabelledStatement ::
   //   Expression ';'
   //   Identifier ':' Statement
-
+  bool starts_with_idenfifier = (peek() == Token::IDENTIFIER);
   Expression* expr = ParseExpression(true, CHECK_OK);
-  if (peek() == Token::COLON && expr &&
+  if (peek() == Token::COLON && starts_with_idenfifier && expr &&
       expr->AsVariableProxy() != NULL &&
       !expr->AsVariableProxy()->is_this()) {
+    // Expression is a single identifier, and not, e.g., a parenthesized
+    // identifier.
     VariableProxy* var = expr->AsVariableProxy();
     Handle<String> label = var->name();
     // TODO(1240780): We don't check for redeclaration of labels
@@ -2055,29 +1707,27 @@ Statement* Parser::ParseExpressionOrLabelledStatement(ZoneStringList* labels,
     // labels requires nontrivial changes to the way scopes are
     // structured.  However, these are probably changes we want to
     // make later anyway so we should go back and fix this then.
-    if (!is_pre_parsing_) {
-      if (ContainsLabel(labels, label) || TargetStackContainsLabel(label)) {
-        SmartPointer<char> c_string = label->ToCString(DISALLOW_NULLS);
-        const char* elms[2] = { "Label", *c_string };
-        Vector<const char*> args(elms, 2);
-        ReportMessage("redeclaration", args);
-        *ok = false;
-        return NULL;
-      }
-      if (labels == NULL) labels = new ZoneStringList(4);
-      labels->Add(label);
-      // Remove the "ghost" variable that turned out to be a label
-      // from the top scope. This way, we don't try to resolve it
-      // during the scope processing.
-      top_scope_->RemoveUnresolved(var);
+    if (ContainsLabel(labels, label) || TargetStackContainsLabel(label)) {
+      SmartPointer<char> c_string = label->ToCString(DISALLOW_NULLS);
+      const char* elms[2] = { "Label", *c_string };
+      Vector<const char*> args(elms, 2);
+      ReportMessage("redeclaration", args);
+      *ok = false;
+      return NULL;
     }
+    if (labels == NULL) labels = new ZoneStringList(4);
+    labels->Add(label);
+    // Remove the "ghost" variable that turned out to be a label
+    // from the top scope. This way, we don't try to resolve it
+    // during the scope processing.
+    top_scope_->RemoveUnresolved(var);
     Expect(Token::COLON, CHECK_OK);
     return ParseStatement(labels, ok);
   }
 
   // Parsed expression statement.
   ExpectSemicolon(CHECK_OK);
-  return NEW(ExpressionStatement(expr));
+  return new ExpressionStatement(expr);
 }
 
 
@@ -2094,10 +1744,10 @@ IfStatement* Parser::ParseIfStatement(ZoneStringList* labels, bool* ok) {
   if (peek() == Token::ELSE) {
     Next();
     else_statement = ParseStatement(labels, CHECK_OK);
-  } else if (!is_pre_parsing_) {
-    else_statement = factory()->EmptyStatement();
+  } else {
+    else_statement = EmptyStatement();
   }
-  return NEW(IfStatement(condition, then_statement, else_statement));
+  return new IfStatement(condition, then_statement, else_statement);
 }
 
 
@@ -2113,19 +1763,17 @@ Statement* Parser::ParseContinueStatement(bool* ok) {
     label = ParseIdentifier(CHECK_OK);
   }
   IterationStatement* target = NULL;
-  if (!is_pre_parsing_) {
-    target = LookupContinueTarget(label, CHECK_OK);
-    if (target == NULL) {
-      // Illegal continue statement.  To be consistent with KJS we delay
-      // reporting of the syntax error until runtime.
-      Handle<String> error_type = Factory::illegal_continue_symbol();
-      if (!label.is_null()) error_type = Factory::unknown_label_symbol();
-      Expression* throw_error = NewThrowSyntaxError(error_type, label);
-      return NEW(ExpressionStatement(throw_error));
-    }
+  target = LookupContinueTarget(label, CHECK_OK);
+  if (target == NULL) {
+    // Illegal continue statement.  To be consistent with KJS we delay
+    // reporting of the syntax error until runtime.
+    Handle<String> error_type = Factory::illegal_continue_symbol();
+    if (!label.is_null()) error_type = Factory::unknown_label_symbol();
+    Expression* throw_error = NewThrowSyntaxError(error_type, label);
+    return new ExpressionStatement(throw_error);
   }
   ExpectSemicolon(CHECK_OK);
-  return NEW(ContinueStatement(target));
+  return new ContinueStatement(target);
 }
 
 
@@ -2143,22 +1791,20 @@ Statement* Parser::ParseBreakStatement(ZoneStringList* labels, bool* ok) {
   // Parse labeled break statements that target themselves into
   // empty statements, e.g. 'l1: l2: l3: break l2;'
   if (!label.is_null() && ContainsLabel(labels, label)) {
-    return factory()->EmptyStatement();
+    return EmptyStatement();
   }
   BreakableStatement* target = NULL;
-  if (!is_pre_parsing_) {
-    target = LookupBreakTarget(label, CHECK_OK);
-    if (target == NULL) {
-      // Illegal break statement.  To be consistent with KJS we delay
-      // reporting of the syntax error until runtime.
-      Handle<String> error_type = Factory::illegal_break_symbol();
-      if (!label.is_null()) error_type = Factory::unknown_label_symbol();
-      Expression* throw_error = NewThrowSyntaxError(error_type, label);
-      return NEW(ExpressionStatement(throw_error));
-    }
+  target = LookupBreakTarget(label, CHECK_OK);
+  if (target == NULL) {
+    // Illegal break statement.  To be consistent with KJS we delay
+    // reporting of the syntax error until runtime.
+    Handle<String> error_type = Factory::illegal_break_symbol();
+    if (!label.is_null()) error_type = Factory::unknown_label_symbol();
+    Expression* throw_error = NewThrowSyntaxError(error_type, label);
+    return new ExpressionStatement(throw_error);
   }
   ExpectSemicolon(CHECK_OK);
-  return NEW(BreakStatement(target));
+  return new BreakStatement(target);
 }
 
 
@@ -2176,10 +1822,10 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
   // function. See ECMA-262, section 12.9, page 67.
   //
   // To be consistent with KJS we report the syntax error at runtime.
-  if (!is_pre_parsing_ && !top_scope_->is_function_scope()) {
+  if (!top_scope_->is_function_scope()) {
     Handle<String> type = Factory::illegal_return_symbol();
     Expression* throw_error = NewThrowSyntaxError(type, Handle<Object>::null());
-    return NEW(ExpressionStatement(throw_error));
+    return new ExpressionStatement(throw_error);
   }
 
   Token::Value tok = peek();
@@ -2188,12 +1834,12 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
       tok == Token::RBRACE ||
       tok == Token::EOS) {
     ExpectSemicolon(CHECK_OK);
-    return NEW(ReturnStatement(GetLiteralUndefined()));
+    return new ReturnStatement(GetLiteralUndefined());
   }
 
   Expression* expr = ParseExpression(true, CHECK_OK);
   ExpectSemicolon(CHECK_OK);
-  return NEW(ReturnStatement(expr));
+  return new ReturnStatement(expr);
 }
 
 
@@ -2202,7 +1848,7 @@ Block* Parser::WithHelper(Expression* obj,
                           bool is_catch_block,
                           bool* ok) {
   // Parse the statement and collect escaping labels.
-  ZoneList<BreakTarget*>* target_list = NEW(ZoneList<BreakTarget*>(0));
+  ZoneList<BreakTarget*>* target_list = new ZoneList<BreakTarget*>(0);
   TargetCollector collector(target_list);
   Statement* stat;
   { Target target(&this->target_stack_, &collector);
@@ -2214,21 +1860,21 @@ Block* Parser::WithHelper(Expression* obj,
   // Create resulting block with two statements.
   // 1: Evaluate the with expression.
   // 2: The try-finally block evaluating the body.
-  Block* result = NEW(Block(NULL, 2, false));
+  Block* result = new Block(NULL, 2, false);
 
   if (result != NULL) {
-    result->AddStatement(NEW(WithEnterStatement(obj, is_catch_block)));
+    result->AddStatement(new WithEnterStatement(obj, is_catch_block));
 
     // Create body block.
-    Block* body = NEW(Block(NULL, 1, false));
+    Block* body = new Block(NULL, 1, false);
     body->AddStatement(stat);
 
     // Create exit block.
-    Block* exit = NEW(Block(NULL, 1, false));
-    exit->AddStatement(NEW(WithExitStatement()));
+    Block* exit = new Block(NULL, 1, false);
+    exit->AddStatement(new WithExitStatement());
 
     // Return a try-finally statement.
-    TryFinallyStatement* wrapper = NEW(TryFinallyStatement(body, exit));
+    TryFinallyStatement* wrapper = new TryFinallyStatement(body, exit);
     wrapper->set_escaping_targets(collector.targets());
     result->AddStatement(wrapper);
   }
@@ -2270,15 +1916,15 @@ CaseClause* Parser::ParseCaseClause(bool* default_seen_ptr, bool* ok) {
   }
   Expect(Token::COLON, CHECK_OK);
 
-  ZoneListWrapper<Statement> statements = factory()->NewList<Statement>(5);
+  ZoneList<Statement*>* statements = new ZoneList<Statement*>(5);
   while (peek() != Token::CASE &&
          peek() != Token::DEFAULT &&
          peek() != Token::RBRACE) {
     Statement* stat = ParseStatement(NULL, CHECK_OK);
-    statements.Add(stat);
+    statements->Add(stat);
   }
 
-  return NEW(CaseClause(label, statements.elements()));
+  return new CaseClause(label, statements);
 }
 
 
@@ -2287,7 +1933,7 @@ SwitchStatement* Parser::ParseSwitchStatement(ZoneStringList* labels,
   // SwitchStatement ::
   //   'switch' '(' Expression ')' '{' CaseClause* '}'
 
-  SwitchStatement* statement = NEW(SwitchStatement(labels));
+  SwitchStatement* statement = new SwitchStatement(labels);
   Target target(&this->target_stack_, statement);
 
   Expect(Token::SWITCH, CHECK_OK);
@@ -2296,15 +1942,15 @@ SwitchStatement* Parser::ParseSwitchStatement(ZoneStringList* labels,
   Expect(Token::RPAREN, CHECK_OK);
 
   bool default_seen = false;
-  ZoneListWrapper<CaseClause> cases = factory()->NewList<CaseClause>(4);
+  ZoneList<CaseClause*>* cases = new ZoneList<CaseClause*>(4);
   Expect(Token::LBRACE, CHECK_OK);
   while (peek() != Token::RBRACE) {
     CaseClause* clause = ParseCaseClause(&default_seen, CHECK_OK);
-    cases.Add(clause);
+    cases->Add(clause);
   }
   Expect(Token::RBRACE, CHECK_OK);
 
-  if (statement) statement->Initialize(tag, cases.elements());
+  if (statement) statement->Initialize(tag, cases);
   return statement;
 }
 
@@ -2323,7 +1969,7 @@ Statement* Parser::ParseThrowStatement(bool* ok) {
   Expression* exception = ParseExpression(true, CHECK_OK);
   ExpectSemicolon(CHECK_OK);
 
-  return NEW(ExpressionStatement(new Throw(exception, pos)));
+  return new ExpressionStatement(new Throw(exception, pos));
 }
 
 
@@ -2341,7 +1987,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
 
   Expect(Token::TRY, CHECK_OK);
 
-  ZoneList<BreakTarget*>* target_list = NEW(ZoneList<BreakTarget*>(0));
+  ZoneList<BreakTarget*>* target_list = new ZoneList<BreakTarget*>(0);
   TargetCollector collector(target_list);
   Block* try_block;
 
@@ -2364,7 +2010,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
   // then we will need to collect jump targets from the catch block. Since
   // we don't know yet if there will be a finally block, we always collect
   // the jump targets.
-  ZoneList<BreakTarget*>* catch_target_list = NEW(ZoneList<BreakTarget*>(0));
+  ZoneList<BreakTarget*>* catch_target_list = new ZoneList<BreakTarget*>(0);
   TargetCollector catch_collector(catch_target_list);
   bool has_catch = false;
   if (tok == Token::CATCH) {
@@ -2379,8 +2025,8 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
       // Allocate a temporary for holding the finally state while
       // executing the finally block.
       catch_var = top_scope_->NewTemporary(Factory::catch_var_symbol());
-      Literal* name_literal = NEW(Literal(name));
-      Expression* obj = NEW(CatchExtensionObject(name_literal, catch_var));
+      Literal* name_literal = new Literal(name);
+      Expression* obj = new CatchExtensionObject(name_literal, catch_var);
       { Target target(&this->target_stack_, &catch_collector);
         catch_block = WithHelper(obj, NULL, true, CHECK_OK);
       }
@@ -2403,30 +2049,28 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
   // to:
   //   'try { try { } catch { } } finally { }'
 
-  if (!is_pre_parsing_ && catch_block != NULL && finally_block != NULL) {
+  if (catch_block != NULL && finally_block != NULL) {
     TryCatchStatement* statement =
-        NEW(TryCatchStatement(try_block, catch_var, catch_block));
+        new TryCatchStatement(try_block, catch_var, catch_block);
     statement->set_escaping_targets(collector.targets());
-    try_block = NEW(Block(NULL, 1, false));
+    try_block = new Block(NULL, 1, false);
     try_block->AddStatement(statement);
     catch_block = NULL;
   }
 
   TryStatement* result = NULL;
-  if (!is_pre_parsing_) {
-    if (catch_block != NULL) {
-      ASSERT(finally_block == NULL);
-      result = NEW(TryCatchStatement(try_block, catch_var, catch_block));
-      result->set_escaping_targets(collector.targets());
-    } else {
-      ASSERT(finally_block != NULL);
-      result = NEW(TryFinallyStatement(try_block, finally_block));
-      // Add the jump targets of the try block and the catch block.
-      for (int i = 0; i < collector.targets()->length(); i++) {
-        catch_collector.AddTarget(collector.targets()->at(i));
-      }
-      result->set_escaping_targets(catch_collector.targets());
+  if (catch_block != NULL) {
+    ASSERT(finally_block == NULL);
+    result = new TryCatchStatement(try_block, catch_var, catch_block);
+    result->set_escaping_targets(collector.targets());
+  } else {
+    ASSERT(finally_block != NULL);
+    result = new TryFinallyStatement(try_block, finally_block);
+    // Add the jump targets of the try block and the catch block.
+    for (int i = 0; i < collector.targets()->length(); i++) {
+      catch_collector.AddTarget(collector.targets()->at(i));
     }
+    result->set_escaping_targets(catch_collector.targets());
   }
 
   return result;
@@ -2439,7 +2083,7 @@ DoWhileStatement* Parser::ParseDoWhileStatement(ZoneStringList* labels,
   //   'do' Statement 'while' '(' Expression ')' ';'
 
   temp_scope_->AddLoop();
-  DoWhileStatement* loop = NEW(DoWhileStatement(labels));
+  DoWhileStatement* loop = new DoWhileStatement(labels);
   Target target(&this->target_stack_, loop);
 
   Expect(Token::DO, CHECK_OK);
@@ -2472,7 +2116,7 @@ WhileStatement* Parser::ParseWhileStatement(ZoneStringList* labels, bool* ok) {
   //   'while' '(' Expression ')' Statement
 
   temp_scope_->AddLoop();
-  WhileStatement* loop = NEW(WhileStatement(labels));
+  WhileStatement* loop = new WhileStatement(labels);
   Target target(&this->target_stack_, loop);
 
   Expect(Token::WHILE, CHECK_OK);
@@ -2502,7 +2146,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
       Block* variable_statement =
           ParseVariableDeclarations(false, &each, CHECK_OK);
       if (peek() == Token::IN && each != NULL) {
-        ForInStatement* loop = NEW(ForInStatement(labels));
+        ForInStatement* loop = new ForInStatement(labels);
         Target target(&this->target_stack_, loop);
 
         Expect(Token::IN, CHECK_OK);
@@ -2510,17 +2154,12 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
         Expect(Token::RPAREN, CHECK_OK);
 
         Statement* body = ParseStatement(NULL, CHECK_OK);
-        if (is_pre_parsing_) {
-          return NULL;
-        } else {
-          loop->Initialize(each, enumerable, body);
-          Block* result = NEW(Block(NULL, 2, false));
-          result->AddStatement(variable_statement);
-          result->AddStatement(loop);
-          // Parsed for-in loop w/ variable/const declaration.
-          return result;
-        }
-
+        loop->Initialize(each, enumerable, body);
+        Block* result = new Block(NULL, 2, false);
+        result->AddStatement(variable_statement);
+        result->AddStatement(loop);
+        // Parsed for-in loop w/ variable/const declaration.
+        return result;
       } else {
         init = variable_statement;
       }
@@ -2536,7 +2175,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
           Handle<String> type = Factory::invalid_lhs_in_for_in_symbol();
           expression = NewThrowReferenceError(type);
         }
-        ForInStatement* loop = NEW(ForInStatement(labels));
+        ForInStatement* loop = new ForInStatement(labels);
         Target target(&this->target_stack_, loop);
 
         Expect(Token::IN, CHECK_OK);
@@ -2549,13 +2188,13 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
         return loop;
 
       } else {
-        init = NEW(ExpressionStatement(expression));
+        init = new ExpressionStatement(expression);
       }
     }
   }
 
   // Standard 'for' loop
-  ForStatement* loop = NEW(ForStatement(labels));
+  ForStatement* loop = new ForStatement(labels);
   Target target(&this->target_stack_, loop);
 
   // Parsed initializer at this point.
@@ -2571,7 +2210,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
   Statement* next = NULL;
   if (peek() != Token::RPAREN) {
     Expression* exp = ParseExpression(true, CHECK_OK);
-    next = NEW(ExpressionStatement(exp));
+    next = new ExpressionStatement(exp);
   }
   Expect(Token::RPAREN, CHECK_OK);
 
@@ -2592,7 +2231,7 @@ Expression* Parser::ParseExpression(bool accept_IN, bool* ok) {
     Expect(Token::COMMA, CHECK_OK);
     int position = scanner().location().beg_pos;
     Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
-    result = NEW(BinaryOperation(Token::COMMA, result, right, position));
+    result = new BinaryOperation(Token::COMMA, result, right, position);
   }
   return result;
 }
@@ -2652,7 +2291,7 @@ Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) {
     fni_->Leave();
   }
 
-  return NEW(Assignment(op, expression, right, pos));
+  return new Assignment(op, expression, right, pos);
 }
 
 
@@ -2674,8 +2313,8 @@ Expression* Parser::ParseConditionalExpression(bool accept_IN, bool* ok) {
   Expect(Token::COLON, CHECK_OK);
   int right_position = scanner().peek_location().beg_pos;
   Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
-  return NEW(Conditional(expression, left, right,
-                         left_position, right_position));
+  return new Conditional(expression, left, right,
+                         left_position, right_position);
 }
 
 
@@ -2782,12 +2421,12 @@ Expression* Parser::ParseBinaryExpression(int prec, bool accept_IN, bool* ok) {
         x = NewCompareNode(cmp, x, y, position);
         if (cmp != op) {
           // The comparison was negated - add a NOT.
-          x = NEW(UnaryOperation(Token::NOT, x));
+          x = new UnaryOperation(Token::NOT, x);
         }
 
       } else {
         // We have a "normal" binary operation.
-        x = NEW(BinaryOperation(op, x, y, position));
+        x = new BinaryOperation(op, x, y, position);
       }
     }
   }
@@ -2800,19 +2439,19 @@ Expression* Parser::NewCompareNode(Token::Value op,
                                    Expression* y,
                                    int position) {
   ASSERT(op != Token::NE && op != Token::NE_STRICT);
-  if (!is_pre_parsing_ && (op == Token::EQ || op == Token::EQ_STRICT)) {
+  if (op == Token::EQ || op == Token::EQ_STRICT) {
     bool is_strict = (op == Token::EQ_STRICT);
     Literal* x_literal = x->AsLiteral();
     if (x_literal != NULL && x_literal->IsNull()) {
-      return NEW(CompareToNull(is_strict, y));
+      return new CompareToNull(is_strict, y);
     }
 
     Literal* y_literal = y->AsLiteral();
     if (y_literal != NULL && y_literal->IsNull()) {
-      return NEW(CompareToNull(is_strict, x));
+      return new CompareToNull(is_strict, x);
     }
   }
-  return NEW(CompareOperation(op, x, y, position));
+  return new CompareOperation(op, x, y, position);
 }
 
 
@@ -2849,7 +2488,7 @@ Expression* Parser::ParseUnaryExpression(bool* ok) {
       }
     }
 
-    return NEW(UnaryOperation(op, expression));
+    return new UnaryOperation(op, expression);
 
   } else if (Token::IsCountOp(op)) {
     op = Next();
@@ -2863,8 +2502,8 @@ Expression* Parser::ParseUnaryExpression(bool* ok) {
       expression = NewThrowReferenceError(type);
     }
     int position = scanner().location().beg_pos;
-    IncrementOperation* increment = NEW(IncrementOperation(op, expression));
-    return NEW(CountOperation(true /* prefix */, increment, position));
+    IncrementOperation* increment = new IncrementOperation(op, expression);
+    return new CountOperation(true /* prefix */, increment, position);
 
   } else {
     return ParsePostfixExpression(ok);
@@ -2888,8 +2527,8 @@ Expression* Parser::ParsePostfixExpression(bool* ok) {
     }
     Token::Value next = Next();
     int position = scanner().location().beg_pos;
-    IncrementOperation* increment = NEW(IncrementOperation(next, expression));
-    expression = NEW(CountOperation(false /* postfix */, increment, position));
+    IncrementOperation* increment = new IncrementOperation(next, expression);
+    expression = new CountOperation(false /* postfix */, increment, position);
   }
   return expression;
 }
@@ -2912,7 +2551,7 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
         Consume(Token::LBRACK);
         int pos = scanner().location().beg_pos;
         Expression* index = ParseExpression(true, CHECK_OK);
-        result = factory()->NewProperty(result, index, pos);
+        result = new Property(result, index, pos);
         Expect(Token::RBRACK, CHECK_OK);
         break;
       }
@@ -2929,17 +2568,15 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
         // declared in the current scope chain. These calls are marked as
         // potentially direct eval calls. Whether they are actually direct calls
         // to eval is determined at run time.
-        if (!is_pre_parsing_) {
-          VariableProxy* callee = result->AsVariableProxy();
-          if (callee != NULL && callee->IsVariable(Factory::eval_symbol())) {
-            Handle<String> name = callee->name();
-            Variable* var = top_scope_->Lookup(name);
-            if (var == NULL) {
-              top_scope_->RecordEvalCall();
-            }
+        VariableProxy* callee = result->AsVariableProxy();
+        if (callee != NULL && callee->IsVariable(Factory::eval_symbol())) {
+          Handle<String> name = callee->name();
+          Variable* var = top_scope_->Lookup(name);
+          if (var == NULL) {
+            top_scope_->RecordEvalCall();
           }
         }
-        result = factory()->NewCall(result, args, pos);
+        result = NewCall(result, args, pos);
         break;
       }
 
@@ -2947,7 +2584,7 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
         Consume(Token::PERIOD);
         int pos = scanner().location().beg_pos;
         Handle<String> name = ParseIdentifierName(CHECK_OK);
-        result = factory()->NewProperty(result, NEW(Literal(name)), pos);
+        result = new Property(result, new Literal(name), pos);
         if (fni_ != NULL) fni_->PushLiteralName(name);
         break;
       }
@@ -2959,7 +2596,6 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
 }
 
 
-
 Expression* Parser::ParseNewPrefix(PositionStack* stack, bool* ok) {
   // NewExpression ::
   //   ('new')+ MemberExpression
@@ -2984,7 +2620,7 @@ Expression* Parser::ParseNewPrefix(PositionStack* stack, bool* ok) {
 
   if (!stack->is_empty()) {
     int last = stack->pop();
-    result = NEW(CallNew(result, new ZoneList<Expression*>(0), last));
+    result = new CallNew(result, new ZoneList<Expression*>(0), last);
   }
   return result;
 }
@@ -3026,7 +2662,7 @@ Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack,
         Consume(Token::LBRACK);
         int pos = scanner().location().beg_pos;
         Expression* index = ParseExpression(true, CHECK_OK);
-        result = factory()->NewProperty(result, index, pos);
+        result = new Property(result, index, pos);
         Expect(Token::RBRACK, CHECK_OK);
         break;
       }
@@ -3034,7 +2670,7 @@ Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack,
         Consume(Token::PERIOD);
         int pos = scanner().location().beg_pos;
         Handle<String> name = ParseIdentifierName(CHECK_OK);
-        result = factory()->NewProperty(result, NEW(Literal(name)), pos);
+        result = new Property(result, new Literal(name), pos);
         if (fni_ != NULL) fni_->PushLiteralName(name);
         break;
       }
@@ -3043,7 +2679,7 @@ Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack,
         // Consume one of the new prefixes (already parsed).
         ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
         int last = stack->pop();
-        result = NEW(CallNew(result, args, last));
+        result = new CallNew(result, args, last);
         break;
       }
       default:
@@ -3062,7 +2698,7 @@ DebuggerStatement* Parser::ParseDebuggerStatement(bool* ok) {
 
   Expect(Token::DEBUGGER, CHECK_OK);
   ExpectSemicolon(CHECK_OK);
-  return NEW(DebuggerStatement());
+  return new DebuggerStatement();
 }
 
 
@@ -3120,38 +2756,30 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) {
   switch (peek()) {
     case Token::THIS: {
       Consume(Token::THIS);
-      if (is_pre_parsing_) {
-        result = VariableProxySentinel::this_proxy();
-      } else {
-        VariableProxy* recv = top_scope_->receiver();
-        result = recv;
-      }
+      VariableProxy* recv = top_scope_->receiver();
+      result = recv;
       break;
     }
 
     case Token::NULL_LITERAL:
       Consume(Token::NULL_LITERAL);
-      result = NEW(Literal(Factory::null_value()));
+      result = new Literal(Factory::null_value());
       break;
 
     case Token::TRUE_LITERAL:
       Consume(Token::TRUE_LITERAL);
-      result = NEW(Literal(Factory::true_value()));
+      result = new Literal(Factory::true_value());
       break;
 
     case Token::FALSE_LITERAL:
       Consume(Token::FALSE_LITERAL);
-      result = NEW(Literal(Factory::false_value()));
+      result = new Literal(Factory::false_value());
       break;
 
     case Token::IDENTIFIER: {
       Handle<String> name = ParseIdentifier(CHECK_OK);
       if (fni_ != NULL) fni_->PushVariableName(name);
-      if (is_pre_parsing_) {
-        result = VariableProxySentinel::identifier_proxy();
-      } else {
-        result = top_scope_->NewUnresolved(name, inside_with());
-      }
+      result = top_scope_->NewUnresolved(name, inside_with());
       break;
     }
 
@@ -3166,7 +2794,7 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) {
     case Token::STRING: {
       Consume(Token::STRING);
       Handle<String> symbol = GetSymbol(CHECK_OK);
-      result = NEW(Literal(symbol));
+      result = new Literal(symbol);
       if (fni_ != NULL) fni_->PushLiteralName(symbol);
       break;
     }
@@ -3244,7 +2872,7 @@ Expression* Parser::ParseArrayLiteral(bool* ok) {
   // ArrayLiteral ::
   //   '[' Expression? (',' Expression?)* ']'
 
-  ZoneListWrapper<Expression> values = factory()->NewList<Expression>(4);
+  ZoneList<Expression*>* values = new ZoneList<Expression*>(4);
   Expect(Token::LBRACK, CHECK_OK);
   while (peek() != Token::RBRACK) {
     Expression* elem;
@@ -3253,7 +2881,7 @@ Expression* Parser::ParseArrayLiteral(bool* ok) {
     } else {
       elem = ParseAssignmentExpression(true, CHECK_OK);
     }
-    values.Add(elem);
+    values->Add(elem);
     if (peek() != Token::RBRACK) {
       Expect(Token::COMMA, CHECK_OK);
     }
@@ -3263,21 +2891,19 @@ Expression* Parser::ParseArrayLiteral(bool* ok) {
   // Update the scope information before the pre-parsing bailout.
   int literal_index = temp_scope_->NextMaterializedLiteralIndex();
 
-  if (is_pre_parsing_) return NULL;
-
   // Allocate a fixed array with all the literals.
   Handle<FixedArray> literals =
-      Factory::NewFixedArray(values.length(), TENURED);
+      Factory::NewFixedArray(values->length(), TENURED);
 
   // Fill in the literals.
   bool is_simple = true;
   int depth = 1;
-  for (int i = 0; i < values.length(); i++) {
-    MaterializedLiteral* m_literal = values.at(i)->AsMaterializedLiteral();
+  for (int i = 0, n = values->length(); i < n; i++) {
+    MaterializedLiteral* m_literal = values->at(i)->AsMaterializedLiteral();
     if (m_literal != NULL && m_literal->depth() + 1 > depth) {
       depth = m_literal->depth() + 1;
     }
-    Handle<Object> boilerplate_value = GetBoilerplateValue(values.at(i));
+    Handle<Object> boilerplate_value = GetBoilerplateValue(values->at(i));
     if (boilerplate_value->IsUndefined()) {
       literals->set_the_hole(i);
       is_simple = false;
@@ -3288,12 +2914,12 @@ Expression* Parser::ParseArrayLiteral(bool* ok) {
 
   // Simple and shallow arrays can be lazily copied, we transform the
   // elements array to a copy-on-write array.
-  if (is_simple && depth == 1 && values.length() > 0) {
+  if (is_simple && depth == 1 && values->length() > 0) {
     literals->set_map(Heap::fixed_cow_array_map());
   }
 
-  return NEW(ArrayLiteral(literals, values.elements(),
-                          literal_index, is_simple, depth));
+  return new ArrayLiteral(literals, values,
+                          literal_index, is_simple, depth);
 }
 
 
@@ -3440,7 +3066,7 @@ ObjectLiteral::Property* Parser::ParseObjectLiteralGetSet(bool is_getter,
                              DECLARATION,
                              CHECK_OK);
     ObjectLiteral::Property* property =
-        NEW(ObjectLiteral::Property(is_getter, value));
+        new ObjectLiteral::Property(is_getter, value);
     return property;
   } else {
     ReportUnexpectedToken(next);
@@ -3457,8 +3083,8 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
   //     | (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral)
   //    )*[','] '}'
 
-  ZoneListWrapper<ObjectLiteral::Property> properties =
-      factory()->NewList<ObjectLiteral::Property>(4);
+  ZoneList<ObjectLiteral::Property*>* properties =
+      new ZoneList<ObjectLiteral::Property*>(4);
   int number_of_boilerplate_properties = 0;
 
   Expect(Token::LBRACE, CHECK_OK);
@@ -3481,7 +3107,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
             if (IsBoilerplateProperty(property)) {
               number_of_boilerplate_properties++;
             }
-            properties.Add(property);
+            properties->Add(property);
             if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK);
 
             if (fni_ != NULL) {
@@ -3492,7 +3118,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
         }
         // Failed to parse as get/set property, so it's just a property
         // called "get" or "set".
-        key = NEW(Literal(id));
+        key = new Literal(id);
         break;
       }
       case Token::STRING: {
@@ -3504,7 +3130,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
           key = NewNumberLiteral(index);
           break;
         }
-        key = NEW(Literal(string));
+        key = new Literal(string);
         break;
       }
       case Token::NUMBER: {
@@ -3518,7 +3144,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
         if (Token::IsKeyword(next)) {
           Consume(next);
           Handle<String> string = GetSymbol(CHECK_OK);
-          key = NEW(Literal(string));
+          key = new Literal(string);
         } else {
           // Unexpected token.
           Token::Value next = Next();
@@ -3532,11 +3158,11 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
     Expression* value = ParseAssignmentExpression(true, CHECK_OK);
 
     ObjectLiteral::Property* property =
-        NEW(ObjectLiteral::Property(key, value));
+        new ObjectLiteral::Property(key, value);
 
     // Count CONSTANT or COMPUTED properties to maintain the enumeration order.
     if (IsBoilerplateProperty(property)) number_of_boilerplate_properties++;
-    properties.Add(property);
+    properties->Add(property);
 
     // TODO(1240767): Consider allowing trailing comma.
     if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK);
@@ -3549,7 +3175,6 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
   Expect(Token::RBRACE, CHECK_OK);
   // Computation of literal_index must happen before pre parse bailout.
   int literal_index = temp_scope_->NextMaterializedLiteralIndex();
-  if (is_pre_parsing_) return NULL;
 
   Handle<FixedArray> constant_properties =
       Factory::NewFixedArray(number_of_boilerplate_properties * 2, TENURED);
@@ -3557,13 +3182,13 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
   bool is_simple = true;
   bool fast_elements = true;
   int depth = 1;
-  BuildObjectLiteralConstantProperties(properties.elements(),
+  BuildObjectLiteralConstantProperties(properties,
                                        constant_properties,
                                        &is_simple,
                                        &fast_elements,
                                        &depth);
   return new ObjectLiteral(constant_properties,
-                           properties.elements(),
+                           properties,
                            literal_index,
                            is_simple,
                            fast_elements,
@@ -3581,19 +3206,6 @@ Expression* Parser::ParseRegExpLiteral(bool seen_equal, bool* ok) {
 
   int literal_index = temp_scope_->NextMaterializedLiteralIndex();
 
-  if (is_pre_parsing_) {
-    // If we're preparsing we just do all the parsing stuff without
-    // building anything.
-    if (!scanner_.ScanRegExpFlags()) {
-      Next();
-      ReportMessage("invalid_regexp_flags", Vector<const char*>::empty());
-      *ok = false;
-      return NULL;
-    }
-    Next();
-    return NULL;
-  }
-
   Handle<String> js_pattern =
       Factory::NewStringFromUtf8(scanner_.next_literal(), TENURED);
   scanner_.ScanRegExpFlags();
@@ -3609,17 +3221,17 @@ ZoneList<Expression*>* Parser::ParseArguments(bool* ok) {
   // Arguments ::
   //   '(' (AssignmentExpression)*[','] ')'
 
-  ZoneListWrapper<Expression> result = factory()->NewList<Expression>(4);
+  ZoneList<Expression*>* result = new ZoneList<Expression*>(4);
   Expect(Token::LPAREN, CHECK_OK);
   bool done = (peek() == Token::RPAREN);
   while (!done) {
     Expression* argument = ParseAssignmentExpression(true, CHECK_OK);
-    result.Add(argument);
+    result->Add(argument);
     done = (peek() == Token::RPAREN);
     if (!done) Expect(Token::COMMA, CHECK_OK);
   }
   Expect(Token::RPAREN, CHECK_OK);
-  return result.elements();
+  return result;
 }
 
 
@@ -3635,9 +3247,9 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
   // this is the actual function name, otherwise this is the name of the
   // variable declared and initialized with the function (expression). In
   // that case, we don't have a function name (it's empty).
-  Handle<String> name = is_named ? var_name : factory()->EmptySymbol();
+  Handle<String> name = is_named ? var_name : Factory::empty_symbol();
   // The function name, if any.
-  Handle<String> function_name = factory()->EmptySymbol();
+  Handle<String> function_name = Factory::empty_symbol();
   if (is_named && (type == EXPRESSION || type == NESTED)) {
     function_name = name;
   }
@@ -3645,7 +3257,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
   int num_parameters = 0;
   // Parse function body.
   { Scope* scope =
-        factory()->NewScope(top_scope_, Scope::FUNCTION_SCOPE, inside_with());
+        NewScope(top_scope_, Scope::FUNCTION_SCOPE, inside_with());
     LexicalScope lexical_scope(&this->top_scope_, &this->with_nesting_level_,
                                scope);
     TemporaryScope temp_scope(&this->temp_scope_);
@@ -3658,18 +3270,16 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
     bool done = (peek() == Token::RPAREN);
     while (!done) {
       Handle<String> param_name = ParseIdentifier(CHECK_OK);
-      if (!is_pre_parsing_) {
-        top_scope_->AddParameter(top_scope_->DeclareLocal(param_name,
-                                                          Variable::VAR));
-        num_parameters++;
-      }
+      top_scope_->AddParameter(top_scope_->DeclareLocal(param_name,
+                                                        Variable::VAR));
+      num_parameters++;
       done = (peek() == Token::RPAREN);
       if (!done) Expect(Token::COMMA, CHECK_OK);
     }
     Expect(Token::RPAREN, CHECK_OK);
 
     Expect(Token::LBRACE, CHECK_OK);
-    ZoneListWrapper<Statement> body = factory()->NewList<Statement>(8);
+    ZoneList<Statement*>* body = new ZoneList<Statement*>(8);
 
     // If we have a named function expression, we add a local variable
     // declaration to the body of the function with the name of the
@@ -3677,17 +3287,15 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
     // NOTE: We create a proxy and resolve it here so that in the
     // future we can change the AST to only refer to VariableProxies
     // instead of Variables and Proxis as is the case now.
-    if (!is_pre_parsing_
-        && !function_name.is_null()
-        && function_name->length() > 0) {
+    if (!function_name.is_null() && function_name->length() > 0) {
       Variable* fvar = top_scope_->DeclareFunctionVar(function_name);
       VariableProxy* fproxy =
           top_scope_->NewUnresolved(function_name, inside_with());
       fproxy->BindTo(fvar);
-      body.Add(new ExpressionStatement(
-                   new Assignment(Token::INIT_CONST, fproxy,
-                                  NEW(ThisFunction()),
-                                  RelocInfo::kNoPosition)));
+      body->Add(new ExpressionStatement(
+                    new Assignment(Token::INIT_CONST, fproxy,
+                                   new ThisFunction(),
+                                   RelocInfo::kNoPosition)));
     }
 
     // Determine if the function will be lazily compiled. The mode can
@@ -3719,12 +3327,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
       this_property_assignments = Factory::empty_fixed_array();
       Expect(Token::RBRACE, CHECK_OK);
     } else {
-      FunctionEntry entry;
-      if (is_lazily_compiled) entry = log()->LogFunction(function_block_pos);
-      {
-        ConditionalLogPauseScope pause_if(is_lazily_compiled, log());
-        ParseSourceElements(&body, Token::RBRACE, CHECK_OK);
-      }
+      ParseSourceElements(body, Token::RBRACE, CHECK_OK);
+
       materialized_literal_count = temp_scope.materialized_literal_count();
       expected_property_count = temp_scope.expected_property_count();
       only_simple_this_property_assignments =
@@ -3733,19 +3337,12 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
 
       Expect(Token::RBRACE, CHECK_OK);
       end_pos = scanner_.location().end_pos;
-      if (entry.is_valid()) {
-        ASSERT(is_lazily_compiled);
-        ASSERT(is_pre_parsing_);
-        entry.set_end_pos(end_pos);
-        entry.set_literal_count(materialized_literal_count);
-        entry.set_property_count(expected_property_count);
-      }
     }
 
     FunctionLiteral* function_literal =
-        NEW(FunctionLiteral(name,
+        new FunctionLiteral(name,
                             top_scope_,
-                            body.elements(),
+                            body,
                             materialized_literal_count,
                             expected_property_count,
                             only_simple_this_property_assignments,
@@ -3754,10 +3351,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
                             start_pos,
                             end_pos,
                             function_name->length() > 0,
-                            temp_scope.ContainsLoops()));
-    if (!is_pre_parsing_) {
-      function_literal->set_function_token_position(function_token_position);
-    }
+                            temp_scope.ContainsLoops());
+    function_literal->set_function_token_position(function_token_position);
 
     if (fni_ != NULL && !is_named) fni_->AddFunction(function_literal);
     return function_literal;
@@ -3772,7 +3367,6 @@ Expression* Parser::ParseV8Intrinsic(bool* ok) {
   Expect(Token::MOD, CHECK_OK);
   Handle<String> name = ParseIdentifier(CHECK_OK);
   ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
-  if (is_pre_parsing_) return NULL;
 
   if (extension_ != NULL) {
     // The extension structures are only accessible while parsing the
@@ -3808,7 +3402,7 @@ Expression* Parser::ParseV8Intrinsic(bool* ok) {
   }
 
   // We have a valid intrinsics call or a call to a builtin.
-  return NEW(CallRuntime(name, function, args));
+  return new CallRuntime(name, function, args);
 }
 
 
@@ -3856,12 +3450,12 @@ void Parser::ExpectSemicolon(bool* ok) {
 
 
 Literal* Parser::GetLiteralUndefined() {
-  return NEW(Literal(Factory::undefined_value()));
+  return new Literal(Factory::undefined_value());
 }
 
 
 Literal* Parser::GetLiteralTheHole() {
-  return NEW(Literal(Factory::the_hole_value()));
+  return new Literal(Factory::the_hole_value());
 }
 
 
@@ -3964,7 +3558,7 @@ void Parser::RegisterTargetUse(BreakTarget* target, Target* stop) {
 
 
 Literal* Parser::NewNumberLiteral(double number) {
-  return NEW(Literal(Factory::NewNumber(number, TENURED)));
+  return new Literal(Factory::NewNumber(number, TENURED));
 }
 
 
@@ -3996,8 +3590,6 @@ Expression* Parser::NewThrowTypeError(Handle<String> type,
 Expression* Parser::NewThrowError(Handle<String> constructor,
                                   Handle<String> type,
                                   Vector< Handle<Object> > arguments) {
-  if (is_pre_parsing_) return NULL;
-
   int argc = arguments.length();
   Handle<JSArray> array = Factory::NewJSArray(argc, TENURED);
   ASSERT(array->IsJSArray() && array->HasFastElements());
@@ -4185,17 +3777,17 @@ Handle<Object> JsonParser::ParseJsonArray() {
 RegExpParser::RegExpParser(FlatStringReader* in,
                            Handle<String>* error,
                            bool multiline)
-  : current_(kEndMarker),
+  : error_(error),
+    captures_(NULL),
+    in_(in),
+    current_(kEndMarker),
+    next_pos_(0),
+    capture_count_(0),
     has_more_(true),
     multiline_(multiline),
-    next_pos_(0),
-    in_(in),
-    error_(error),
     simple_(false),
     contains_anchor_(false),
-    captures_(NULL),
     is_scanned_for_captures_(false),
-    capture_count_(0),
     failed_(false) {
   Advance(1);
 }
@@ -5003,23 +4595,6 @@ bool ScriptDataImpl::HasError() {
 }
 
 
-// Preparse, but only collect data that is immediately useful,
-// even if the preparser data is only used once.
-ScriptDataImpl* ParserApi::PartialPreParse(Handle<String> source,
-                                           unibrow::CharacterStream* stream,
-                                           v8::Extension* extension) {
-  Handle<Script> no_script;
-  bool allow_natives_syntax =
-      FLAG_allow_natives_syntax || Bootstrapper::IsActive();
-  PartialPreParser parser(no_script, allow_natives_syntax, extension);
-  if (!parser.PreParseProgram(source, stream)) return NULL;
-  // Extract the accumulated data from the recorder as a single
-  // contiguous vector that we are responsible for disposing.
-  Vector<unsigned> store = parser.recorder()->ExtractData();
-  return new ScriptDataImpl(store);
-}
-
-
 void ScriptDataImpl::Initialize() {
   // Prepares state for use.
   if (store_.length() >= kHeaderSize) {
@@ -5063,18 +4638,82 @@ int ScriptDataImpl::ReadNumber(byte** source) {
 }
 
 
+static ScriptDataImpl* DoPreParse(UTF16Buffer* stream,
+                                  bool allow_lazy,
+                                  PartialParserRecorder* recorder) {
+  typedef preparser::Scanner<UTF16Buffer, UTF8Buffer> PreScanner;
+  PreScanner scanner;
+  scanner.Initialize(stream);
+  preparser::PreParser<PreScanner, PartialParserRecorder> preparser;
+  if (!preparser.PreParseProgram(&scanner, recorder, allow_lazy)) {
+    Top::StackOverflow();
+    return NULL;
+  }
+
+  // Extract the accumulated data from the recorder as a single
+  // contiguous vector that we are responsible for disposing.
+  Vector<unsigned> store = recorder->ExtractData();
+  return new ScriptDataImpl(store);
+}
+
+
+// Create an UTF16Buffer for the preparser to use as input,
+// and preparse the source.
+static ScriptDataImpl* DoPreParse(Handle<String> source,
+                                  unibrow::CharacterStream* stream,
+                                  bool allow_lazy,
+                                  PartialParserRecorder* recorder) {
+  if (source.is_null()) {
+    CharacterStreamUTF16Buffer buffer;
+    int length = stream->Length();
+    buffer.Initialize(source, stream, 0, length);
+    return DoPreParse(&buffer, allow_lazy, recorder);
+  } else if (source->IsExternalAsciiString()) {
+    ExternalStringUTF16Buffer<ExternalAsciiString, char> buffer;
+    int length = source->length();
+    buffer.Initialize(Handle<ExternalAsciiString>::cast(source), 0, length);
+    return DoPreParse(&buffer, allow_lazy, recorder);
+  } else if (source->IsExternalTwoByteString()) {
+    ExternalStringUTF16Buffer<ExternalTwoByteString, uint16_t> buffer;
+    int length = source->length();
+    buffer.Initialize(Handle<ExternalTwoByteString>::cast(source), 0, length);
+    return DoPreParse(&buffer, allow_lazy, recorder);
+  } else {
+    CharacterStreamUTF16Buffer buffer;
+    SafeStringInputBuffer input;
+    input.Reset(0, source.location());
+    int length = source->length();
+    buffer.Initialize(source, &input, 0, length);
+    return DoPreParse(&buffer, allow_lazy, recorder);
+  }
+}
+
+
+// Preparse, but only collect data that is immediately useful,
+// even if the preparser data is only used once.
+ScriptDataImpl* ParserApi::PartialPreParse(Handle<String> source,
+                                           unibrow::CharacterStream* stream,
+                                           v8::Extension* extension) {
+  Handle<Script> no_script;
+  bool allow_lazy = FLAG_lazy && (extension == NULL);
+  if (!allow_lazy) {
+    // Partial preparsing is only about lazily compiled functions.
+    // If we don't allow lazy compilation, the log data will be empty.
+    return NULL;
+  }
+  PartialParserRecorder recorder;
+
+  return DoPreParse(source, stream, allow_lazy, &recorder);
+}
+
+
 ScriptDataImpl* ParserApi::PreParse(Handle<String> source,
                                     unibrow::CharacterStream* stream,
                                     v8::Extension* extension) {
   Handle<Script> no_script;
-  bool allow_natives_syntax =
-      FLAG_allow_natives_syntax || Bootstrapper::IsActive();
-  CompletePreParser parser(no_script, allow_natives_syntax, extension);
-  if (!parser.PreParseProgram(source, stream)) return NULL;
-  // Extract the accumulated data from the recorder as a single
-  // contiguous vector that we are responsible for disposing.
-  Vector<unsigned> store = parser.recorder()->ExtractData();
-  return new ScriptDataImpl(store);
+  bool allow_lazy = FLAG_lazy && (extension == NULL);
+  CompleteParserRecorder recorder;
+  return DoPreParse(source, stream, allow_lazy, &recorder);
 }
 
 
@@ -5105,14 +4744,13 @@ bool ParserApi::Parse(CompilationInfo* info) {
   FunctionLiteral* result = NULL;
   Handle<Script> script = info->script();
   if (info->is_lazy()) {
-    AstBuildingParser parser(script, true, NULL, NULL);
+    Parser parser(script, true, NULL, NULL);
     result = parser.ParseLazy(info->shared_info());
   } else {
     bool allow_natives_syntax =
         FLAG_allow_natives_syntax || Bootstrapper::IsActive();
     ScriptDataImpl* pre_data = info->pre_parse_data();
-    AstBuildingParser parser(script, allow_natives_syntax, info->extension(),
-                             pre_data);
+    Parser parser(script, allow_natives_syntax, info->extension(), pre_data);
     if (pre_data != NULL && pre_data->has_error()) {
       Scanner::Location loc = pre_data->MessageLocation();
       const char* message = pre_data->BuildMessage();
@@ -5134,6 +4772,4 @@ bool ParserApi::Parse(CompilationInfo* info) {
   return (result != NULL);
 }
 
-#undef NEW
-
 } }  // namespace v8::internal
index 19b382e8ded3442c794dc57c2ab17f337aee39ff..64f621c9e2e695d8e24f690b1ce07ca73adc3676 100644 (file)
 #include "allocation.h"
 #include "ast.h"
 #include "scanner.h"
+#include "scopes.h"
 
 namespace v8 {
 namespace internal {
 
 class CompilationInfo;
 class FuncNameInferrer;
-class ParserFactory;
 class ParserLog;
 class PositionStack;
 class Target;
@@ -132,7 +132,7 @@ class ScriptDataImpl : public ScriptData {
   unsigned version() { return store_[kVersionOffset]; }
 
   static const unsigned kMagicNumber = 0xBadDead;
-  static const unsigned kCurrentVersion = 4;
+  static const unsigned kCurrentVersion = 5;
 
   static const int kMagicOffset = 0;
   static const int kVersionOffset = 1;
@@ -177,6 +177,125 @@ class ScriptDataImpl : public ScriptData {
 };
 
 
+// Record only functions.
+class PartialParserRecorder {
+ public:
+  PartialParserRecorder();
+
+  void LogFunction(int start, int end, int literals, int properties) {
+    function_store_.Add(start);
+    function_store_.Add(end);
+    function_store_.Add(literals);
+    function_store_.Add(properties);
+  }
+
+  void LogSymbol(int start, const char* symbol, int length) { }
+
+  // Logs an error message and marks the log as containing an error.
+  // Further logging will be ignored, and ExtractData will return a vector
+  // representing the error only.
+  void LogMessage(int start,
+                  int end,
+                  const char* message,
+                  const char* argument_opt) {
+    Scanner::Location location(start, end);
+    Vector<const char*> arguments;
+    if (argument_opt != NULL) {
+      arguments = Vector<const char*>(&argument_opt, 1);
+    }
+    this->LogMessage(location, message, arguments);
+  }
+
+  int function_position() { return function_store_.size(); }
+
+  void LogMessage(Scanner::Location loc,
+                  const char* message,
+                  Vector<const char*> args);
+
+  Vector<unsigned> ExtractData();
+
+  void PauseRecording() {
+    pause_count_++;
+    is_recording_ = false;
+  }
+
+  void ResumeRecording() {
+    ASSERT(pause_count_ > 0);
+    if (--pause_count_ == 0) is_recording_ = !has_error();
+  }
+
+  int symbol_position() { return 0; }
+  int symbol_ids() { return 0; }
+
+ protected:
+  bool has_error() {
+    return static_cast<bool>(preamble_[ScriptDataImpl::kHasErrorOffset]);
+  }
+
+  bool is_recording() {
+    return is_recording_;
+  }
+
+  void WriteString(Vector<const char> str);
+
+  Collector<unsigned> function_store_;
+  unsigned preamble_[ScriptDataImpl::kHeaderSize];
+  bool is_recording_;
+  int pause_count_;
+
+#ifdef DEBUG
+  int prev_start_;
+#endif
+};
+
+
+// Record both functions and symbols.
+class CompleteParserRecorder: public PartialParserRecorder {
+ public:
+  CompleteParserRecorder();
+
+  void LogSymbol(int start, Vector<const char> literal);
+
+  void LogSymbol(int start, const char* symbol, int length) {
+    LogSymbol(start, Vector<const char>(symbol, length));
+  }
+
+  Vector<unsigned> ExtractData();
+
+  int symbol_position() { return symbol_store_.size(); }
+  int symbol_ids() { return symbol_id_; }
+
+ private:
+  static int vector_hash(Vector<const char> string) {
+    int hash = 0;
+    for (int i = 0; i < string.length(); i++) {
+      int c = string[i];
+      hash += c;
+      hash += (hash << 10);
+      hash ^= (hash >> 6);
+    }
+    return hash;
+  }
+
+  static bool vector_compare(void* a, void* b) {
+    Vector<const char>* string1 = reinterpret_cast<Vector<const char>* >(a);
+    Vector<const char>* string2 = reinterpret_cast<Vector<const char>* >(b);
+    int length = string1->length();
+    if (string2->length() != length) return false;
+    return memcmp(string1->start(), string2->start(), length) == 0;
+  }
+
+  // Write a non-negative number to the symbol store.
+  void WriteNumber(int number);
+
+  Collector<byte> symbol_store_;
+  Collector<Vector<const char> > symbol_entries_;
+  HashMap symbol_table_;
+  int symbol_id_;
+};
+
+
+
 class ParserApi {
  public:
   // Parses the source code represented by the compilation info and sets its
@@ -196,6 +315,8 @@ class ParserApi {
                                          v8::Extension* extension);
 };
 
+// ----------------------------------------------------------------------------
+// REGEXP PARSING
 
 // A BuffferedZoneList is an automatically growing list, just like (and backed
 // by) a ZoneList, that is optimized for the case of adding and removing
@@ -411,51 +532,44 @@ class RegExpParser {
   uc32 Next();
   FlatStringReader* in() { return in_; }
   void ScanForCaptures();
+
+  Handle<String>* error_;
+  ZoneList<RegExpCapture*>* captures_;
+  FlatStringReader* in_;
   uc32 current_;
+  int next_pos_;
+  // The capture count is only valid after we have scanned for captures.
+  int capture_count_;
   bool has_more_;
   bool multiline_;
-  int next_pos_;
-  FlatStringReader* in_;
-  Handle<String>* error_;
   bool simple_;
   bool contains_anchor_;
-  ZoneList<RegExpCapture*>* captures_;
   bool is_scanned_for_captures_;
-  // The capture count is only valid after we have scanned for captures.
-  int capture_count_;
   bool failed_;
 };
 
+// ----------------------------------------------------------------------------
+// JAVASCRIPT PARSING
 
 class Parser {
  public:
-  Parser(Handle<Script> script, bool allow_natives_syntax,
-         v8::Extension* extension, ParserMode is_pre_parsing,
-         ParserFactory* factory, ParserLog* log, ScriptDataImpl* pre_data);
+  Parser(Handle<Script> script,
+         bool allow_natives_syntax,
+         v8::Extension* extension,
+         ScriptDataImpl* pre_data);
   virtual ~Parser() { }
 
-  // Pre-parse the program from the character stream; returns true on
-  // success, false if a stack-overflow happened during parsing.
-  bool PreParseProgram(Handle<String> source, unibrow::CharacterStream* stream);
-
-  void ReportMessage(const char* message, Vector<const char*> args);
-  virtual void ReportMessageAt(Scanner::Location loc,
-                               const char* message,
-                               Vector<const char*> args) = 0;
-
-
   // Returns NULL if parsing failed.
   FunctionLiteral* ParseProgram(Handle<String> source,
                                 bool in_global_context);
+
   FunctionLiteral* ParseLazy(Handle<SharedFunctionInfo> info);
 
-  // The minimum number of contiguous assignment that will
-  // be treated as an initialization block. Benchmarks show that
-  // the overhead exceeds the savings below this limit.
-  static const int kMinInitializationBlock = 3;
+  void ReportMessageAt(Scanner::Location loc,
+                       const char* message,
+                       Vector<const char*> args);
 
  protected:
-
   enum Mode {
     PARSE_LAZILY,
     PARSE_EAGERLY
@@ -464,28 +578,9 @@ class Parser {
   // Report syntax error
   void ReportUnexpectedToken(Token::Value token);
   void ReportInvalidPreparseData(Handle<String> name, bool* ok);
-
-  Handle<Script> script_;
-  Scanner scanner_;
-
-  Scope* top_scope_;
-  int with_nesting_level_;
-
-  TemporaryScope* temp_scope_;
-  Mode mode_;
-
-  Target* target_stack_;  // for break, continue statements
-  bool allow_natives_syntax_;
-  v8::Extension* extension_;
-  ParserFactory* factory_;
-  ParserLog* log_;
-  bool is_pre_parsing_;
-  ScriptDataImpl* pre_data_;
-  FuncNameInferrer* fni_;
+  void ReportMessage(const char* message, Vector<const char*> args);
 
   bool inside_with() const { return with_nesting_level_ > 0; }
-  ParserFactory* factory() const { return factory_; }
-  ParserLog* log() const { return log_; }
   Scanner& scanner()  { return scanner_; }
   Mode mode() const { return mode_; }
   ScriptDataImpl* pre_data() const { return pre_data_; }
@@ -494,7 +589,7 @@ class Parser {
   // which is set to false if parsing failed; it is unchanged otherwise.
   // By making the 'exception handling' explicit, we are forced to check
   // for failure at the call sites.
-  void* ParseSourceElements(ZoneListWrapper<Statement>* processor,
+  void* ParseSourceElements(ZoneList<Statement*>* processor,
                             int end_token, bool* ok);
   Statement* ParseStatement(ZoneStringList* labels, bool* ok);
   Statement* ParseFunctionDeclaration(bool* ok);
@@ -607,10 +702,10 @@ class Parser {
                                            bool* ok);
 
   // Parser support
-  virtual VariableProxy* Declare(Handle<String> name, Variable::Mode mode,
-                                 FunctionLiteral* fun,
-                                 bool resolve,
-                                 bool* ok) = 0;
+  VariableProxy* Declare(Handle<String> name, Variable::Mode mode,
+                         FunctionLiteral* fun,
+                         bool resolve,
+                         bool* ok);
 
   bool TargetStackContainsLabel(Handle<String> label);
   BreakableStatement* LookupBreakTarget(Handle<String> label, bool* ok);
@@ -618,6 +713,28 @@ class Parser {
 
   void RegisterTargetUse(BreakTarget* target, Target* stop);
 
+  // Factory methods.
+
+  Statement* EmptyStatement() {
+    static v8::internal::EmptyStatement empty;
+    return &empty;
+  }
+
+  Scope* NewScope(Scope* parent, Scope::Type type, bool inside_with);
+
+  Handle<String> LookupSymbol(int symbol_id,
+                              Vector<const char> string);
+
+  Handle<String> LookupCachedSymbol(int symbol_id,
+                                    Vector<const char> string);
+
+  Expression* NewCall(Expression* expression,
+                      ZoneList<Expression*>* arguments,
+                      int pos) {
+    return new Call(expression, arguments, pos);
+  }
+
+
   // Create a number literal.
   Literal* NewNumberLiteral(double value);
 
@@ -639,6 +756,24 @@ class Parser {
   Expression* NewThrowError(Handle<String> constructor,
                             Handle<String> type,
                             Vector< Handle<Object> > arguments);
+
+  ZoneList<Handle<String> > symbol_cache_;
+
+  Handle<Script> script_;
+  Scanner scanner_;
+
+  Scope* top_scope_;
+  int with_nesting_level_;
+
+  TemporaryScope* temp_scope_;
+  Mode mode_;
+
+  Target* target_stack_;  // for break, continue statements
+  bool allow_natives_syntax_;
+  v8::Extension* extension_;
+  bool is_pre_parsing_;
+  ScriptDataImpl* pre_data_;
+  FuncNameInferrer* fni_;
 };
 
 
@@ -673,6 +808,9 @@ class CompileTimeValue: public AllStatic {
 };
 
 
+// ----------------------------------------------------------------------------
+// JSON PARSING
+
 // JSON is a subset of JavaScript, as specified in, e.g., the ECMAScript 5
 // specification section 15.12.1 (and appendix A.8).
 // The grammar is given section 15.12.1.2 (and appendix A.8.2).
index c0eb21395feef7ae433456798f057c25db9b4af8..89003ba83f912fa178d5dfc949188051d3ec01c6 100644 (file)
@@ -99,30 +99,12 @@ uint64_t OS::CpuFeaturesImpliedByPlatform() {
 
 
 #ifdef __arm__
-bool OS::ArmCpuHasFeature(CpuFeature feature) {
-  const char* search_string = NULL;
+static bool CPUInfoContainsString(const char * search_string) {
   const char* file_name = "/proc/cpuinfo";
-  // Simple detection of VFP at runtime for Linux.
-  // It is based on /proc/cpuinfo, which reveals hardware configuration
-  // to user-space applications.  According to ARM (mid 2009), no similar
-  // facility is universally available on the ARM architectures,
-  // so it's up to individual OSes to provide such.
-  //
   // This is written as a straight shot one pass parser
   // and not using STL string and ifstream because,
   // on Linux, it's reading from a (non-mmap-able)
   // character special device.
-  switch (feature) {
-    case VFP3:
-      search_string = "vfp";
-      break;
-    case ARMv7:
-      search_string = "ARMv7";
-      break;
-    default:
-      UNREACHABLE();
-  }
-
   FILE* f = NULL;
   const char* what = search_string;
 
@@ -149,6 +131,43 @@ bool OS::ArmCpuHasFeature(CpuFeature feature) {
   // Did not find string in the proc file.
   return false;
 }
+
+bool OS::ArmCpuHasFeature(CpuFeature feature) {
+  const int max_items = 2;
+  const char* search_strings[max_items] = { NULL, NULL };
+  int search_items = 0;
+  // Simple detection of VFP at runtime for Linux.
+  // It is based on /proc/cpuinfo, which reveals hardware configuration
+  // to user-space applications.  According to ARM (mid 2009), no similar
+  // facility is universally available on the ARM architectures,
+  // so it's up to individual OSes to provide such.
+  switch (feature) {
+    case VFP3:
+      search_strings[0] = "vfpv3";
+      // Some old kernels will report vfp for A8, not vfpv3, so we check for
+      // A8 explicitely. The cpuinfo file report the CPU Part which for Cortex
+      // A8 is 0xc08.
+      search_strings[1] = "0xc08";
+      search_items = 2;
+      ASSERT(search_items <= max_items);
+      break;
+    case ARMv7:
+      search_strings[0] = "ARMv7" ;
+      search_items = 1;
+      ASSERT(search_items <= max_items);
+      break;
+    default:
+      UNREACHABLE();
+  }
+
+  for (int i = 0; i < search_items; ++i) {
+    if (CPUInfoContainsString(search_strings[i])) {
+      return true;
+    }
+  }
+
+  return false;
+}
 #endif  // def __arm__
 
 
@@ -809,8 +828,17 @@ class Sampler::PlatformData : public Malloced {
       syscall(SYS_tgkill, vm_tgid_, vm_tid_, SIGPROF);
       // Convert ms to us and subtract 100 us to compensate delays
       // occuring during signal delivery.
-      int result = usleep(sampler_->interval_ * 1000 - 100);
-      ASSERT(result == 0 || errno == EINTR);
+      const useconds_t interval = sampler_->interval_ * 1000 - 100;
+      int result = usleep(interval);
+#ifdef DEBUG
+      if (result != 0 && errno != EINTR) {
+        fprintf(stderr,
+                "SignalSender usleep error; interval = %u, errno = %d\n",
+                interval,
+                errno);
+        ASSERT(result == 0 || errno == EINTR);
+      }
+#endif
       USE(result);
     }
   }
@@ -843,6 +871,7 @@ Sampler::Sampler(int interval, bool profiling)
 
 
 Sampler::~Sampler() {
+  ASSERT(!data_->signal_sender_launched_);
   delete data_;
 }
 
index caea16cb9be50bb09619afa2066aa0145ecfd3d2..a0ba5e865ca738497521c733fd6390587b714857 100644 (file)
@@ -865,8 +865,9 @@ void* OS::Allocate(const size_t requested,
 
   // For exectutable pages try and randomize the allocation address
   if (prot == PAGE_EXECUTE_READWRITE && msize >= Page::kPageSize) {
-      address = (V8::Random() << kPageSizeBits) | kAllocationRandomAddressMin;
-      address &= kAllocationRandomAddressMax;
+    address = (V8::RandomPrivate() << kPageSizeBits)
+      | kAllocationRandomAddressMin;
+    address &= kAllocationRandomAddressMax;
   }
 
   LPVOID mbase = VirtualAlloc(reinterpret_cast<void *>(address),
diff --git a/deps/v8/src/preparser.h b/deps/v8/src/preparser.h
new file mode 100644 (file)
index 0000000..547e766
--- /dev/null
@@ -0,0 +1,1419 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_PREPARSER_H
+#define V8_PREPARSER_H
+
+#include "unicode.h"
+#include "utils.h"
+
+namespace v8 {
+namespace preparser {
+
+// Preparsing checks a JavaScript program and emits preparse-data that helps
+// a later parsing to be faster.
+// See preparser-data.h for the data.
+
+// The PreParser checks that the syntax follows the grammar for JavaScript,
+// and collects some information about the program along the way.
+// The grammar check is only performed in order to understand the program
+// sufficiently to deduce some information about it, that can be used
+// to speed up later parsing. Finding errors is not the goal of pre-parsing,
+// rather it is to speed up properly written and correct programs.
+// That means that contextual checks (like a label being declared where
+// it is used) are generally omitted.
+
+namespace i = v8::internal;
+
+enum StatementType {
+  kUnknownStatement
+};
+
+enum ExpressionType {
+  kUnknownExpression,
+  kIdentifierExpression,  // Used to detect labels.
+  kThisExpression,
+  kThisPropertyExpression
+};
+
+enum IdentifierType {
+  kUnknownIdentifier
+};
+
+enum SourceElementTypes {
+  kUnknownSourceElements
+};
+
+
+typedef int SourceElements;
+typedef int Expression;
+typedef int Statement;
+typedef int Identifier;
+typedef int Arguments;
+
+
+template <typename Scanner, typename PreParserLog>
+class PreParser {
+ public:
+  PreParser() : scope_(NULL), allow_lazy_(true) { }
+  ~PreParser() { }
+
+  // Pre-parse the program from the character stream; returns true on
+  // success (even if parsing failed, the pre-parse data successfully
+  // captured the syntax error), and false if a stack-overflow happened
+  // during parsing.
+  bool PreParseProgram(Scanner* scanner,
+                       PreParserLog* log,
+                       bool allow_lazy) {
+    allow_lazy_ = allow_lazy;
+    scanner_ = scanner;
+    log_ = log;
+    Scope top_scope(&scope_, kTopLevelScope);
+    bool ok = true;
+    ParseSourceElements(i::Token::EOS, &ok);
+    bool stack_overflow = scanner_->stack_overflow();
+    if (!ok && !stack_overflow) {
+      ReportUnexpectedToken(scanner_->current_token());
+    }
+    return !stack_overflow;
+  }
+
+ private:
+  enum ScopeType {
+    kTopLevelScope,
+    kFunctionScope
+  };
+
+  class Scope {
+   public:
+    Scope(Scope** variable, ScopeType type)
+        : variable_(variable),
+          prev_(*variable),
+          type_(type),
+          materialized_literal_count_(0),
+          expected_properties_(0),
+          with_nesting_count_(0) {
+      *variable = this;
+    }
+    ~Scope() { *variable_ = prev_; }
+    void NextMaterializedLiteralIndex() { materialized_literal_count_++; }
+    void AddProperty() { expected_properties_++; }
+    ScopeType type() { return type_; }
+    int expected_properties() { return expected_properties_; }
+    int materialized_literal_count() { return materialized_literal_count_; }
+    bool IsInsideWith() { return with_nesting_count_ != 0; }
+    void EnterWith() { with_nesting_count_++; }
+    void LeaveWith() { with_nesting_count_--; }
+
+   private:
+    Scope** const variable_;
+    Scope* const prev_;
+    const ScopeType type_;
+    int materialized_literal_count_;
+    int expected_properties_;
+    int with_nesting_count_;
+  };
+
+  // Types that allow us to recognize simple this-property assignments.
+  // A simple this-property assignment is a statement on the form
+  // "this.propertyName = {primitive constant or function parameter name);"
+  // where propertyName isn't "__proto__".
+  // The result is only relevant if the function body contains only
+  // simple this-property assignments.
+
+  // Report syntax error
+  void ReportUnexpectedToken(i::Token::Value token);
+  void ReportMessageAt(int start_pos,
+                       int end_pos,
+                       const char* type,
+                       const char* name_opt) {
+    log_->LogMessage(start_pos, end_pos, type, name_opt);
+  }
+
+  // All ParseXXX functions take as the last argument an *ok parameter
+  // which is set to false if parsing failed; it is unchanged otherwise.
+  // By making the 'exception handling' explicit, we are forced to check
+  // for failure at the call sites.
+  SourceElements ParseSourceElements(int end_token, bool* ok);
+  Statement ParseStatement(bool* ok);
+  Statement ParseFunctionDeclaration(bool* ok);
+  Statement ParseNativeDeclaration(bool* ok);
+  Statement ParseBlock(bool* ok);
+  Statement ParseVariableStatement(bool* ok);
+  Statement ParseVariableDeclarations(bool accept_IN, int* num_decl, bool* ok);
+  Statement ParseExpressionOrLabelledStatement(bool* ok);
+  Statement ParseIfStatement(bool* ok);
+  Statement ParseContinueStatement(bool* ok);
+  Statement ParseBreakStatement(bool* ok);
+  Statement ParseReturnStatement(bool* ok);
+  Statement ParseWithStatement(bool* ok);
+  Statement ParseSwitchStatement(bool* ok);
+  Statement ParseDoWhileStatement(bool* ok);
+  Statement ParseWhileStatement(bool* ok);
+  Statement ParseForStatement(bool* ok);
+  Statement ParseThrowStatement(bool* ok);
+  Statement ParseTryStatement(bool* ok);
+  Statement ParseDebuggerStatement(bool* ok);
+
+  Expression ParseExpression(bool accept_IN, bool* ok);
+  Expression ParseAssignmentExpression(bool accept_IN, bool* ok);
+  Expression ParseConditionalExpression(bool accept_IN, bool* ok);
+  Expression ParseBinaryExpression(int prec, bool accept_IN, bool* ok);
+  Expression ParseUnaryExpression(bool* ok);
+  Expression ParsePostfixExpression(bool* ok);
+  Expression ParseLeftHandSideExpression(bool* ok);
+  Expression ParseNewExpression(bool* ok);
+  Expression ParseMemberExpression(bool* ok);
+  Expression ParseMemberWithNewPrefixesExpression(unsigned new_count, bool* ok);
+  Expression ParsePrimaryExpression(bool* ok);
+  Expression ParseArrayLiteral(bool* ok);
+  Expression ParseObjectLiteral(bool* ok);
+  Expression ParseRegExpLiteral(bool seen_equal, bool* ok);
+  Expression ParseV8Intrinsic(bool* ok);
+
+  Arguments ParseArguments(bool* ok);
+  Expression ParseFunctionLiteral(bool* ok);
+
+  Identifier ParseIdentifier(bool* ok);
+  Identifier ParseIdentifierName(bool* ok);
+  Identifier ParseIdentifierOrGetOrSet(bool* is_get, bool* is_set, bool* ok);
+
+  Identifier GetIdentifierSymbol();
+  unsigned int HexDigitValue(char digit);
+  Expression GetStringSymbol();
+
+
+  i::Token::Value peek() { return scanner_->peek(); }
+  i::Token::Value Next() {
+    i::Token::Value next = scanner_->Next();
+    return next;
+  }
+
+  void Consume(i::Token::Value token) {
+    Next();
+  }
+
+  void Expect(i::Token::Value token, bool* ok) {
+    if (Next() != token) {
+      *ok = false;
+    }
+  }
+
+  bool Check(i::Token::Value token) {
+    i::Token::Value next = peek();
+    if (next == token) {
+      Consume(next);
+      return true;
+    }
+    return false;
+  }
+  void ExpectSemicolon(bool* ok);
+
+  static int Precedence(i::Token::Value tok, bool accept_IN);
+
+  Scanner* scanner_;
+  PreParserLog* log_;
+  Scope* scope_;
+  bool allow_lazy_;
+};
+
+
+#define CHECK_OK  ok);  \
+  if (!*ok) return -1;  \
+  ((void)0
+#define DUMMY )  // to make indentation work
+#undef DUMMY
+
+
+template <typename Scanner, typename Log>
+void PreParser<Scanner, Log>::ReportUnexpectedToken(i::Token::Value token) {
+  // We don't report stack overflows here, to avoid increasing the
+  // stack depth even further.  Instead we report it after parsing is
+  // over, in ParseProgram.
+  if (token == i::Token::ILLEGAL && scanner_->stack_overflow()) {
+    return;
+  }
+  typename Scanner::Location source_location = scanner_->location();
+
+  // Four of the tokens are treated specially
+  switch (token) {
+  case i::Token::EOS:
+    return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
+                           "unexpected_eos", NULL);
+  case i::Token::NUMBER:
+    return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
+                           "unexpected_token_number", NULL);
+  case i::Token::STRING:
+    return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
+                           "unexpected_token_string", NULL);
+  case i::Token::IDENTIFIER:
+    return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
+                           "unexpected_token_identifier", NULL);
+  default:
+    const char* name = i::Token::String(token);
+    ReportMessageAt(source_location.beg_pos, source_location.end_pos,
+                    "unexpected_token", name);
+  }
+}
+
+
+template <typename Scanner, typename Log>
+SourceElements PreParser<Scanner, Log>::ParseSourceElements(int end_token,
+                                                            bool* ok) {
+  // SourceElements ::
+  //   (Statement)* <end_token>
+
+  while (peek() != end_token) {
+    ParseStatement(CHECK_OK);
+  }
+  return kUnknownSourceElements;
+}
+
+
+template <typename Scanner, typename Log>
+Statement PreParser<Scanner, Log>::ParseStatement(bool* ok) {
+  // Statement ::
+  //   Block
+  //   VariableStatement
+  //   EmptyStatement
+  //   ExpressionStatement
+  //   IfStatement
+  //   IterationStatement
+  //   ContinueStatement
+  //   BreakStatement
+  //   ReturnStatement
+  //   WithStatement
+  //   LabelledStatement
+  //   SwitchStatement
+  //   ThrowStatement
+  //   TryStatement
+  //   DebuggerStatement
+
+  // Note: Since labels can only be used by 'break' and 'continue'
+  // statements, which themselves are only valid within blocks,
+  // iterations or 'switch' statements (i.e., BreakableStatements),
+  // labels can be simply ignored in all other cases; except for
+  // trivial labeled break statements 'label: break label' which is
+  // parsed into an empty statement.
+
+  // Keep the source position of the statement
+  switch (peek()) {
+    case i::Token::LBRACE:
+      return ParseBlock(ok);
+
+    case i::Token::CONST:
+    case i::Token::VAR:
+      return ParseVariableStatement(ok);
+
+    case i::Token::SEMICOLON:
+      Next();
+      return kUnknownStatement;
+
+    case i::Token::IF:
+      return  ParseIfStatement(ok);
+
+    case i::Token::DO:
+      return ParseDoWhileStatement(ok);
+
+    case i::Token::WHILE:
+      return ParseWhileStatement(ok);
+
+    case i::Token::FOR:
+      return ParseForStatement(ok);
+
+    case i::Token::CONTINUE:
+      return ParseContinueStatement(ok);
+
+    case i::Token::BREAK:
+      return ParseBreakStatement(ok);
+
+    case i::Token::RETURN:
+      return ParseReturnStatement(ok);
+
+    case i::Token::WITH:
+      return ParseWithStatement(ok);
+
+    case i::Token::SWITCH:
+      return ParseSwitchStatement(ok);
+
+    case i::Token::THROW:
+      return ParseThrowStatement(ok);
+
+    case i::Token::TRY:
+      return ParseTryStatement(ok);
+
+    case i::Token::FUNCTION:
+      return ParseFunctionDeclaration(ok);
+
+    case i::Token::NATIVE:
+      return ParseNativeDeclaration(ok);
+
+    case i::Token::DEBUGGER:
+      return ParseDebuggerStatement(ok);
+
+    default:
+      return ParseExpressionOrLabelledStatement(ok);
+  }
+}
+
+
+template <typename Scanner, typename Log>
+Statement PreParser<Scanner, Log>::ParseFunctionDeclaration(bool* ok) {
+  // FunctionDeclaration ::
+  //   'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
+  Expect(i::Token::FUNCTION, CHECK_OK);
+  ParseIdentifier(CHECK_OK);
+  ParseFunctionLiteral(CHECK_OK);
+  return kUnknownStatement;
+}
+
+
+// Language extension which is only enabled for source files loaded
+// through the API's extension mechanism.  A native function
+// declaration is resolved by looking up the function through a
+// callback provided by the extension.
+template <typename Scanner, typename Log>
+Statement PreParser<Scanner, Log>::ParseNativeDeclaration(bool* ok) {
+  Expect(i::Token::NATIVE, CHECK_OK);
+  Expect(i::Token::FUNCTION, CHECK_OK);
+  ParseIdentifier(CHECK_OK);
+  Expect(i::Token::LPAREN, CHECK_OK);
+  bool done = (peek() == i::Token::RPAREN);
+  while (!done) {
+    ParseIdentifier(CHECK_OK);
+    done = (peek() == i::Token::RPAREN);
+    if (!done) {
+      Expect(i::Token::COMMA, CHECK_OK);
+    }
+  }
+  Expect(i::Token::RPAREN, CHECK_OK);
+  Expect(i::Token::SEMICOLON, CHECK_OK);
+  return kUnknownStatement;
+}
+
+
+template <typename Scanner, typename Log>
+Statement PreParser<Scanner, Log>::ParseBlock(bool* ok) {
+  // Block ::
+  //   '{' Statement* '}'
+
+  // Note that a Block does not introduce a new execution scope!
+  // (ECMA-262, 3rd, 12.2)
+  //
+  Expect(i::Token::LBRACE, CHECK_OK);
+  while (peek() != i::Token::RBRACE) {
+    ParseStatement(CHECK_OK);
+  }
+  Expect(i::Token::RBRACE, CHECK_OK);
+  return kUnknownStatement;
+}
+
+
+template <typename Scanner, typename Log>
+Statement PreParser<Scanner, Log>::ParseVariableStatement(bool* ok) {
+  // VariableStatement ::
+  //   VariableDeclarations ';'
+
+  Statement result = ParseVariableDeclarations(true, NULL, CHECK_OK);
+  ExpectSemicolon(CHECK_OK);
+  return result;
+}
+
+
+// If the variable declaration declares exactly one non-const
+// variable, then *var is set to that variable. In all other cases,
+// *var is untouched; in particular, it is the caller's responsibility
+// to initialize it properly. This mechanism is also used for the parsing
+// of 'for-in' loops.
+template <typename Scanner, typename Log>
+Statement PreParser<Scanner, Log>::ParseVariableDeclarations(bool accept_IN,
+                                                  int* num_decl,
+                                                  bool* ok) {
+  // VariableDeclarations ::
+  //   ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[',']
+
+  if (peek() == i::Token::VAR) {
+    Consume(i::Token::VAR);
+  } else if (peek() == i::Token::CONST) {
+    Consume(i::Token::CONST);
+  } else {
+    *ok = false;
+    return 0;
+  }
+
+  // The scope of a variable/const declared anywhere inside a function
+  // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). .
+  int nvars = 0;  // the number of variables declared
+  do {
+    // Parse variable name.
+    if (nvars > 0) Consume(i::Token::COMMA);
+    ParseIdentifier(CHECK_OK);
+    nvars++;
+    if (peek() == i::Token::ASSIGN) {
+      Expect(i::Token::ASSIGN, CHECK_OK);
+      ParseAssignmentExpression(accept_IN, CHECK_OK);
+    }
+  } while (peek() == i::Token::COMMA);
+
+  if (num_decl != NULL) *num_decl = nvars;
+  return kUnknownStatement;
+}
+
+
+template <typename Scanner, typename Log>
+Statement PreParser<Scanner, Log>::ParseExpressionOrLabelledStatement(
+    bool* ok) {
+  // ExpressionStatement | LabelledStatement ::
+  //   Expression ';'
+  //   Identifier ':' Statement
+
+  Expression expr = ParseExpression(true, CHECK_OK);
+  if (peek() == i::Token::COLON && expr == kIdentifierExpression) {
+    Consume(i::Token::COLON);
+    return ParseStatement(ok);
+  }
+  // Parsed expression statement.
+  ExpectSemicolon(CHECK_OK);
+  return kUnknownStatement;
+}
+
+
+template <typename Scanner, typename Log>
+Statement PreParser<Scanner, Log>::ParseIfStatement(bool* ok) {
+  // IfStatement ::
+  //   'if' '(' Expression ')' Statement ('else' Statement)?
+
+  Expect(i::Token::IF, CHECK_OK);
+  Expect(i::Token::LPAREN, CHECK_OK);
+  ParseExpression(true, CHECK_OK);
+  Expect(i::Token::RPAREN, CHECK_OK);
+  ParseStatement(CHECK_OK);
+  if (peek() == i::Token::ELSE) {
+    Next();
+    ParseStatement(CHECK_OK);
+  }
+  return kUnknownStatement;
+}
+
+
+template <typename Scanner, typename Log>
+Statement PreParser<Scanner, Log>::ParseContinueStatement(bool* ok) {
+  // ContinueStatement ::
+  //   'continue' [no line terminator] Identifier? ';'
+
+  Expect(i::Token::CONTINUE, CHECK_OK);
+  i::Token::Value tok = peek();
+  if (!scanner_->has_line_terminator_before_next() &&
+      tok != i::Token::SEMICOLON &&
+      tok != i::Token::RBRACE &&
+      tok != i::Token::EOS) {
+    ParseIdentifier(CHECK_OK);
+  }
+  ExpectSemicolon(CHECK_OK);
+  return kUnknownStatement;
+}
+
+
+template <typename Scanner, typename Log>
+Statement PreParser<Scanner, Log>::ParseBreakStatement(bool* ok) {
+  // BreakStatement ::
+  //   'break' [no line terminator] Identifier? ';'
+
+  Expect(i::Token::BREAK, CHECK_OK);
+  i::Token::Value tok = peek();
+  if (!scanner_->has_line_terminator_before_next() &&
+      tok != i::Token::SEMICOLON &&
+      tok != i::Token::RBRACE &&
+      tok != i::Token::EOS) {
+    ParseIdentifier(CHECK_OK);
+  }
+  ExpectSemicolon(CHECK_OK);
+  return kUnknownStatement;
+}
+
+
+template <typename Scanner, typename Log>
+Statement PreParser<Scanner, Log>::ParseReturnStatement(bool* ok) {
+  // ReturnStatement ::
+  //   'return' [no line terminator] Expression? ';'
+
+  // Consume the return token. It is necessary to do the before
+  // reporting any errors on it, because of the way errors are
+  // reported (underlining).
+  Expect(i::Token::RETURN, CHECK_OK);
+
+  // An ECMAScript program is considered syntactically incorrect if it
+  // contains a return statement that is not within the body of a
+  // function. See ECMA-262, section 12.9, page 67.
+  // This is not handled during preparsing.
+
+  i::Token::Value tok = peek();
+  if (!scanner_->has_line_terminator_before_next() &&
+      tok != i::Token::SEMICOLON &&
+      tok != i::Token::RBRACE &&
+      tok != i::Token::EOS) {
+    ParseExpression(true, CHECK_OK);
+  }
+  ExpectSemicolon(CHECK_OK);
+  return kUnknownStatement;
+}
+
+
+template <typename Scanner, typename Log>
+Statement PreParser<Scanner, Log>::ParseWithStatement(bool* ok) {
+  // WithStatement ::
+  //   'with' '(' Expression ')' Statement
+  Expect(i::Token::WITH, CHECK_OK);
+  Expect(i::Token::LPAREN, CHECK_OK);
+  ParseExpression(true, CHECK_OK);
+  Expect(i::Token::RPAREN, CHECK_OK);
+
+  scope_->EnterWith();
+  ParseStatement(CHECK_OK);
+  scope_->LeaveWith();
+  return kUnknownStatement;
+}
+
+
+template <typename Scanner, typename Log>
+Statement PreParser<Scanner, Log>::ParseSwitchStatement(bool* ok) {
+  // SwitchStatement ::
+  //   'switch' '(' Expression ')' '{' CaseClause* '}'
+
+  Expect(i::Token::SWITCH, CHECK_OK);
+  Expect(i::Token::LPAREN, CHECK_OK);
+  ParseExpression(true, CHECK_OK);
+  Expect(i::Token::RPAREN, CHECK_OK);
+
+  Expect(i::Token::LBRACE, CHECK_OK);
+  i::Token::Value token = peek();
+  while (token != i::Token::RBRACE) {
+    if (token == i::Token::CASE) {
+      Expect(i::Token::CASE, CHECK_OK);
+      ParseExpression(true, CHECK_OK);
+      Expect(i::Token::COLON, CHECK_OK);
+    } else if (token == i::Token::DEFAULT) {
+      Expect(i::Token::DEFAULT, CHECK_OK);
+      Expect(i::Token::COLON, CHECK_OK);
+    } else {
+      ParseStatement(CHECK_OK);
+    }
+    token = peek();
+  }
+  Expect(i::Token::RBRACE, CHECK_OK);
+
+  return kUnknownStatement;
+}
+
+
+template <typename Scanner, typename Log>
+Statement PreParser<Scanner, Log>::ParseDoWhileStatement(bool* ok) {
+  // DoStatement ::
+  //   'do' Statement 'while' '(' Expression ')' ';'
+
+  Expect(i::Token::DO, CHECK_OK);
+  ParseStatement(CHECK_OK);
+  Expect(i::Token::WHILE, CHECK_OK);
+  Expect(i::Token::LPAREN, CHECK_OK);
+  ParseExpression(true, CHECK_OK);
+  Expect(i::Token::RPAREN, CHECK_OK);
+  return kUnknownStatement;
+}
+
+
+template <typename Scanner, typename Log>
+Statement PreParser<Scanner, Log>::ParseWhileStatement(bool* ok) {
+  // WhileStatement ::
+  //   'while' '(' Expression ')' Statement
+
+  Expect(i::Token::WHILE, CHECK_OK);
+  Expect(i::Token::LPAREN, CHECK_OK);
+  ParseExpression(true, CHECK_OK);
+  Expect(i::Token::RPAREN, CHECK_OK);
+  ParseStatement(CHECK_OK);
+  return kUnknownStatement;
+}
+
+
+template <typename Scanner, typename Log>
+Statement PreParser<Scanner, Log>::ParseForStatement(bool* ok) {
+  // ForStatement ::
+  //   'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
+
+  Expect(i::Token::FOR, CHECK_OK);
+  Expect(i::Token::LPAREN, CHECK_OK);
+  if (peek() != i::Token::SEMICOLON) {
+    if (peek() == i::Token::VAR || peek() == i::Token::CONST) {
+      int decl_count;
+      ParseVariableDeclarations(false, &decl_count, CHECK_OK);
+      if (peek() == i::Token::IN && decl_count == 1) {
+        Expect(i::Token::IN, CHECK_OK);
+        ParseExpression(true, CHECK_OK);
+        Expect(i::Token::RPAREN, CHECK_OK);
+
+        ParseStatement(CHECK_OK);
+        return kUnknownStatement;
+      }
+    } else {
+      ParseExpression(false, CHECK_OK);
+      if (peek() == i::Token::IN) {
+        Expect(i::Token::IN, CHECK_OK);
+        ParseExpression(true, CHECK_OK);
+        Expect(i::Token::RPAREN, CHECK_OK);
+
+        ParseStatement(CHECK_OK);
+        return kUnknownStatement;
+      }
+    }
+  }
+
+  // Parsed initializer at this point.
+  Expect(i::Token::SEMICOLON, CHECK_OK);
+
+  if (peek() != i::Token::SEMICOLON) {
+    ParseExpression(true, CHECK_OK);
+  }
+  Expect(i::Token::SEMICOLON, CHECK_OK);
+
+  if (peek() != i::Token::RPAREN) {
+    ParseExpression(true, CHECK_OK);
+  }
+  Expect(i::Token::RPAREN, CHECK_OK);
+
+  ParseStatement(CHECK_OK);
+  return kUnknownStatement;
+}
+
+
+template <typename Scanner, typename Log>
+Statement PreParser<Scanner, Log>::ParseThrowStatement(bool* ok) {
+  // ThrowStatement ::
+  //   'throw' [no line terminator] Expression ';'
+
+  Expect(i::Token::THROW, CHECK_OK);
+  if (scanner_->has_line_terminator_before_next()) {
+    typename Scanner::Location pos = scanner_->location();
+    ReportMessageAt(pos.beg_pos, pos.end_pos,
+                    "newline_after_throw", NULL);
+    *ok = false;
+    return NULL;
+  }
+  ParseExpression(true, CHECK_OK);
+  ExpectSemicolon(CHECK_OK);
+
+  return kUnknownStatement;
+}
+
+
+template <typename Scanner, typename Log>
+Statement PreParser<Scanner, Log>::ParseTryStatement(bool* ok) {
+  // TryStatement ::
+  //   'try' Block Catch
+  //   'try' Block Finally
+  //   'try' Block Catch Finally
+  //
+  // Catch ::
+  //   'catch' '(' Identifier ')' Block
+  //
+  // Finally ::
+  //   'finally' Block
+
+  // In preparsing, allow any number of catch/finally blocks, including zero
+  // of both.
+
+  Expect(i::Token::TRY, CHECK_OK);
+
+  ParseBlock(CHECK_OK);
+
+  bool catch_or_finally_seen = false;
+  if (peek() == i::Token::CATCH) {
+    Consume(i::Token::CATCH);
+    Expect(i::Token::LPAREN, CHECK_OK);
+    ParseIdentifier(CHECK_OK);
+    Expect(i::Token::RPAREN, CHECK_OK);
+    scope_->EnterWith();
+    ParseBlock(ok);
+    scope_->LeaveWith();
+    if (!*ok) return kUnknownStatement;
+    catch_or_finally_seen = true;
+  }
+  if (peek() == i::Token::FINALLY) {
+    Consume(i::Token::FINALLY);
+    ParseBlock(CHECK_OK);
+    catch_or_finally_seen = true;
+  }
+  if (!catch_or_finally_seen) {
+    *ok = false;
+  }
+  return kUnknownStatement;
+}
+
+
+template <typename Scanner, typename Log>
+Statement PreParser<Scanner, Log>::ParseDebuggerStatement(bool* ok) {
+  // In ECMA-262 'debugger' is defined as a reserved keyword. In some browser
+  // contexts this is used as a statement which invokes the debugger as if a
+  // break point is present.
+  // DebuggerStatement ::
+  //   'debugger' ';'
+
+  Expect(i::Token::DEBUGGER, CHECK_OK);
+  ExpectSemicolon(CHECK_OK);
+  return kUnknownStatement;
+}
+
+
+// Precedence = 1
+template <typename Scanner, typename Log>
+Expression PreParser<Scanner, Log>::ParseExpression(bool accept_IN, bool* ok) {
+  // Expression ::
+  //   AssignmentExpression
+  //   Expression ',' AssignmentExpression
+
+  Expression result = ParseAssignmentExpression(accept_IN, CHECK_OK);
+  while (peek() == i::Token::COMMA) {
+    Expect(i::Token::COMMA, CHECK_OK);
+    ParseAssignmentExpression(accept_IN, CHECK_OK);
+    result = kUnknownExpression;
+  }
+  return result;
+}
+
+
+// Precedence = 2
+template <typename Scanner, typename Log>
+Expression PreParser<Scanner, Log>::ParseAssignmentExpression(bool accept_IN,
+                                                              bool* ok) {
+  // AssignmentExpression ::
+  //   ConditionalExpression
+  //   LeftHandSideExpression AssignmentOperator AssignmentExpression
+
+  Expression expression = ParseConditionalExpression(accept_IN, CHECK_OK);
+
+  if (!i::Token::IsAssignmentOp(peek())) {
+    // Parsed conditional expression only (no assignment).
+    return expression;
+  }
+
+  i::Token::Value op = Next();  // Get assignment operator.
+  ParseAssignmentExpression(accept_IN, CHECK_OK);
+
+  if ((op == i::Token::ASSIGN) && (expression == kThisPropertyExpression)) {
+    scope_->AddProperty();
+  }
+
+  return kUnknownExpression;
+}
+
+
+// Precedence = 3
+template <typename Scanner, typename Log>
+Expression PreParser<Scanner, Log>::ParseConditionalExpression(bool accept_IN,
+                                                               bool* ok) {
+  // ConditionalExpression ::
+  //   LogicalOrExpression
+  //   LogicalOrExpression '?' AssignmentExpression ':' AssignmentExpression
+
+  // We start using the binary expression parser for prec >= 4 only!
+  Expression expression = ParseBinaryExpression(4, accept_IN, CHECK_OK);
+  if (peek() != i::Token::CONDITIONAL) return expression;
+  Consume(i::Token::CONDITIONAL);
+  // In parsing the first assignment expression in conditional
+  // expressions we always accept the 'in' keyword; see ECMA-262,
+  // section 11.12, page 58.
+  ParseAssignmentExpression(true, CHECK_OK);
+  Expect(i::Token::COLON, CHECK_OK);
+  ParseAssignmentExpression(accept_IN, CHECK_OK);
+  return kUnknownExpression;
+}
+
+
+template <typename Scanner, typename Log>
+int PreParser<Scanner, Log>::Precedence(i::Token::Value tok, bool accept_IN) {
+  if (tok == i::Token::IN && !accept_IN)
+    return 0;  // 0 precedence will terminate binary expression parsing
+
+  return i::Token::Precedence(tok);
+}
+
+
+// Precedence >= 4
+template <typename Scanner, typename Log>
+Expression PreParser<Scanner, Log>::ParseBinaryExpression(int prec,
+                                                          bool accept_IN,
+                                                          bool* ok) {
+  Expression result = ParseUnaryExpression(CHECK_OK);
+  for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) {
+    // prec1 >= 4
+    while (Precedence(peek(), accept_IN) == prec1) {
+      Next();
+      ParseBinaryExpression(prec1 + 1, accept_IN, CHECK_OK);
+      result = kUnknownExpression;
+    }
+  }
+  return result;
+}
+
+
+template <typename Scanner, typename Log>
+Expression PreParser<Scanner, Log>::ParseUnaryExpression(bool* ok) {
+  // UnaryExpression ::
+  //   PostfixExpression
+  //   'delete' UnaryExpression
+  //   'void' UnaryExpression
+  //   'typeof' UnaryExpression
+  //   '++' UnaryExpression
+  //   '--' UnaryExpression
+  //   '+' UnaryExpression
+  //   '-' UnaryExpression
+  //   '~' UnaryExpression
+  //   '!' UnaryExpression
+
+  i::Token::Value op = peek();
+  if (i::Token::IsUnaryOp(op) || i::Token::IsCountOp(op)) {
+    op = Next();
+    ParseUnaryExpression(ok);
+    return kUnknownExpression;
+  } else {
+    return ParsePostfixExpression(ok);
+  }
+}
+
+
+template <typename Scanner, typename Log>
+Expression PreParser<Scanner, Log>::ParsePostfixExpression(bool* ok) {
+  // PostfixExpression ::
+  //   LeftHandSideExpression ('++' | '--')?
+
+  Expression expression = ParseLeftHandSideExpression(CHECK_OK);
+  if (!scanner_->has_line_terminator_before_next() &&
+      i::Token::IsCountOp(peek())) {
+    Next();
+    return kUnknownExpression;
+  }
+  return expression;
+}
+
+
+template <typename Scanner, typename Log>
+Expression PreParser<Scanner, Log>::ParseLeftHandSideExpression(bool* ok) {
+  // LeftHandSideExpression ::
+  //   (NewExpression | MemberExpression) ...
+
+  Expression result;
+  if (peek() == i::Token::NEW) {
+    result = ParseNewExpression(CHECK_OK);
+  } else {
+    result = ParseMemberExpression(CHECK_OK);
+  }
+
+  while (true) {
+    switch (peek()) {
+      case i::Token::LBRACK: {
+        Consume(i::Token::LBRACK);
+        ParseExpression(true, CHECK_OK);
+        Expect(i::Token::RBRACK, CHECK_OK);
+        if (result == kThisExpression) {
+          result = kThisPropertyExpression;
+        } else {
+          result = kUnknownExpression;
+        }
+        break;
+      }
+
+      case i::Token::LPAREN: {
+        ParseArguments(CHECK_OK);
+        result = kUnknownExpression;
+        break;
+      }
+
+      case i::Token::PERIOD: {
+        Consume(i::Token::PERIOD);
+        ParseIdentifierName(CHECK_OK);
+        if (result == kThisExpression) {
+          result = kThisPropertyExpression;
+        } else {
+          result = kUnknownExpression;
+        }
+        break;
+      }
+
+      default:
+        return result;
+    }
+  }
+}
+
+
+template <typename Scanner, typename Log>
+Expression PreParser<Scanner, Log>::ParseNewExpression(bool* ok) {
+  // NewExpression ::
+  //   ('new')+ MemberExpression
+
+  // The grammar for new expressions is pretty warped. The keyword
+  // 'new' can either be a part of the new expression (where it isn't
+  // followed by an argument list) or a part of the member expression,
+  // where it must be followed by an argument list. To accommodate
+  // this, we parse the 'new' keywords greedily and keep track of how
+  // many we have parsed. This information is then passed on to the
+  // member expression parser, which is only allowed to match argument
+  // lists as long as it has 'new' prefixes left
+  unsigned new_count = 0;
+  do {
+    Consume(i::Token::NEW);
+    new_count++;
+  } while (peek() == i::Token::NEW);
+
+  return ParseMemberWithNewPrefixesExpression(new_count, ok);
+}
+
+
+template <typename Scanner, typename Log>
+Expression PreParser<Scanner, Log>::ParseMemberExpression(bool* ok) {
+  return ParseMemberWithNewPrefixesExpression(0, ok);
+}
+
+
+template <typename Scanner, typename Log>
+Expression PreParser<Scanner, Log>::ParseMemberWithNewPrefixesExpression(
+    unsigned new_count, bool* ok) {
+  // MemberExpression ::
+  //   (PrimaryExpression | FunctionLiteral)
+  //     ('[' Expression ']' | '.' Identifier | Arguments)*
+
+  // Parse the initial primary or function expression.
+  Expression result = NULL;
+  if (peek() == i::Token::FUNCTION) {
+    Consume(i::Token::FUNCTION);
+    if (peek() == i::Token::IDENTIFIER) {
+      ParseIdentifier(CHECK_OK);
+    }
+    result = ParseFunctionLiteral(CHECK_OK);
+  } else {
+    result = ParsePrimaryExpression(CHECK_OK);
+  }
+
+  while (true) {
+    switch (peek()) {
+      case i::Token::LBRACK: {
+        Consume(i::Token::LBRACK);
+        ParseExpression(true, CHECK_OK);
+        Expect(i::Token::RBRACK, CHECK_OK);
+        if (result == kThisExpression) {
+          result = kThisPropertyExpression;
+        } else {
+          result = kUnknownExpression;
+        }
+        break;
+      }
+      case i::Token::PERIOD: {
+        Consume(i::Token::PERIOD);
+        ParseIdentifierName(CHECK_OK);
+        if (result == kThisExpression) {
+          result = kThisPropertyExpression;
+        } else {
+          result = kUnknownExpression;
+        }
+        break;
+      }
+      case i::Token::LPAREN: {
+        if (new_count == 0) return result;
+        // Consume one of the new prefixes (already parsed).
+        ParseArguments(CHECK_OK);
+        new_count--;
+        result = kUnknownExpression;
+        break;
+      }
+      default:
+        return result;
+    }
+  }
+}
+
+
+template <typename Scanner, typename Log>
+Expression PreParser<Scanner, Log>::ParsePrimaryExpression(bool* ok) {
+  // PrimaryExpression ::
+  //   'this'
+  //   'null'
+  //   'true'
+  //   'false'
+  //   Identifier
+  //   Number
+  //   String
+  //   ArrayLiteral
+  //   ObjectLiteral
+  //   RegExpLiteral
+  //   '(' Expression ')'
+
+  Expression result = kUnknownExpression;
+  switch (peek()) {
+    case i::Token::THIS: {
+      Next();
+      result = kThisExpression;
+      break;
+    }
+
+    case i::Token::IDENTIFIER: {
+      ParseIdentifier(CHECK_OK);
+      result = kIdentifierExpression;
+      break;
+    }
+
+    case i::Token::NULL_LITERAL:
+    case i::Token::TRUE_LITERAL:
+    case i::Token::FALSE_LITERAL:
+    case i::Token::NUMBER: {
+      Next();
+      break;
+    }
+    case i::Token::STRING: {
+      Next();
+      result = GetStringSymbol();
+      break;
+    }
+
+    case i::Token::ASSIGN_DIV:
+      result = ParseRegExpLiteral(true, CHECK_OK);
+      break;
+
+    case i::Token::DIV:
+      result = ParseRegExpLiteral(false, CHECK_OK);
+      break;
+
+    case i::Token::LBRACK:
+      result = ParseArrayLiteral(CHECK_OK);
+      break;
+
+    case i::Token::LBRACE:
+      result = ParseObjectLiteral(CHECK_OK);
+      break;
+
+    case i::Token::LPAREN:
+      Consume(i::Token::LPAREN);
+      result = ParseExpression(true, CHECK_OK);
+      Expect(i::Token::RPAREN, CHECK_OK);
+      if (result == kIdentifierExpression) result = kUnknownExpression;
+      break;
+
+    case i::Token::MOD:
+      result = ParseV8Intrinsic(CHECK_OK);
+      break;
+
+    default: {
+      Next();
+      *ok = false;
+      return kUnknownExpression;
+    }
+  }
+
+  return result;
+}
+
+
+template <typename Scanner, typename Log>
+Expression PreParser<Scanner, Log>::ParseArrayLiteral(bool* ok) {
+  // ArrayLiteral ::
+  //   '[' Expression? (',' Expression?)* ']'
+  Expect(i::Token::LBRACK, CHECK_OK);
+  while (peek() != i::Token::RBRACK) {
+    if (peek() != i::Token::COMMA) {
+      ParseAssignmentExpression(true, CHECK_OK);
+    }
+    if (peek() != i::Token::RBRACK) {
+      Expect(i::Token::COMMA, CHECK_OK);
+    }
+  }
+  Expect(i::Token::RBRACK, CHECK_OK);
+
+  scope_->NextMaterializedLiteralIndex();
+  return kUnknownExpression;
+}
+
+
+template <typename Scanner, typename Log>
+Expression PreParser<Scanner, Log>::ParseObjectLiteral(bool* ok) {
+  // ObjectLiteral ::
+  //   '{' (
+  //       ((IdentifierName | String | Number) ':' AssignmentExpression)
+  //     | (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral)
+  //    )*[','] '}'
+
+  Expect(i::Token::LBRACE, CHECK_OK);
+  while (peek() != i::Token::RBRACE) {
+    i::Token::Value next = peek();
+    switch (next) {
+      case i::Token::IDENTIFIER: {
+        bool is_getter = false;
+        bool is_setter = false;
+        ParseIdentifierOrGetOrSet(&is_getter, &is_setter, CHECK_OK);
+        if ((is_getter || is_setter) && peek() != i::Token::COLON) {
+            i::Token::Value name = Next();
+            if (name != i::Token::IDENTIFIER &&
+                name != i::Token::NUMBER &&
+                name != i::Token::STRING &&
+                !i::Token::IsKeyword(name)) {
+              *ok = false;
+              return kUnknownExpression;
+            }
+            ParseFunctionLiteral(CHECK_OK);
+            if (peek() != i::Token::RBRACE) {
+              Expect(i::Token::COMMA, CHECK_OK);
+            }
+            continue;  // restart the while
+        }
+        break;
+      }
+      case i::Token::STRING:
+        Consume(next);
+        GetStringSymbol();
+        break;
+      case i::Token::NUMBER:
+        Consume(next);
+        break;
+      default:
+        if (i::Token::IsKeyword(next)) {
+          Consume(next);
+        } else {
+          // Unexpected token.
+          *ok = false;
+          return kUnknownExpression;
+        }
+    }
+
+    Expect(i::Token::COLON, CHECK_OK);
+    ParseAssignmentExpression(true, CHECK_OK);
+
+    // TODO(1240767): Consider allowing trailing comma.
+    if (peek() != i::Token::RBRACE) Expect(i::Token::COMMA, CHECK_OK);
+  }
+  Expect(i::Token::RBRACE, CHECK_OK);
+
+  scope_->NextMaterializedLiteralIndex();
+  return kUnknownExpression;
+}
+
+
+template <typename Scanner, typename Log>
+Expression PreParser<Scanner, Log>::ParseRegExpLiteral(bool seen_equal,
+                                                       bool* ok) {
+  if (!scanner_->ScanRegExpPattern(seen_equal)) {
+    Next();
+    typename Scanner::Location location = scanner_->location();
+    ReportMessageAt(location.beg_pos, location.end_pos,
+                    "unterminated_regexp", NULL);
+    *ok = false;
+    return kUnknownExpression;
+  }
+
+  scope_->NextMaterializedLiteralIndex();
+
+  if (!scanner_->ScanRegExpFlags()) {
+    Next();
+    typename Scanner::Location location = scanner_->location();
+    ReportMessageAt(location.beg_pos, location.end_pos,
+                    "invalid_regexp_flags", NULL);
+    *ok = false;
+    return kUnknownExpression;
+  }
+  Next();
+  return kUnknownExpression;
+}
+
+
+template <typename Scanner, typename Log>
+Arguments PreParser<Scanner, Log>::ParseArguments(bool* ok) {
+  // Arguments ::
+  //   '(' (AssignmentExpression)*[','] ')'
+
+  Expect(i::Token::LPAREN, CHECK_OK);
+  bool done = (peek() == i::Token::RPAREN);
+  int argc = 0;
+  while (!done) {
+    ParseAssignmentExpression(true, CHECK_OK);
+    argc++;
+    done = (peek() == i::Token::RPAREN);
+    if (!done) Expect(i::Token::COMMA, CHECK_OK);
+  }
+  Expect(i::Token::RPAREN, CHECK_OK);
+  return argc;
+}
+
+
+template <typename Scanner, typename Log>
+Expression PreParser<Scanner, Log>::ParseFunctionLiteral(bool* ok) {
+  // Function ::
+  //   '(' FormalParameterList? ')' '{' FunctionBody '}'
+
+  // Parse function body.
+  ScopeType outer_scope_type = scope_->type();
+  bool inside_with = scope_->IsInsideWith();
+  Scope function_scope(&scope_, kFunctionScope);
+
+  //  FormalParameterList ::
+  //    '(' (Identifier)*[','] ')'
+  Expect(i::Token::LPAREN, CHECK_OK);
+  bool done = (peek() == i::Token::RPAREN);
+  while (!done) {
+    ParseIdentifier(CHECK_OK);
+    done = (peek() == i::Token::RPAREN);
+    if (!done) {
+      Expect(i::Token::COMMA, CHECK_OK);
+    }
+  }
+  Expect(i::Token::RPAREN, CHECK_OK);
+
+  Expect(i::Token::LBRACE, CHECK_OK);
+  int function_block_pos = scanner_->location().beg_pos;
+
+  // Determine if the function will be lazily compiled.
+  // Currently only happens to top-level functions.
+  // Optimistically assume that all top-level functions are lazily compiled.
+  bool is_lazily_compiled =
+      (outer_scope_type == kTopLevelScope && !inside_with && allow_lazy_);
+
+  if (is_lazily_compiled) {
+    log_->PauseRecording();
+    ParseSourceElements(i::Token::RBRACE, ok);
+    log_->ResumeRecording();
+    if (!*ok) return kUnknownExpression;
+
+    Expect(i::Token::RBRACE, CHECK_OK);
+
+    int end_pos = scanner_->location().end_pos;
+    log_->LogFunction(function_block_pos, end_pos,
+                      function_scope.materialized_literal_count(),
+                      function_scope.expected_properties());
+  } else {
+    ParseSourceElements(i::Token::RBRACE, CHECK_OK);
+    Expect(i::Token::RBRACE, CHECK_OK);
+  }
+  return kUnknownExpression;
+}
+
+
+template <typename Scanner, typename Log>
+Expression PreParser<Scanner, Log>::ParseV8Intrinsic(bool* ok) {
+  // CallRuntime ::
+  //   '%' Identifier Arguments
+
+  Expect(i::Token::MOD, CHECK_OK);
+  ParseIdentifier(CHECK_OK);
+  ParseArguments(CHECK_OK);
+
+  return kUnknownExpression;
+}
+
+
+template <typename Scanner, typename Log>
+void PreParser<Scanner, Log>::ExpectSemicolon(bool* ok) {
+  // Check for automatic semicolon insertion according to
+  // the rules given in ECMA-262, section 7.9, page 21.
+  i::Token::Value tok = peek();
+  if (tok == i::Token::SEMICOLON) {
+    Next();
+    return;
+  }
+  if (scanner_->has_line_terminator_before_next() ||
+      tok == i::Token::RBRACE ||
+      tok == i::Token::EOS) {
+    return;
+  }
+  Expect(i::Token::SEMICOLON, ok);
+}
+
+
+template <typename Scanner, typename Log>
+Identifier PreParser<Scanner, Log>::GetIdentifierSymbol() {
+  const char* literal_chars = scanner_->literal_string();
+  int literal_length = scanner_->literal_length();
+  int identifier_pos = scanner_->location().beg_pos;
+
+  log_->LogSymbol(identifier_pos, literal_chars, literal_length);
+
+  return kUnknownExpression;
+}
+
+
+template <typename Scanner, typename Log>
+Expression PreParser<Scanner, Log>::GetStringSymbol() {
+  const char* literal_chars = scanner_->literal_string();
+  int literal_length = scanner_->literal_length();
+
+  int literal_position = scanner_->location().beg_pos;
+  log_->LogSymbol(literal_position, literal_chars, literal_length);
+
+  return kUnknownExpression;
+}
+
+
+template <typename Scanner, typename Log>
+Identifier PreParser<Scanner, Log>::ParseIdentifier(bool* ok) {
+  Expect(i::Token::IDENTIFIER, ok);
+  if (!*ok) return kUnknownIdentifier;
+  return GetIdentifierSymbol();
+}
+
+
+template <typename Scanner, typename Log>
+Identifier PreParser<Scanner, Log>::ParseIdentifierName(bool* ok) {
+  i::Token::Value next = Next();
+  if (i::Token::IsKeyword(next)) {
+    int pos = scanner_->location().beg_pos;
+    const char* keyword = i::Token::String(next);
+    log_->LogSymbol(pos, keyword, i::StrLength(keyword));
+    return kUnknownExpression;
+  }
+  if (next == i::Token::IDENTIFIER) {
+    return GetIdentifierSymbol();
+  }
+  *ok = false;
+  return kUnknownIdentifier;
+}
+
+
+// This function reads an identifier and determines whether or not it
+// is 'get' or 'set'.  The reason for not using ParseIdentifier and
+// checking on the output is that this involves heap allocation which
+// we can't do during preparsing.
+template <typename Scanner, typename Log>
+Identifier PreParser<Scanner, Log>::ParseIdentifierOrGetOrSet(bool* is_get,
+                                                   bool* is_set,
+                                                   bool* ok) {
+  Expect(i::Token::IDENTIFIER, CHECK_OK);
+  if (scanner_->literal_length() == 3) {
+    const char* token = scanner_->literal_string();
+    *is_get = strncmp(token, "get", 3) == 0;
+    *is_set = !*is_get && strncmp(token, "set", 3) == 0;
+  }
+  return GetIdentifierSymbol();
+}
+
+#undef CHECK_OK
+} }  // v8::preparser
+
+#endif  // V8_PREPARSER_H
diff --git a/deps/v8/src/prescanner.h b/deps/v8/src/prescanner.h
new file mode 100644 (file)
index 0000000..7fb8aa5
--- /dev/null
@@ -0,0 +1,1098 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_PRESCANNER_H_
+#define V8_PRESCANNER_H_
+
+#include "token.h"
+#include "char-predicates-inl.h"
+#include "utils.h"
+#include "scanner-base.h"
+
+namespace v8 {
+namespace preparser {
+
+namespace i = v8::internal;
+
+typedef int uc32;
+
+int HexValue(uc32 c) {
+  int res = c | 0x20;  // Uppercase letters.
+  int is_digit = (c & 0x10) >> 4;  // 0 if non-digit, 1 if digit.
+  // What to add to digits to make them consecutive with 'a'-'f' letters.
+  int kDelta = 'a' - '9' - 1;
+  // What to subtract to digits and letters to get them back to the range 0..15.
+  int kStart = '0' + kDelta;
+  res -= kStart;
+  res += kDelta * is_digit;
+  return res;
+}
+
+
+class PreScannerStackGuard {
+ public:
+  explicit PreScannerStackGuard(int max_size)
+      : limit_(StackPoint().at() - max_size) { }
+  bool has_overflowed() {
+    return StackPoint().at() < limit_;
+  }
+ private:
+  class StackPoint {
+   public:
+    char* at() { return reinterpret_cast<char*>(this); }
+  };
+  char* limit_;
+};
+
+
+// Scanner for preparsing.
+// InputStream is a source of UC16 characters with limited push-back.
+// LiteralsBuffer is a collector of (UTF-8) characters used to capture literals.
+template <typename InputStream, typename LiteralsBuffer>
+class Scanner {
+ public:
+  enum LiteralType {
+    kLiteralNumber,
+    kLiteralIdentifier,
+    kLiteralString,
+    kLiteralRegExp,
+    kLiteralRegExpFlags
+  };
+
+  class LiteralScope {
+   public:
+    explicit LiteralScope(Scanner* self, LiteralType type);
+    ~LiteralScope();
+    void Complete();
+
+   private:
+    Scanner* scanner_;
+    bool complete_;
+  };
+
+  Scanner();
+
+  void Initialize(InputStream* stream);
+
+  // Returns the next token.
+  i::Token::Value Next();
+
+  // Returns the current token again.
+  i::Token::Value current_token() { return current_.token; }
+
+  // One token look-ahead (past the token returned by Next()).
+  i::Token::Value peek() const { return next_.token; }
+
+  // Returns true if there was a line terminator before the peek'ed token.
+  bool has_line_terminator_before_next() const {
+    return has_line_terminator_before_next_;
+  }
+
+  struct Location {
+    Location(int b, int e) : beg_pos(b), end_pos(e) { }
+    Location() : beg_pos(0), end_pos(0) { }
+    int beg_pos;
+    int end_pos;
+  };
+
+  // Returns the location information for the current token
+  // (the token returned by Next()).
+  Location location() const { return current_.location; }
+  // Returns the location information for the look-ahead token
+  // (the token returned by peek()).
+  Location peek_location() const { return next_.location; }
+
+  // Returns the literal string, if any, for the current token (the
+  // token returned by Next()). The string is 0-terminated and in
+  // UTF-8 format; they may contain 0-characters. Literal strings are
+  // collected for identifiers, strings, and numbers.
+  // These functions only give the correct result if the literal
+  // was scanned between calls to StartLiteral() and TerminateLiteral().
+  const char* literal_string() const {
+    return current_.literal_chars;
+  }
+
+  int literal_length() const {
+    // Excluding terminal '\x00' added by TerminateLiteral().
+    return current_.literal_length - 1;
+  }
+
+  i::Vector<const char> literal() const {
+    return i::Vector<const char>(literal_string(), literal_length());
+  }
+
+  // Returns the literal string for the next token (the token that
+  // would be returned if Next() were called).
+  const char* next_literal_string() const {
+    return next_.literal_chars;
+  }
+
+
+  // Returns the length of the next token (that would be returned if
+  // Next() were called).
+  int next_literal_length() const {
+    // Excluding terminal '\x00' added by TerminateLiteral().
+    return next_.literal_length - 1;
+  }
+
+  i::Vector<const char> next_literal() const {
+    return i::Vector<const char>(next_literal_string(), next_literal_length());
+  }
+
+  // Scans the input as a regular expression pattern, previous
+  // character(s) must be /(=). Returns true if a pattern is scanned.
+  bool ScanRegExpPattern(bool seen_equal);
+  // Returns true if regexp flags are scanned (always since flags can
+  // be empty).
+  bool ScanRegExpFlags();
+
+  // Seek forward to the given position.  This operation does not
+  // work in general, for instance when there are pushed back
+  // characters, but works for seeking forward until simple delimiter
+  // tokens, which is what it is used for.
+  void SeekForward(int pos);
+
+  bool stack_overflow() { return stack_overflow_; }
+
+  static const int kCharacterLookaheadBufferSize = 1;
+  static const int kNoEndPosition = 1;
+
+ private:
+  // The current and look-ahead token.
+  struct TokenDesc {
+    i::Token::Value token;
+    Location location;
+    const char* literal_chars;
+    int literal_length;
+  };
+
+  // Default stack limit is 128K pointers.
+  static const int kMaxStackSize = 128 * 1024 * sizeof(void*);  // NOLINT.
+
+  void Init(unibrow::CharacterStream* stream);
+
+  // Literal buffer support
+  inline void StartLiteral(LiteralType type);
+  inline void AddLiteralChar(uc32 ch);
+  inline void AddLiteralCharAdvance();
+  inline void TerminateLiteral();
+  // Stops scanning of a literal, e.g., due to an encountered error.
+  inline void DropLiteral();
+
+  // Low-level scanning support.
+  void Advance() { c0_ = source_->Advance(); }
+  void PushBack(uc32 ch) {
+    source_->PushBack(ch);
+    c0_ = ch;
+  }
+
+  bool SkipWhiteSpace();
+
+  i::Token::Value SkipSingleLineComment();
+  i::Token::Value SkipMultiLineComment();
+
+  inline i::Token::Value Select(i::Token::Value tok);
+  inline i::Token::Value Select(uc32 next,
+                                i::Token::Value then,
+                                i::Token::Value else_);
+
+  // Scans a single JavaScript token.
+  void Scan();
+
+  void ScanDecimalDigits();
+  i::Token::Value ScanNumber(bool seen_period);
+  i::Token::Value ScanIdentifier();
+  uc32 ScanHexEscape(uc32 c, int length);
+  uc32 ScanOctalEscape(uc32 c, int length);
+  void ScanEscape();
+  i::Token::Value ScanString();
+
+  // Scans a possible HTML comment -- begins with '<!'.
+  i::Token::Value ScanHtmlComment();
+
+  // Return the current source position.
+  int source_pos() {
+    return source_->pos() - kCharacterLookaheadBufferSize;
+  }
+
+  // Decodes a unicode escape-sequence which is part of an identifier.
+  // If the escape sequence cannot be decoded the result is kBadRune.
+  uc32 ScanIdentifierUnicodeEscape();
+
+  PreScannerStackGuard stack_guard_;
+
+  TokenDesc current_;  // desc for current token (as returned by Next())
+  TokenDesc next_;     // desc for next token (one token look-ahead)
+  bool has_line_terminator_before_next_;
+
+  // Source.
+  InputStream* source_;
+
+  // Buffer to hold literal values (identifiers, strings, numerals, regexps and
+  // regexp flags) using '\x00'-terminated UTF-8 encoding.
+  // Handles allocation internally.
+  // Notice that the '\x00' termination is meaningless for strings and regexps
+  // which may contain the zero-character, but can be used as terminator for
+  // identifiers, numerals and regexp flags.
+  LiteralsBuffer literal_buffer_;
+
+  bool stack_overflow_;
+
+  // One Unicode character look-ahead; c0_ < 0 at the end of the input.
+  uc32 c0_;
+};
+
+
+// ----------------------------------------------------------------------------
+// Scanner::LiteralScope
+
+template <typename InputStream, typename LiteralsBuffer>
+Scanner<InputStream, LiteralsBuffer>::LiteralScope::LiteralScope(
+    Scanner* self, LiteralType type)
+    : scanner_(self), complete_(false) {
+  self->StartLiteral(type);
+}
+
+
+template <typename InputStream, typename LiteralsBuffer>
+Scanner<InputStream, LiteralsBuffer>::LiteralScope::~LiteralScope() {
+  if (!complete_) scanner_->DropLiteral();
+}
+
+template <typename InputStream, typename LiteralsBuffer>
+void Scanner<InputStream, LiteralsBuffer>::LiteralScope::Complete() {
+  scanner_->TerminateLiteral();
+  complete_ = true;
+}
+
+
+// ----------------------------------------------------------------------------
+// Scanner.
+template <typename InputStream, typename LiteralsBuffer>
+Scanner<InputStream, LiteralsBuffer>::Scanner()
+    : stack_guard_(kMaxStackSize),
+      has_line_terminator_before_next_(false),
+      source_(NULL),
+      stack_overflow_(false) {}
+
+
+template <typename InputStream, typename LiteralsBuffer>
+void Scanner<InputStream, LiteralsBuffer>::Initialize(InputStream* stream) {
+  source_ = stream;
+
+  // Initialize current_ to not refer to a literal.
+  current_.literal_length = 0;
+  // Reset literal buffer.
+  literal_buffer_.Reset();
+
+  // Set c0_ (one character ahead)
+  ASSERT(kCharacterLookaheadBufferSize == 1);
+  Advance();
+
+  // Skip initial whitespace allowing HTML comment ends just like
+  // after a newline and scan first token.
+  has_line_terminator_before_next_ = true;
+  SkipWhiteSpace();
+  Scan();
+}
+
+
+template <typename InputStream, typename LiteralsBuffer>
+i::Token::Value Scanner<InputStream, LiteralsBuffer>::Next() {
+  // BUG 1215673: Find a thread safe way to set a stack limit in
+  // pre-parse mode. Otherwise, we cannot safely pre-parse from other
+  // threads.
+  current_ = next_;
+  // Check for stack-overflow before returning any tokens.
+  if (stack_guard_.has_overflowed()) {
+    stack_overflow_ = true;
+    next_.token = i::Token::ILLEGAL;
+  } else {
+    has_line_terminator_before_next_ = false;
+    Scan();
+  }
+  return current_.token;
+}
+
+
+template <typename InputStream, typename LiteralsBuffer>
+void Scanner<InputStream, LiteralsBuffer>::StartLiteral(LiteralType type) {
+  // Only record string and literal identifiers when preparsing.
+  // Those are the ones that are recorded as symbols. Numbers and
+  // regexps are not recorded.
+  if (type == kLiteralString || type == kLiteralIdentifier) {
+    literal_buffer_.StartLiteral();
+  }
+}
+
+
+template <typename InputStream, typename LiteralsBuffer>
+void Scanner<InputStream, LiteralsBuffer>::AddLiteralChar(uc32 c) {
+  literal_buffer_.AddChar(c);
+}
+
+
+template <typename InputStream, typename LiteralsBuffer>
+void Scanner<InputStream, LiteralsBuffer>::TerminateLiteral() {
+  i::Vector<const char> chars = literal_buffer_.EndLiteral();
+  next_.literal_chars = chars.start();
+  next_.literal_length = chars.length();
+}
+
+
+template <typename InputStream, typename LiteralsBuffer>
+void Scanner<InputStream, LiteralsBuffer>::DropLiteral() {
+  literal_buffer_.DropLiteral();
+}
+
+
+template <typename InputStream, typename LiteralsBuffer>
+void Scanner<InputStream, LiteralsBuffer>::AddLiteralCharAdvance() {
+  AddLiteralChar(c0_);
+  Advance();
+}
+
+
+static inline bool IsByteOrderMark(uc32 c) {
+  // The Unicode value U+FFFE is guaranteed never to be assigned as a
+  // Unicode character; this implies that in a Unicode context the
+  // 0xFF, 0xFE byte pattern can only be interpreted as the U+FEFF
+  // character expressed in little-endian byte order (since it could
+  // not be a U+FFFE character expressed in big-endian byte
+  // order). Nevertheless, we check for it to be compatible with
+  // Spidermonkey.
+  return c == 0xFEFF || c == 0xFFFE;
+}
+
+
+template <typename InputStream, typename LiteralsBuffer>
+bool Scanner<InputStream, LiteralsBuffer>::SkipWhiteSpace() {
+  int start_position = source_pos();
+
+  while (true) {
+    // We treat byte-order marks (BOMs) as whitespace for better
+    // compatibility with Spidermonkey and other JavaScript engines.
+    while (i::ScannerConstants::kIsWhiteSpace.get(c0_)
+           || IsByteOrderMark(c0_)) {
+      // IsWhiteSpace() includes line terminators!
+      if (i::ScannerConstants::kIsLineTerminator.get(c0_)) {
+        // Ignore line terminators, but remember them. This is necessary
+        // for automatic semicolon insertion.
+        has_line_terminator_before_next_ = true;
+      }
+      Advance();
+    }
+
+    // If there is an HTML comment end '-->' at the beginning of a
+    // line (with only whitespace in front of it), we treat the rest
+    // of the line as a comment. This is in line with the way
+    // SpiderMonkey handles it.
+    if (c0_ == '-' && has_line_terminator_before_next_) {
+      Advance();
+      if (c0_ == '-') {
+        Advance();
+        if (c0_ == '>') {
+          // Treat the rest of the line as a comment.
+          SkipSingleLineComment();
+          // Continue skipping white space after the comment.
+          continue;
+        }
+        PushBack('-');  // undo Advance()
+      }
+      PushBack('-');  // undo Advance()
+    }
+    // Return whether or not we skipped any characters.
+    return source_pos() != start_position;
+  }
+}
+
+
+template <typename InputStream, typename LiteralsBuffer>
+i::Token::Value Scanner<InputStream, LiteralsBuffer>::SkipSingleLineComment() {
+  Advance();
+
+  // The line terminator at the end of the line is not considered
+  // to be part of the single-line comment; it is recognized
+  // separately by the lexical grammar and becomes part of the
+  // stream of input elements for the syntactic grammar (see
+  // ECMA-262, section 7.4, page 12).
+  while (c0_ >= 0 && !i::ScannerConstants::kIsLineTerminator.get(c0_)) {
+    Advance();
+  }
+
+  return i::Token::WHITESPACE;
+}
+
+
+template <typename InputStream, typename LiteralsBuffer>
+i::Token::Value Scanner<InputStream, LiteralsBuffer>::SkipMultiLineComment() {
+  ASSERT(c0_ == '*');
+  Advance();
+
+  while (c0_ >= 0) {
+    char ch = c0_;
+    Advance();
+    // If we have reached the end of the multi-line comment, we
+    // consume the '/' and insert a whitespace. This way all
+    // multi-line comments are treated as whitespace - even the ones
+    // containing line terminators. This contradicts ECMA-262, section
+    // 7.4, page 12, that says that multi-line comments containing
+    // line terminators should be treated as a line terminator, but it
+    // matches the behaviour of SpiderMonkey and KJS.
+    if (ch == '*' && c0_ == '/') {
+      c0_ = ' ';
+      return i::Token::WHITESPACE;
+    }
+  }
+
+  // Unterminated multi-line comment.
+  return i::Token::ILLEGAL;
+}
+
+
+template <typename InputStream, typename LiteralsBuffer>
+i::Token::Value Scanner<InputStream, LiteralsBuffer>::ScanHtmlComment() {
+  // Check for <!-- comments.
+  ASSERT(c0_ == '!');
+  Advance();
+  if (c0_ == '-') {
+    Advance();
+    if (c0_ == '-') return SkipSingleLineComment();
+    PushBack('-');  // undo Advance()
+  }
+  PushBack('!');  // undo Advance()
+  ASSERT(c0_ == '!');
+  return i::Token::LT;
+}
+
+
+template <typename InputStream, typename LiteralsBuffer>
+void Scanner<InputStream, LiteralsBuffer>::Scan() {
+  next_.literal_length = 0;
+  i::Token::Value token;
+  do {
+    // Remember the position of the next token
+    next_.location.beg_pos = source_pos();
+
+    switch (c0_) {
+      case ' ':
+      case '\t':
+        Advance();
+        token = i::Token::WHITESPACE;
+        break;
+
+      case '\n':
+        Advance();
+        has_line_terminator_before_next_ = true;
+        token = i::Token::WHITESPACE;
+        break;
+
+      case '"': case '\'':
+        token = ScanString();
+        break;
+
+      case '<':
+        // < <= << <<= <!--
+        Advance();
+        if (c0_ == '=') {
+          token = Select(i::Token::LTE);
+        } else if (c0_ == '<') {
+          token = Select('=', i::Token::ASSIGN_SHL, i::Token::SHL);
+        } else if (c0_ == '!') {
+          token = ScanHtmlComment();
+        } else {
+          token = i::Token::LT;
+        }
+        break;
+
+      case '>':
+        // > >= >> >>= >>> >>>=
+        Advance();
+        if (c0_ == '=') {
+          token = Select(i::Token::GTE);
+        } else if (c0_ == '>') {
+          // >> >>= >>> >>>=
+          Advance();
+          if (c0_ == '=') {
+            token = Select(i::Token::ASSIGN_SAR);
+          } else if (c0_ == '>') {
+            token = Select('=', i::Token::ASSIGN_SHR, i::Token::SHR);
+          } else {
+            token = i::Token::SAR;
+          }
+        } else {
+          token = i::Token::GT;
+        }
+        break;
+
+      case '=':
+        // = == ===
+        Advance();
+        if (c0_ == '=') {
+          token = Select('=', i::Token::EQ_STRICT, i::Token::EQ);
+        } else {
+          token = i::Token::ASSIGN;
+        }
+        break;
+
+      case '!':
+        // ! != !==
+        Advance();
+        if (c0_ == '=') {
+          token = Select('=', i::Token::NE_STRICT, i::Token::NE);
+        } else {
+          token = i::Token::NOT;
+        }
+        break;
+
+      case '+':
+        // + ++ +=
+        Advance();
+        if (c0_ == '+') {
+          token = Select(i::Token::INC);
+        } else if (c0_ == '=') {
+          token = Select(i::Token::ASSIGN_ADD);
+        } else {
+          token = i::Token::ADD;
+        }
+        break;
+
+      case '-':
+        // - -- --> -=
+        Advance();
+        if (c0_ == '-') {
+          Advance();
+          if (c0_ == '>' && has_line_terminator_before_next_) {
+            // For compatibility with SpiderMonkey, we skip lines that
+            // start with an HTML comment end '-->'.
+            token = SkipSingleLineComment();
+          } else {
+            token = i::Token::DEC;
+          }
+        } else if (c0_ == '=') {
+          token = Select(i::Token::ASSIGN_SUB);
+        } else {
+          token = i::Token::SUB;
+        }
+        break;
+
+      case '*':
+        // * *=
+        token = Select('=', i::Token::ASSIGN_MUL, i::Token::MUL);
+        break;
+
+      case '%':
+        // % %=
+        token = Select('=', i::Token::ASSIGN_MOD, i::Token::MOD);
+        break;
+
+      case '/':
+        // /  // /* /=
+        Advance();
+        if (c0_ == '/') {
+          token = SkipSingleLineComment();
+        } else if (c0_ == '*') {
+          token = SkipMultiLineComment();
+        } else if (c0_ == '=') {
+          token = Select(i::Token::ASSIGN_DIV);
+        } else {
+          token = i::Token::DIV;
+        }
+        break;
+
+      case '&':
+        // & && &=
+        Advance();
+        if (c0_ == '&') {
+          token = Select(i::Token::AND);
+        } else if (c0_ == '=') {
+          token = Select(i::Token::ASSIGN_BIT_AND);
+        } else {
+          token = i::Token::BIT_AND;
+        }
+        break;
+
+      case '|':
+        // | || |=
+        Advance();
+        if (c0_ == '|') {
+          token = Select(i::Token::OR);
+        } else if (c0_ == '=') {
+          token = Select(i::Token::ASSIGN_BIT_OR);
+        } else {
+          token = i::Token::BIT_OR;
+        }
+        break;
+
+      case '^':
+        // ^ ^=
+        token = Select('=', i::Token::ASSIGN_BIT_XOR, i::Token::BIT_XOR);
+        break;
+
+      case '.':
+        // . Number
+        Advance();
+        if (i::IsDecimalDigit(c0_)) {
+          token = ScanNumber(true);
+        } else {
+          token = i::Token::PERIOD;
+        }
+        break;
+
+      case ':':
+        token = Select(i::Token::COLON);
+        break;
+
+      case ';':
+        token = Select(i::Token::SEMICOLON);
+        break;
+
+      case ',':
+        token = Select(i::Token::COMMA);
+        break;
+
+      case '(':
+        token = Select(i::Token::LPAREN);
+        break;
+
+      case ')':
+        token = Select(i::Token::RPAREN);
+        break;
+
+      case '[':
+        token = Select(i::Token::LBRACK);
+        break;
+
+      case ']':
+        token = Select(i::Token::RBRACK);
+        break;
+
+      case '{':
+        token = Select(i::Token::LBRACE);
+        break;
+
+      case '}':
+        token = Select(i::Token::RBRACE);
+        break;
+
+      case '?':
+        token = Select(i::Token::CONDITIONAL);
+        break;
+
+      case '~':
+        token = Select(i::Token::BIT_NOT);
+        break;
+
+      default:
+        if (i::ScannerConstants::kIsIdentifierStart.get(c0_)) {
+          token = ScanIdentifier();
+        } else if (i::IsDecimalDigit(c0_)) {
+          token = ScanNumber(false);
+        } else if (SkipWhiteSpace()) {
+          token = i::Token::WHITESPACE;
+        } else if (c0_ < 0) {
+          token = i::Token::EOS;
+        } else {
+          token = Select(i::Token::ILLEGAL);
+        }
+        break;
+    }
+
+    // Continue scanning for tokens as long as we're just skipping
+    // whitespace.
+  } while (token == i::Token::WHITESPACE);
+
+  next_.location.end_pos = source_pos();
+  next_.token = token;
+}
+
+
+template <typename InputStream, typename LiteralsBuffer>
+void Scanner<InputStream, LiteralsBuffer>::SeekForward(int pos) {
+  source_->SeekForward(pos - 1);
+  Advance();
+  // This function is only called to seek to the location
+  // of the end of a function (at the "}" token). It doesn't matter
+  // whether there was a line terminator in the part we skip.
+  has_line_terminator_before_next_ = false;
+  Scan();
+}
+
+
+template <typename InputStream, typename LiteralsBuffer>
+uc32 Scanner<InputStream, LiteralsBuffer>::ScanHexEscape(uc32 c, int length) {
+  ASSERT(length <= 4);  // prevent overflow
+
+  uc32 digits[4];
+  uc32 x = 0;
+  for (int i = 0; i < length; i++) {
+    digits[i] = c0_;
+    int d = HexValue(c0_);
+    if (d < 0) {
+      // According to ECMA-262, 3rd, 7.8.4, page 18, these hex escapes
+      // should be illegal, but other JS VMs just return the
+      // non-escaped version of the original character.
+
+      // Push back digits read, except the last one (in c0_).
+      for (int j = i-1; j >= 0; j--) {
+        PushBack(digits[j]);
+      }
+      // Notice: No handling of error - treat it as "\u"->"u".
+      return c;
+    }
+    x = x * 16 + d;
+    Advance();
+  }
+
+  return x;
+}
+
+
+// Octal escapes of the forms '\0xx' and '\xxx' are not a part of
+// ECMA-262. Other JS VMs support them.
+template <typename InputStream, typename LiteralsBuffer>
+uc32 Scanner<InputStream, LiteralsBuffer>::ScanOctalEscape(
+    uc32 c, int length) {
+  uc32 x = c - '0';
+  for (int i = 0; i < length; i++) {
+    int d = c0_ - '0';
+    if (d < 0 || d > 7) break;
+    int nx = x * 8 + d;
+    if (nx >= 256) break;
+    x = nx;
+    Advance();
+  }
+  return x;
+}
+
+
+template <typename InputStream, typename LiteralsBuffer>
+void Scanner<InputStream, LiteralsBuffer>::ScanEscape() {
+  uc32 c = c0_;
+  Advance();
+
+  // Skip escaped newlines.
+  if (i::ScannerConstants::kIsLineTerminator.get(c)) {
+    // Allow CR+LF newlines in multiline string literals.
+    if (i::IsCarriageReturn(c) && i::IsLineFeed(c0_)) Advance();
+    // Allow LF+CR newlines in multiline string literals.
+    if (i::IsLineFeed(c) && i::IsCarriageReturn(c0_)) Advance();
+    return;
+  }
+
+  switch (c) {
+    case '\'':  // fall through
+    case '"' :  // fall through
+    case '\\': break;
+    case 'b' : c = '\b'; break;
+    case 'f' : c = '\f'; break;
+    case 'n' : c = '\n'; break;
+    case 'r' : c = '\r'; break;
+    case 't' : c = '\t'; break;
+    case 'u' : c = ScanHexEscape(c, 4); break;
+    case 'v' : c = '\v'; break;
+    case 'x' : c = ScanHexEscape(c, 2); break;
+    case '0' :  // fall through
+    case '1' :  // fall through
+    case '2' :  // fall through
+    case '3' :  // fall through
+    case '4' :  // fall through
+    case '5' :  // fall through
+    case '6' :  // fall through
+    case '7' : c = ScanOctalEscape(c, 2); break;
+  }
+
+  // According to ECMA-262, 3rd, 7.8.4 (p 18ff) these
+  // should be illegal, but they are commonly handled
+  // as non-escaped characters by JS VMs.
+  AddLiteralChar(c);
+}
+
+
+template <typename InputStream, typename LiteralsBuffer>
+i::Token::Value Scanner<InputStream, LiteralsBuffer>::ScanString() {
+  uc32 quote = c0_;
+  Advance();  // consume quote
+
+  LiteralScope literal(this, kLiteralString);
+  while (c0_ != quote && c0_ >= 0
+         && !i::ScannerConstants::kIsLineTerminator.get(c0_)) {
+    uc32 c = c0_;
+    Advance();
+    if (c == '\\') {
+      if (c0_ < 0) return i::Token::ILLEGAL;
+      ScanEscape();
+    } else {
+      AddLiteralChar(c);
+    }
+  }
+  if (c0_ != quote) return i::Token::ILLEGAL;
+  literal.Complete();
+
+  Advance();  // consume quote
+  return i::Token::STRING;
+}
+
+
+template <typename InputStream, typename LiteralsBuffer>
+i::Token::Value Scanner<InputStream, LiteralsBuffer>::Select(
+    i::Token::Value tok) {
+  Advance();
+  return tok;
+}
+
+
+template <typename InputStream, typename LiteralsBuffer>
+i::Token::Value Scanner<InputStream, LiteralsBuffer>::Select(
+    uc32 next,
+    i::Token::Value then,
+    i::Token::Value else_) {
+  Advance();
+  if (c0_ == next) {
+    Advance();
+    return then;
+  } else {
+    return else_;
+  }
+}
+
+
+// Returns true if any decimal digits were scanned, returns false otherwise.
+template <typename InputStream, typename LiteralsBuffer>
+void Scanner<InputStream, LiteralsBuffer>::ScanDecimalDigits() {
+  while (i::IsDecimalDigit(c0_))
+    AddLiteralCharAdvance();
+}
+
+
+template <typename InputStream, typename LiteralsBuffer>
+i::Token::Value Scanner<InputStream, LiteralsBuffer>::ScanNumber(
+    bool seen_period) {
+  // c0_ is the first digit of the number or the fraction.
+  ASSERT(i::IsDecimalDigit(c0_));
+
+  enum { DECIMAL, HEX, OCTAL } kind = DECIMAL;
+
+  LiteralScope literal(this, kLiteralNumber);
+  if (seen_period) {
+    // we have already seen a decimal point of the float
+    AddLiteralChar('.');
+    ScanDecimalDigits();  // we know we have at least one digit
+
+  } else {
+    // if the first character is '0' we must check for octals and hex
+    if (c0_ == '0') {
+      AddLiteralCharAdvance();
+
+      // either 0, 0exxx, 0Exxx, 0.xxx, an octal number, or a hex number
+      if (c0_ == 'x' || c0_ == 'X') {
+        // hex number
+        kind = HEX;
+        AddLiteralCharAdvance();
+        if (!i::IsHexDigit(c0_)) {
+          // we must have at least one hex digit after 'x'/'X'
+          return i::Token::ILLEGAL;
+        }
+        while (i::IsHexDigit(c0_)) {
+          AddLiteralCharAdvance();
+        }
+      } else if ('0' <= c0_ && c0_ <= '7') {
+        // (possible) octal number
+        kind = OCTAL;
+        while (true) {
+          if (c0_ == '8' || c0_ == '9') {
+            kind = DECIMAL;
+            break;
+          }
+          if (c0_  < '0' || '7'  < c0_) break;
+          AddLiteralCharAdvance();
+        }
+      }
+    }
+
+    // Parse decimal digits and allow trailing fractional part.
+    if (kind == DECIMAL) {
+      ScanDecimalDigits();  // optional
+      if (c0_ == '.') {
+        AddLiteralCharAdvance();
+        ScanDecimalDigits();  // optional
+      }
+    }
+  }
+
+  // scan exponent, if any
+  if (c0_ == 'e' || c0_ == 'E') {
+    ASSERT(kind != HEX);  // 'e'/'E' must be scanned as part of the hex number
+    if (kind == OCTAL) return i::Token::ILLEGAL;
+    // scan exponent
+    AddLiteralCharAdvance();
+    if (c0_ == '+' || c0_ == '-')
+      AddLiteralCharAdvance();
+    if (!i::IsDecimalDigit(c0_)) {
+      // we must have at least one decimal digit after 'e'/'E'
+      return i::Token::ILLEGAL;
+    }
+    ScanDecimalDigits();
+  }
+
+  // The source character immediately following a numeric literal must
+  // not be an identifier start or a decimal digit; see ECMA-262
+  // section 7.8.3, page 17 (note that we read only one decimal digit
+  // if the value is 0).
+  if (i::IsDecimalDigit(c0_)
+      || i::ScannerConstants::kIsIdentifierStart.get(c0_))
+    return i::Token::ILLEGAL;
+
+  literal.Complete();
+
+  return i::Token::NUMBER;
+}
+
+
+template <typename InputStream, typename LiteralsBuffer>
+uc32 Scanner<InputStream, LiteralsBuffer>::ScanIdentifierUnicodeEscape() {
+  Advance();
+  if (c0_ != 'u') return unibrow::Utf8::kBadChar;
+  Advance();
+  uc32 c = ScanHexEscape('u', 4);
+  // We do not allow a unicode escape sequence to start another
+  // unicode escape sequence.
+  if (c == '\\') return unibrow::Utf8::kBadChar;
+  return c;
+}
+
+
+template <typename InputStream, typename LiteralsBuffer>
+i::Token::Value Scanner<InputStream, LiteralsBuffer>::ScanIdentifier() {
+  ASSERT(i::ScannerConstants::kIsIdentifierStart.get(c0_));
+
+  LiteralScope literal(this, kLiteralIdentifier);
+  i::KeywordMatcher keyword_match;
+
+  // Scan identifier start character.
+  if (c0_ == '\\') {
+    uc32 c = ScanIdentifierUnicodeEscape();
+    // Only allow legal identifier start characters.
+    if (!i::ScannerConstants::kIsIdentifierStart.get(c)) {
+      return i::Token::ILLEGAL;
+    }
+    AddLiteralChar(c);
+    keyword_match.Fail();
+  } else {
+    AddLiteralChar(c0_);
+    keyword_match.AddChar(c0_);
+    Advance();
+  }
+
+  // Scan the rest of the identifier characters.
+  while (i::ScannerConstants::kIsIdentifierPart.get(c0_)) {
+    if (c0_ == '\\') {
+      uc32 c = ScanIdentifierUnicodeEscape();
+      // Only allow legal identifier part characters.
+      if (!i::ScannerConstants::kIsIdentifierPart.get(c)) {
+        return i::Token::ILLEGAL;
+      }
+      AddLiteralChar(c);
+      keyword_match.Fail();
+    } else {
+      AddLiteralChar(c0_);
+      keyword_match.AddChar(c0_);
+      Advance();
+    }
+  }
+  literal.Complete();
+
+  return keyword_match.token();
+}
+
+
+template <typename InputStream, typename LiteralsBuffer>
+bool Scanner<InputStream, LiteralsBuffer>::ScanRegExpPattern(bool seen_equal) {
+  // Scan: ('/' | '/=') RegularExpressionBody '/' RegularExpressionFlags
+  bool in_character_class = false;
+
+  // Previous token is either '/' or '/=', in the second case, the
+  // pattern starts at =.
+  next_.location.beg_pos = source_pos() - (seen_equal ? 2 : 1);
+  next_.location.end_pos = source_pos() - (seen_equal ? 1 : 0);
+
+  // Scan regular expression body: According to ECMA-262, 3rd, 7.8.5,
+  // the scanner should pass uninterpreted bodies to the RegExp
+  // constructor.
+  LiteralScope literal(this, kLiteralRegExp);
+  if (seen_equal)
+    AddLiteralChar('=');
+
+  while (c0_ != '/' || in_character_class) {
+    if (i::ScannerConstants::kIsLineTerminator.get(c0_) || c0_ < 0) {
+      return false;
+    }
+    if (c0_ == '\\') {  // escaped character
+      AddLiteralCharAdvance();
+      if (i::ScannerConstants::kIsLineTerminator.get(c0_) || c0_ < 0) {
+        return false;
+      }
+      AddLiteralCharAdvance();
+    } else {  // unescaped character
+      if (c0_ == '[') in_character_class = true;
+      if (c0_ == ']') in_character_class = false;
+      AddLiteralCharAdvance();
+    }
+  }
+  Advance();  // consume '/'
+
+  literal.Complete();
+
+  return true;
+}
+
+template <typename InputStream, typename LiteralsBuffer>
+bool Scanner<InputStream, LiteralsBuffer>::ScanRegExpFlags() {
+  // Scan regular expression flags.
+  LiteralScope literal(this, kLiteralRegExpFlags);
+  while (i::ScannerConstants::kIsIdentifierPart.get(c0_)) {
+    if (c0_ == '\\') {
+      uc32 c = ScanIdentifierUnicodeEscape();
+      if (c != static_cast<uc32>(unibrow::Utf8::kBadChar)) {
+        // We allow any escaped character, unlike the restriction on
+        // IdentifierPart when it is used to build an IdentifierName.
+        AddLiteralChar(c);
+        continue;
+      }
+    }
+    AddLiteralCharAdvance();
+  }
+  literal.Complete();
+
+  next_.location.end_pos = source_pos() - 1;
+  return true;
+}
+
+
+} }  // namespace v8::preparser
+
+#endif  // V8_PRESCANNER_H_
index a4d9a828dd4ea7b5b05fada3f0d391c7b9002c0b..29f9ab4d3536c4714639ce92caa65dcdb635bd0a 100644 (file)
@@ -1848,22 +1848,6 @@ HeapEntry* HeapSnapshotGenerator::GetEntry(Object* obj) {
 }
 
 
-int HeapSnapshotGenerator::GetGlobalSecurityToken() {
-  return collection_->token_enumerator()->GetTokenId(
-      Top::context()->global()->global_context()->security_token());
-}
-
-
-int HeapSnapshotGenerator::GetObjectSecurityToken(HeapObject* obj) {
-  if (obj->IsGlobalContext()) {
-    return collection_->token_enumerator()->GetTokenId(
-        Context::cast(obj)->security_token());
-  } else {
-    return TokenEnumerator::kNoSecurityToken;
-  }
-}
-
-
 class IndexedReferencesExtractor : public ObjectVisitor {
  public:
   IndexedReferencesExtractor(HeapSnapshotGenerator* generator,
@@ -1893,19 +1877,11 @@ class IndexedReferencesExtractor : public ObjectVisitor {
 
 void HeapSnapshotGenerator::ExtractReferences(HeapObject* obj) {
   // We need to reference JS global objects from snapshot's root.
-  // We also need to only include global objects from the current
-  // security context. And we don't want to add the global proxy,
-  // as we don't have a special type for it.
+  // We use JSGlobalProxy because this is what embedder (e.g. browser)
+  // uses for the global object.
   if (obj->IsJSGlobalProxy()) {
-    int global_security_token = GetGlobalSecurityToken();
     JSGlobalProxy* proxy = JSGlobalProxy::cast(obj);
-    int object_security_token =
-        collection_->token_enumerator()->GetTokenId(
-            Context::cast(proxy->context())->security_token());
-    if (object_security_token == TokenEnumerator::kNoSecurityToken
-        || object_security_token == global_security_token) {
-      SetRootReference(proxy->map()->prototype());
-    }
+    SetRootReference(proxy->map()->prototype());
     return;
   }
 
index 6f63f6a122b25eab533763be1b45ea795f7bc543..b691a056e8567e06be01048037f560802901d8b5 100644 (file)
@@ -948,8 +948,6 @@ class HeapSnapshotGenerator {
 
  private:
   HeapEntry* GetEntry(Object* obj);
-  int GetGlobalSecurityToken();
-  int GetObjectSecurityToken(HeapObject* obj);
   void ExtractReferences(HeapObject* obj);
   void ExtractClosureReferences(JSObject* js_obj, HeapEntry* entry);
   void ExtractPropertyReferences(JSObject* js_obj, HeapEntry* entry);
index 51f4b094d376638c33ed7274ebe1ed8da6d67ed7..d01d04f2e396dd119f939a86b12fdaf13c6e34fc 100644 (file)
@@ -71,9 +71,6 @@ function DoConstructRegExp(object, pattern, flags, isConstructorCall) {
     }
   }
 
-  if (!isConstructorCall) {
-    regExpCache.type = 'none';
-  }
   %RegExpInitializeObject(object, pattern, global, ignoreCase, multiline);
 
   // Call internal function to compile the pattern.
@@ -121,22 +118,6 @@ function DoRegExpExec(regexp, string, index) {
 }
 
 
-function RegExpCache() {
-  this.type = 'none';
-  this.regExp = 0;
-  this.subject = 0;
-  this.replaceString = 0;
-  this.answer = 0;
-  // answerSaved marks whether the contents of answer is valid for a cache
-  // hit in RegExpExec, StringMatch and StringSplit.
-  this.answerSaved = false;
-  this.splitLimit = 0;  // Used only when type is "split".
-}
-
-
-var regExpCache = new RegExpCache();
-
-
 function BuildResultFromMatchInfo(lastMatchInfo, s) {
   var numResults = NUMBER_OF_CAPTURES(lastMatchInfo) >> 1;
   var result = %_RegExpConstructResult(numResults, lastMatchInfo[CAPTURE0], s);
@@ -178,32 +159,6 @@ function RegExpExec(string) {
                         ['RegExp.prototype.exec', this]);
   }
 
-  var cache = regExpCache;
-  var saveAnswer = false;
-
-  var lastIndex = this.lastIndex;
-
-  // Since cache.subject is always a string, a matching input can not
-  // cause visible side-effects when converted to a string, so we can omit
-  // the conversion required by the specification.
-  // Likewise, the regexp.lastIndex and regexp.global properties are value
-  // properties that are not configurable, so reading them can also not cause
-  // any side effects (converting lastIndex to a number can, though).
-  if (%_ObjectEquals(cache.type, 'exec') &&
-      %_ObjectEquals(0, lastIndex) &&
-      %_IsRegExpEquivalent(cache.regExp, this) &&
-      %_ObjectEquals(cache.subject, string)) {
-    if (cache.answerSaved) {
-      // The regexp.lastIndex value must be 0 for non-global RegExps, and for
-      // global RegExps we only cache negative results, which gives a lastIndex
-      // of zero as well.
-      this.lastIndex = 0;
-      return %_RegExpCloneResult(cache.answer);
-    } else {
-      saveAnswer = true;
-    }
-  }
-
   if (%_ArgumentsLength() === 0) {
     var regExpInput = LAST_INPUT(lastMatchInfo);
     if (IS_UNDEFINED(regExpInput)) {
@@ -217,11 +172,13 @@ function RegExpExec(string) {
   } else {
     s = ToString(string);
   }
-  var global = this.global;
+  var lastIndex = this.lastIndex;
 
   // Conversion is required by the ES5 specification (RegExp.prototype.exec
   // algorithm, step 5) even if the value is discarded for non-global RegExps.
   var i = TO_INTEGER(lastIndex);
+
+  var global = this.global;
   if (global) {
     if (i < 0 || i > s.length) {
       this.lastIndex = 0;
@@ -236,35 +193,16 @@ function RegExpExec(string) {
   var matchIndices = %_RegExpExec(this, s, i, lastMatchInfo);
 
   if (matchIndices === null) {
-    if (global) {
-      // Cache negative result only if initial lastIndex was zero.
-      this.lastIndex = 0;
-      if (lastIndex !== 0) return matchIndices;
-    }
-    cache.regExp = this;
-    cache.subject = s;            // Always a string.
-    cache.answer = null;
-    cache.answerSaved = true;     // Safe since no cloning is needed.
-    cache.type = 'exec';
-    return matchIndices;        // No match.
+    if (global) this.lastIndex = 0;
+    return null;
   }
 
   // Successful match.
   lastMatchInfoOverride = null;
-  var result = BuildResultFromMatchInfo(matchIndices, s);
-
   if (global) {
-    // Don't cache positive results for global regexps.
     this.lastIndex = lastMatchInfo[CAPTURE1];
-  } else {
-    cache.regExp = this;
-    cache.subject = s;
-    if (saveAnswer) cache.answer = %_RegExpCloneResult(result);
-    cache.answerSaved = saveAnswer;
-    cache.type = 'exec';
   }
-  return result;
-
+  return BuildResultFromMatchInfo(matchIndices, s);
 }
 
 
@@ -289,80 +227,57 @@ function RegExpTest(string) {
     string = regExpInput;
   }
 
-  var lastIndex = this.lastIndex;
-
-  var cache = regExpCache;
-  if (%_ObjectEquals(cache.type, 'test') &&
-      %_IsRegExpEquivalent(cache.regExp, this) &&
-      %_ObjectEquals(cache.subject, string) &&
-      %_ObjectEquals(0, lastIndex)) {
-    // The regexp.lastIndex value must be 0 for non-global RegExps, and for
-    // global RegExps we only cache negative results, which gives a resulting
-    // lastIndex of zero as well.
-    if (global) this.lastIndex = 0;
-    return cache.answer;
-  }
-
   var s;
   if (IS_STRING(string)) {
     s = string;
   } else {
     s = ToString(string);
   }
-  var length = s.length;
+
+  var lastIndex = this.lastIndex;
 
   // Conversion is required by the ES5 specification (RegExp.prototype.exec
   // algorithm, step 5) even if the value is discarded for non-global RegExps.
   var i = TO_INTEGER(lastIndex);
-  if (global) {
-    if (i < 0 || i > length) {
+  
+  if (this.global) {
+    if (i < 0 || i > s.length) {
       this.lastIndex = 0;
       return false;
     }
-  } else {
-    i = 0;
-  }
-
-  var global = this.global;
-
-  // Remove irrelevant preceeding '.*' in a test regexp. The expression
-  // checks whether this.source starts with '.*' and that the third
-  // char is not a '?'
-  if (%_StringCharCodeAt(this.source, 0) == 46 &&  // '.'
-      %_StringCharCodeAt(this.source, 1) == 42 &&  // '*'
-      %_StringCharCodeAt(this.source, 2) != 63) {  // '?'
-    if (!%_ObjectEquals(regexp_key, this)) {
-      regexp_key = this;
-      regexp_val = new $RegExp(this.source.substring(2, this.source.length),
-                               (this.global ? 'g' : '')
-                               + (this.ignoreCase ? 'i' : '')
-                               + (this.multiline ? 'm' : ''));
-    }
-    if (!regexp_val.test(s)) return false;
-  }
-
-  %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]);
-  // matchIndices is either null or the lastMatchInfo array.
-  var matchIndices = %_RegExpExec(this, s, i, lastMatchInfo);
-
-  var result = (matchIndices !== null);
-  if (result) {
-    lastMatchInfoOverride = null;
-  }
-  if (global) {
-    if (result) {
-      this.lastIndex = lastMatchInfo[CAPTURE1];
-      return true;
-    } else {
+    %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]);
+    // matchIndices is either null or the lastMatchInfo array.
+    var matchIndices = %_RegExpExec(this, s, i, lastMatchInfo);
+    if (matchIndices === null) {
       this.lastIndex = 0;
-      if (lastIndex !== 0) return false;
+      return false;
     }
+    lastMatchInfoOverride = null;
+    this.lastIndex = lastMatchInfo[CAPTURE1];
+    return true;    
+  } else {
+    // Non-global regexp.
+    // Remove irrelevant preceeding '.*' in a non-global test regexp. 
+    // The expression checks whether this.source starts with '.*' and 
+    // that the third char is not a '?'.
+    if (%_StringCharCodeAt(this.source, 0) == 46 &&  // '.'
+        %_StringCharCodeAt(this.source, 1) == 42 &&  // '*'
+        %_StringCharCodeAt(this.source, 2) != 63) {  // '?'
+      if (!%_ObjectEquals(regexp_key, this)) {
+        regexp_key = this;
+        regexp_val = new $RegExp(this.source.substring(2, this.source.length),
+                                 (this.ignoreCase ? 'i' : '')
+                                 + (this.multiline ? 'm' : ''));
+      }
+      if (!regexp_val.test(s)) return false;
+    }    
+    %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]);
+    // matchIndices is either null or the lastMatchInfo array.
+    var matchIndices = %_RegExpExec(this, s, 0, lastMatchInfo);
+    if (matchIndices === null) return false;
+    lastMatchInfoOverride = null;
+    return true;
   }
-  cache.type = 'test';
-  cache.regExp = this;
-  cache.subject = s;
-  cache.answer = result;
-  return result;
 }
 
 
@@ -510,7 +425,6 @@ function SetupRegExp() {
     return IS_UNDEFINED(regExpInput) ? "" : regExpInput;
   }
   function RegExpSetInput(string) {
-    regExpCache.type = 'none';
     LAST_INPUT(lastMatchInfo) = ToString(string);
   };
 
index fc1a0232295a73e8b50dc1eea178a9034d9e8b48..5534db557ce53faee9c85aed9681749804354619 100644 (file)
@@ -1424,66 +1424,6 @@ static MaybeObject* Runtime_RegExpConstructResult(Arguments args) {
 }
 
 
-static MaybeObject* Runtime_RegExpCloneResult(Arguments args) {
-  ASSERT(args.length() == 1);
-  Map* regexp_result_map;
-  {
-    AssertNoAllocation no_gc;
-    HandleScope handles;
-    regexp_result_map = Top::global_context()->regexp_result_map();
-  }
-  if (!args[0]->IsJSArray()) return args[0];
-
-  JSArray* result = JSArray::cast(args[0]);
-  // Arguments to RegExpCloneResult should always be fresh RegExp exec call
-  // results (either a fresh JSRegExpResult or null).
-  // If the argument is not a JSRegExpResult, or isn't unmodified, just return
-  // the argument uncloned.
-  if (result->map() != regexp_result_map) return result;
-
-  // Having the original JSRegExpResult map guarantees that we have
-  // fast elements and no properties except the two in-object properties.
-  ASSERT(result->HasFastElements());
-  ASSERT(result->properties() == Heap::empty_fixed_array());
-  ASSERT_EQ(2, regexp_result_map->inobject_properties());
-
-  Object* new_array_alloc;
-  { MaybeObject* maybe_new_array_alloc =
-        Heap::AllocateRaw(JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
-    if (!maybe_new_array_alloc->ToObject(&new_array_alloc)) {
-      return maybe_new_array_alloc;
-    }
-  }
-
-  // Set HeapObject map to JSRegExpResult map.
-  reinterpret_cast<HeapObject*>(new_array_alloc)->set_map(regexp_result_map);
-
-  JSArray* new_array = JSArray::cast(new_array_alloc);
-
-  // Copy JSObject properties.
-  new_array->set_properties(result->properties());  // Empty FixedArray.
-
-  // Copy JSObject elements as copy-on-write.
-  FixedArray* elements = FixedArray::cast(result->elements());
-  if (elements != Heap::empty_fixed_array()) {
-    elements->set_map(Heap::fixed_cow_array_map());
-  }
-  new_array->set_elements(elements);
-
-  // Copy JSArray length.
-  new_array->set_length(result->length());
-
-  // Copy JSRegExpResult in-object property fields input and index.
-  new_array->FastPropertyAtPut(JSRegExpResult::kIndexIndex,
-                               result->FastPropertyAt(
-                                   JSRegExpResult::kIndexIndex));
-  new_array->FastPropertyAtPut(JSRegExpResult::kInputIndex,
-                               result->FastPropertyAt(
-                                   JSRegExpResult::kInputIndex));
-  return new_array;
-}
-
-
 static MaybeObject* Runtime_RegExpInitializeObject(Arguments args) {
   AssertNoAllocation no_alloc;
   ASSERT(args.length() == 5);
@@ -8891,12 +8831,6 @@ static MaybeObject* Runtime_DebugPrintScopes(Arguments args) {
 }
 
 
-static MaybeObject* Runtime_GetCFrames(Arguments args) {
-  // See bug 906.
-  return Heap::undefined_value();
-}
-
-
 static MaybeObject* Runtime_GetThreadCount(Arguments args) {
   HandleScope scope;
   ASSERT(args.length() == 1);
index 72a8037970116a92ca6f43a7197bd7b34199e016..756099b413fe6268dcd69a157165d223f841a372 100644 (file)
@@ -162,7 +162,6 @@ namespace internal {
   F(RegExpExecMultiple, 4, 1) \
   F(RegExpInitializeObject, 5, 1) \
   F(RegExpConstructResult, 3, 1) \
-  F(RegExpCloneResult, 1, 1) \
   \
   /* JSON */ \
   F(ParseJson, 1, 1) \
@@ -325,7 +324,6 @@ namespace internal {
   F(GetScopeCount, 2, 1) \
   F(GetScopeDetails, 3, 1) \
   F(DebugPrintScopes, 0, 1) \
-  F(GetCFrames, 1, 1) \
   F(GetThreadCount, 1, 1) \
   F(GetThreadDetails, 2, 1) \
   F(SetDisableBreak, 1, 1) \
@@ -426,7 +424,7 @@ namespace internal {
 // ----------------------------------------------------------------------------
 // INLINE_AND_RUNTIME_FUNCTION_LIST defines all inlined functions accessed
 // with a native call of the form %_name from within JS code that also have
-  // a corresponding runtime function, that is called for slow cases.
+// a corresponding runtime function, that is called for slow cases.
 // Entries have the form F(name, number of arguments, number of return values).
 #define INLINE_RUNTIME_FUNCTION_LIST(F) \
   F(IsConstructCall, 0, 1)                                                   \
@@ -438,7 +436,6 @@ namespace internal {
   F(StringCompare, 2, 1)                                                     \
   F(RegExpExec, 4, 1)                                                        \
   F(RegExpConstructResult, 3, 1)                                             \
-  F(RegExpCloneResult, 1, 1)                                                 \
   F(GetFromCache, 2, 1)                                                      \
   F(NumberToString, 1, 1)                                                    \
   F(SwapElements, 3, 1)
diff --git a/deps/v8/src/scanner-base.cc b/deps/v8/src/scanner-base.cc
new file mode 100644 (file)
index 0000000..6cde517
--- /dev/null
@@ -0,0 +1,195 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Features shared by parsing and pre-parsing scanners.
+
+#include "../include/v8stdint.h"
+#include "scanner-base.h"
+
+namespace v8 {
+namespace internal {
+
+// ----------------------------------------------------------------------------
+// Character predicates
+
+unibrow::Predicate<IdentifierStart, 128> ScannerConstants::kIsIdentifierStart;
+unibrow::Predicate<IdentifierPart, 128> ScannerConstants::kIsIdentifierPart;
+unibrow::Predicate<unibrow::WhiteSpace, 128> ScannerConstants::kIsWhiteSpace;
+unibrow::Predicate<unibrow::LineTerminator, 128>
+  ScannerConstants::kIsLineTerminator;
+
+StaticResource<ScannerConstants::Utf8Decoder> ScannerConstants::utf8_decoder_;
+
+// Compound predicates.
+
+bool ScannerConstants::IsIdentifier(unibrow::CharacterStream* buffer) {
+  // Checks whether the buffer contains an identifier (no escape).
+  if (!buffer->has_more()) return false;
+  if (!kIsIdentifierStart.get(buffer->GetNext())) {
+    return false;
+  }
+  while (buffer->has_more()) {
+    if (!kIsIdentifierPart.get(buffer->GetNext())) {
+      return false;
+    }
+  }
+  return true;
+}
+
+// ----------------------------------------------------------------------------
+// Keyword Matcher
+
+KeywordMatcher::FirstState KeywordMatcher::first_states_[] = {
+  { "break",  KEYWORD_PREFIX, Token::BREAK },
+  { NULL,     C,              Token::ILLEGAL },
+  { NULL,     D,              Token::ILLEGAL },
+  { "else",   KEYWORD_PREFIX, Token::ELSE },
+  { NULL,     F,              Token::ILLEGAL },
+  { NULL,     UNMATCHABLE,    Token::ILLEGAL },
+  { NULL,     UNMATCHABLE,    Token::ILLEGAL },
+  { NULL,     I,              Token::ILLEGAL },
+  { NULL,     UNMATCHABLE,    Token::ILLEGAL },
+  { NULL,     UNMATCHABLE,    Token::ILLEGAL },
+  { NULL,     UNMATCHABLE,    Token::ILLEGAL },
+  { NULL,     UNMATCHABLE,    Token::ILLEGAL },
+  { NULL,     N,              Token::ILLEGAL },
+  { NULL,     UNMATCHABLE,    Token::ILLEGAL },
+  { NULL,     UNMATCHABLE,    Token::ILLEGAL },
+  { NULL,     UNMATCHABLE,    Token::ILLEGAL },
+  { "return", KEYWORD_PREFIX, Token::RETURN },
+  { "switch", KEYWORD_PREFIX, Token::SWITCH },
+  { NULL,     T,              Token::ILLEGAL },
+  { NULL,     UNMATCHABLE,    Token::ILLEGAL },
+  { NULL,     V,              Token::ILLEGAL },
+  { NULL,     W,              Token::ILLEGAL }
+};
+
+
+void KeywordMatcher::Step(unibrow::uchar input) {
+  switch (state_) {
+    case INITIAL: {
+      // matching the first character is the only state with significant fanout.
+      // Match only lower-case letters in range 'b'..'w'.
+      unsigned int offset = input - kFirstCharRangeMin;
+      if (offset < kFirstCharRangeLength) {
+        state_ = first_states_[offset].state;
+        if (state_ == KEYWORD_PREFIX) {
+          keyword_ = first_states_[offset].keyword;
+          counter_ = 1;
+          keyword_token_ = first_states_[offset].token;
+        }
+        return;
+      }
+      break;
+    }
+    case KEYWORD_PREFIX:
+      if (static_cast<unibrow::uchar>(keyword_[counter_]) == input) {
+        counter_++;
+        if (keyword_[counter_] == '\0') {
+          state_ = KEYWORD_MATCHED;
+          token_ = keyword_token_;
+        }
+        return;
+      }
+      break;
+    case KEYWORD_MATCHED:
+      token_ = Token::IDENTIFIER;
+      break;
+    case C:
+      if (MatchState(input, 'a', CA)) return;
+      if (MatchState(input, 'o', CO)) return;
+      break;
+    case CA:
+      if (MatchKeywordStart(input, "case", 2, Token::CASE)) return;
+      if (MatchKeywordStart(input, "catch", 2, Token::CATCH)) return;
+      break;
+    case CO:
+      if (MatchState(input, 'n', CON)) return;
+      break;
+    case CON:
+      if (MatchKeywordStart(input, "const", 3, Token::CONST)) return;
+      if (MatchKeywordStart(input, "continue", 3, Token::CONTINUE)) return;
+      break;
+    case D:
+      if (MatchState(input, 'e', DE)) return;
+      if (MatchKeyword(input, 'o', KEYWORD_MATCHED, Token::DO)) return;
+      break;
+    case DE:
+      if (MatchKeywordStart(input, "debugger", 2, Token::DEBUGGER)) return;
+      if (MatchKeywordStart(input, "default", 2, Token::DEFAULT)) return;
+      if (MatchKeywordStart(input, "delete", 2, Token::DELETE)) return;
+      break;
+    case F:
+      if (MatchKeywordStart(input, "false", 1, Token::FALSE_LITERAL)) return;
+      if (MatchKeywordStart(input, "finally", 1, Token::FINALLY)) return;
+      if (MatchKeywordStart(input, "for", 1, Token::FOR)) return;
+      if (MatchKeywordStart(input, "function", 1, Token::FUNCTION)) return;
+      break;
+    case I:
+      if (MatchKeyword(input, 'f', KEYWORD_MATCHED, Token::IF)) return;
+      if (MatchKeyword(input, 'n', IN, Token::IN)) return;
+      break;
+    case IN:
+      token_ = Token::IDENTIFIER;
+      if (MatchKeywordStart(input, "instanceof", 2, Token::INSTANCEOF)) {
+        return;
+      }
+      break;
+    case N:
+      if (MatchKeywordStart(input, "native", 1, Token::NATIVE)) return;
+      if (MatchKeywordStart(input, "new", 1, Token::NEW)) return;
+      if (MatchKeywordStart(input, "null", 1, Token::NULL_LITERAL)) return;
+      break;
+    case T:
+      if (MatchState(input, 'h', TH)) return;
+      if (MatchState(input, 'r', TR)) return;
+      if (MatchKeywordStart(input, "typeof", 1, Token::TYPEOF)) return;
+      break;
+    case TH:
+      if (MatchKeywordStart(input, "this", 2, Token::THIS)) return;
+      if (MatchKeywordStart(input, "throw", 2, Token::THROW)) return;
+      break;
+    case TR:
+      if (MatchKeywordStart(input, "true", 2, Token::TRUE_LITERAL)) return;
+      if (MatchKeyword(input, 'y', KEYWORD_MATCHED, Token::TRY)) return;
+      break;
+    case V:
+      if (MatchKeywordStart(input, "var", 1, Token::VAR)) return;
+      if (MatchKeywordStart(input, "void", 1, Token::VOID)) return;
+      break;
+    case W:
+      if (MatchKeywordStart(input, "while", 1, Token::WHILE)) return;
+      if (MatchKeywordStart(input, "with", 1, Token::WITH)) return;
+      break;
+    case UNMATCHABLE:
+      break;
+  }
+  // On fallthrough, it's a failure.
+  state_ = UNMATCHABLE;
+}
+
+} }  // namespace v8::internal
diff --git a/deps/v8/src/scanner-base.h b/deps/v8/src/scanner-base.h
new file mode 100644 (file)
index 0000000..50f3030
--- /dev/null
@@ -0,0 +1,206 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Features shared by parsing and pre-parsing scanners.
+
+#ifndef V8_SCANNER_BASE_H_
+#define V8_SCANNER_BASE_H_
+
+#include "globals.h"
+#include "checks.h"
+#include "allocation.h"
+#include "token.h"
+#include "unicode-inl.h"
+#include "char-predicates.h"
+#include "utils.h"
+
+namespace v8 {
+namespace internal {
+
+// Interface through which the scanner reads characters from the input source.
+class UTF16Buffer {
+ public:
+  UTF16Buffer();
+  virtual ~UTF16Buffer() {}
+
+  virtual void PushBack(uc32 ch) = 0;
+  // Returns a value < 0 when the buffer end is reached.
+  virtual uc32 Advance() = 0;
+  virtual void SeekForward(int pos) = 0;
+
+  int pos() const { return pos_; }
+
+ protected:
+  int pos_;  // Current position in the buffer.
+  int end_;  // Position where scanning should stop (EOF).
+};
+
+
+class ScannerConstants : AllStatic {
+ public:
+  typedef unibrow::Utf8InputBuffer<1024> Utf8Decoder;
+
+  static StaticResource<Utf8Decoder>* utf8_decoder() {
+    return &utf8_decoder_;
+  }
+
+  static unibrow::Predicate<IdentifierStart, 128> kIsIdentifierStart;
+  static unibrow::Predicate<IdentifierPart, 128> kIsIdentifierPart;
+  static unibrow::Predicate<unibrow::LineTerminator, 128> kIsLineTerminator;
+  static unibrow::Predicate<unibrow::WhiteSpace, 128> kIsWhiteSpace;
+
+  static bool IsIdentifier(unibrow::CharacterStream* buffer);
+
+ private:
+  static StaticResource<Utf8Decoder> utf8_decoder_;
+};
+
+
+class KeywordMatcher {
+//  Incrementally recognize keywords.
+//
+//  Recognized keywords:
+//      break case catch const* continue debugger* default delete do else
+//      finally false for function if in instanceof native* new null
+//      return switch this throw true try typeof var void while with
+//
+//  *: Actually "future reserved keywords". These are the only ones we
+//     recognize, the remaining are allowed as identifiers.
+//     In ES5 strict mode, we should disallow all reserved keywords.
+ public:
+  KeywordMatcher()
+      : state_(INITIAL),
+        token_(Token::IDENTIFIER),
+        keyword_(NULL),
+        counter_(0),
+        keyword_token_(Token::ILLEGAL) {}
+
+  Token::Value token() { return token_; }
+
+  inline void AddChar(unibrow::uchar input) {
+    if (state_ != UNMATCHABLE) {
+      Step(input);
+    }
+  }
+
+  void Fail() {
+    token_ = Token::IDENTIFIER;
+    state_ = UNMATCHABLE;
+  }
+
+ private:
+  enum State {
+    UNMATCHABLE,
+    INITIAL,
+    KEYWORD_PREFIX,
+    KEYWORD_MATCHED,
+    C,
+    CA,
+    CO,
+    CON,
+    D,
+    DE,
+    F,
+    I,
+    IN,
+    N,
+    T,
+    TH,
+    TR,
+    V,
+    W
+  };
+
+  struct FirstState {
+    const char* keyword;
+    State state;
+    Token::Value token;
+  };
+
+  // Range of possible first characters of a keyword.
+  static const unsigned int kFirstCharRangeMin = 'b';
+  static const unsigned int kFirstCharRangeMax = 'w';
+  static const unsigned int kFirstCharRangeLength =
+      kFirstCharRangeMax - kFirstCharRangeMin + 1;
+  // State map for first keyword character range.
+  static FirstState first_states_[kFirstCharRangeLength];
+
+  // If input equals keyword's character at position, continue matching keyword
+  // from that position.
+  inline bool MatchKeywordStart(unibrow::uchar input,
+                                const char* keyword,
+                                int position,
+                                Token::Value token_if_match) {
+    if (input == static_cast<unibrow::uchar>(keyword[position])) {
+      state_ = KEYWORD_PREFIX;
+      this->keyword_ = keyword;
+      this->counter_ = position + 1;
+      this->keyword_token_ = token_if_match;
+      return true;
+    }
+    return false;
+  }
+
+  // If input equals match character, transition to new state and return true.
+  inline bool MatchState(unibrow::uchar input, char match, State new_state) {
+    if (input == static_cast<unibrow::uchar>(match)) {
+      state_ = new_state;
+      return true;
+    }
+    return false;
+  }
+
+  inline bool MatchKeyword(unibrow::uchar input,
+                           char match,
+                           State new_state,
+                           Token::Value keyword_token) {
+    if (input != static_cast<unibrow::uchar>(match)) {
+      return false;
+    }
+    state_ = new_state;
+    token_ = keyword_token;
+    return true;
+  }
+
+  void Step(unibrow::uchar input);
+
+  // Current state.
+  State state_;
+  // Token for currently added characters.
+  Token::Value token_;
+
+  // Matching a specific keyword string (there is only one possible valid
+  // keyword with the current prefix).
+  const char* keyword_;
+  int counter_;
+  Token::Value keyword_token_;
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_SCANNER_BASE_H_
index 79d63f1774dceaceceec1eccb19aebb218bb3a34..6b2fcb4c5ec6307a7f5326b99dbd5a06e1021142 100755 (executable)
 #include "ast.h"
 #include "handles.h"
 #include "scanner.h"
+#include "unicode-inl.h"
 
 namespace v8 {
 namespace internal {
 
-// ----------------------------------------------------------------------------
-// Character predicates
-
-
-unibrow::Predicate<IdentifierStart, 128> Scanner::kIsIdentifierStart;
-unibrow::Predicate<IdentifierPart, 128> Scanner::kIsIdentifierPart;
-unibrow::Predicate<unibrow::LineTerminator, 128> Scanner::kIsLineTerminator;
-unibrow::Predicate<unibrow::WhiteSpace, 128> Scanner::kIsWhiteSpace;
-
-
-StaticResource<Scanner::Utf8Decoder> Scanner::utf8_decoder_;
-
-
 // ----------------------------------------------------------------------------
 // UTF8Buffer
 
-UTF8Buffer::UTF8Buffer() : buffer_(kInitialCapacity) { }
+UTF8Buffer::UTF8Buffer() : buffer_(kInitialCapacity), recording_(false) { }
 
 
 UTF8Buffer::~UTF8Buffer() {}
@@ -135,191 +123,6 @@ void CharacterStreamUTF16Buffer::SeekForward(int pos) {
 }
 
 
-// ExternalStringUTF16Buffer
-template <typename StringType, typename CharType>
-ExternalStringUTF16Buffer<StringType, CharType>::ExternalStringUTF16Buffer()
-    : raw_data_(NULL) { }
-
-
-template <typename StringType, typename CharType>
-void ExternalStringUTF16Buffer<StringType, CharType>::Initialize(
-     Handle<StringType> data,
-     int start_position,
-     int end_position) {
-  ASSERT(!data.is_null());
-  raw_data_ = data->resource()->data();
-
-  ASSERT(end_position <= data->length());
-  if (start_position > 0) {
-    SeekForward(start_position);
-  }
-  end_ =
-      end_position != Scanner::kNoEndPosition ? end_position : data->length();
-}
-
-
-template <typename StringType, typename CharType>
-uc32 ExternalStringUTF16Buffer<StringType, CharType>::Advance() {
-  if (pos_ < end_) {
-    return raw_data_[pos_++];
-  } else {
-    // note: currently the following increment is necessary to avoid a
-    // test-parser problem!
-    pos_++;
-    return static_cast<uc32>(-1);
-  }
-}
-
-
-template <typename StringType, typename CharType>
-void ExternalStringUTF16Buffer<StringType, CharType>::PushBack(uc32 ch) {
-  pos_--;
-  ASSERT(pos_ >= Scanner::kCharacterLookaheadBufferSize);
-  ASSERT(raw_data_[pos_ - Scanner::kCharacterLookaheadBufferSize] == ch);
-}
-
-
-template <typename StringType, typename CharType>
-void ExternalStringUTF16Buffer<StringType, CharType>::SeekForward(int pos) {
-  pos_ = pos;
-}
-
-
-// ----------------------------------------------------------------------------
-// Keyword Matcher
-
-KeywordMatcher::FirstState KeywordMatcher::first_states_[] = {
-  { "break",  KEYWORD_PREFIX, Token::BREAK },
-  { NULL,     C,              Token::ILLEGAL },
-  { NULL,     D,              Token::ILLEGAL },
-  { "else",   KEYWORD_PREFIX, Token::ELSE },
-  { NULL,     F,              Token::ILLEGAL },
-  { NULL,     UNMATCHABLE,    Token::ILLEGAL },
-  { NULL,     UNMATCHABLE,    Token::ILLEGAL },
-  { NULL,     I,              Token::ILLEGAL },
-  { NULL,     UNMATCHABLE,    Token::ILLEGAL },
-  { NULL,     UNMATCHABLE,    Token::ILLEGAL },
-  { NULL,     UNMATCHABLE,    Token::ILLEGAL },
-  { NULL,     UNMATCHABLE,    Token::ILLEGAL },
-  { NULL,     N,              Token::ILLEGAL },
-  { NULL,     UNMATCHABLE,    Token::ILLEGAL },
-  { NULL,     UNMATCHABLE,    Token::ILLEGAL },
-  { NULL,     UNMATCHABLE,    Token::ILLEGAL },
-  { "return", KEYWORD_PREFIX, Token::RETURN },
-  { "switch", KEYWORD_PREFIX, Token::SWITCH },
-  { NULL,     T,              Token::ILLEGAL },
-  { NULL,     UNMATCHABLE,    Token::ILLEGAL },
-  { NULL,     V,              Token::ILLEGAL },
-  { NULL,     W,              Token::ILLEGAL }
-};
-
-
-void KeywordMatcher::Step(uc32 input) {
-  switch (state_) {
-    case INITIAL: {
-      // matching the first character is the only state with significant fanout.
-      // Match only lower-case letters in range 'b'..'w'.
-      unsigned int offset = input - kFirstCharRangeMin;
-      if (offset < kFirstCharRangeLength) {
-        state_ = first_states_[offset].state;
-        if (state_ == KEYWORD_PREFIX) {
-          keyword_ = first_states_[offset].keyword;
-          counter_ = 1;
-          keyword_token_ = first_states_[offset].token;
-        }
-        return;
-      }
-      break;
-    }
-    case KEYWORD_PREFIX:
-      if (keyword_[counter_] == input) {
-        ASSERT_NE(input, '\0');
-        counter_++;
-        if (keyword_[counter_] == '\0') {
-          state_ = KEYWORD_MATCHED;
-          token_ = keyword_token_;
-        }
-        return;
-      }
-      break;
-    case KEYWORD_MATCHED:
-      token_ = Token::IDENTIFIER;
-      break;
-    case C:
-      if (MatchState(input, 'a', CA)) return;
-      if (MatchState(input, 'o', CO)) return;
-      break;
-    case CA:
-      if (MatchKeywordStart(input, "case", 2, Token::CASE)) return;
-      if (MatchKeywordStart(input, "catch", 2, Token::CATCH)) return;
-      break;
-    case CO:
-      if (MatchState(input, 'n', CON)) return;
-      break;
-    case CON:
-      if (MatchKeywordStart(input, "const", 3, Token::CONST)) return;
-      if (MatchKeywordStart(input, "continue", 3, Token::CONTINUE)) return;
-      break;
-    case D:
-      if (MatchState(input, 'e', DE)) return;
-      if (MatchKeyword(input, 'o', KEYWORD_MATCHED, Token::DO)) return;
-      break;
-    case DE:
-      if (MatchKeywordStart(input, "debugger", 2, Token::DEBUGGER)) return;
-      if (MatchKeywordStart(input, "default", 2, Token::DEFAULT)) return;
-      if (MatchKeywordStart(input, "delete", 2, Token::DELETE)) return;
-      break;
-    case F:
-      if (MatchKeywordStart(input, "false", 1, Token::FALSE_LITERAL)) return;
-      if (MatchKeywordStart(input, "finally", 1, Token::FINALLY)) return;
-      if (MatchKeywordStart(input, "for", 1, Token::FOR)) return;
-      if (MatchKeywordStart(input, "function", 1, Token::FUNCTION)) return;
-      break;
-    case I:
-      if (MatchKeyword(input, 'f', KEYWORD_MATCHED, Token::IF)) return;
-      if (MatchKeyword(input, 'n', IN, Token::IN)) return;
-      break;
-    case IN:
-      token_ = Token::IDENTIFIER;
-      if (MatchKeywordStart(input, "instanceof", 2, Token::INSTANCEOF)) {
-        return;
-      }
-      break;
-    case N:
-      if (MatchKeywordStart(input, "native", 1, Token::NATIVE)) return;
-      if (MatchKeywordStart(input, "new", 1, Token::NEW)) return;
-      if (MatchKeywordStart(input, "null", 1, Token::NULL_LITERAL)) return;
-      break;
-    case T:
-      if (MatchState(input, 'h', TH)) return;
-      if (MatchState(input, 'r', TR)) return;
-      if (MatchKeywordStart(input, "typeof", 1, Token::TYPEOF)) return;
-      break;
-    case TH:
-      if (MatchKeywordStart(input, "this", 2, Token::THIS)) return;
-      if (MatchKeywordStart(input, "throw", 2, Token::THROW)) return;
-      break;
-    case TR:
-      if (MatchKeywordStart(input, "true", 2, Token::TRUE_LITERAL)) return;
-      if (MatchKeyword(input, 'y', KEYWORD_MATCHED, Token::TRY)) return;
-      break;
-    case V:
-      if (MatchKeywordStart(input, "var", 1, Token::VAR)) return;
-      if (MatchKeywordStart(input, "void", 1, Token::VOID)) return;
-      break;
-    case W:
-      if (MatchKeywordStart(input, "while", 1, Token::WHILE)) return;
-      if (MatchKeywordStart(input, "with", 1, Token::WITH)) return;
-      break;
-    default:
-      UNREACHABLE();
-  }
-  // On fallthrough, it's a failure.
-  state_ = UNMATCHABLE;
-}
-
-
-
 // ----------------------------------------------------------------------------
 // Scanner::LiteralScope
 
@@ -445,7 +248,7 @@ void Scanner::StartLiteral() {
 }
 
 
-void Scanner::AddChar(uc32 c) {
+void Scanner::AddLiteralChar(uc32 c) {
   literal_buffer_.AddChar(c);
 }
 
@@ -460,8 +263,8 @@ void Scanner::DropLiteral() {
 }
 
 
-void Scanner::AddCharAdvance() {
-  AddChar(c0_);
+void Scanner::AddLiteralCharAdvance() {
+  AddLiteralChar(c0_);
   Advance();
 }
 
@@ -494,9 +297,9 @@ bool Scanner::SkipJavaScriptWhiteSpace() {
   while (true) {
     // We treat byte-order marks (BOMs) as whitespace for better
     // compatibility with Spidermonkey and other JavaScript engines.
-    while (kIsWhiteSpace.get(c0_) || IsByteOrderMark(c0_)) {
+    while (ScannerConstants::kIsWhiteSpace.get(c0_) || IsByteOrderMark(c0_)) {
       // IsWhiteSpace() includes line terminators!
-      if (kIsLineTerminator.get(c0_)) {
+      if (ScannerConstants::kIsLineTerminator.get(c0_)) {
         // Ignore line terminators, but remember them. This is necessary
         // for automatic semicolon insertion.
         has_line_terminator_before_next_ = true;
@@ -536,7 +339,7 @@ Token::Value Scanner::SkipSingleLineComment() {
   // separately by the lexical grammar and becomes part of the
   // stream of input elements for the syntactic grammar (see
   // ECMA-262, section 7.4, page 12).
-  while (c0_ >= 0 && !kIsLineTerminator.get(c0_)) {
+  while (c0_ >= 0 && !ScannerConstants::kIsLineTerminator.get(c0_)) {
     Advance();
   }
 
@@ -673,29 +476,29 @@ Token::Value Scanner::ScanJsonString() {
     // Check for control character (0x00-0x1f) or unterminated string (<0).
     if (c0_ < 0x20) return Token::ILLEGAL;
     if (c0_ != '\\') {
-      AddCharAdvance();
+      AddLiteralCharAdvance();
     } else {
       Advance();
       switch (c0_) {
         case '"':
         case '\\':
         case '/':
-          AddChar(c0_);
+          AddLiteralChar(c0_);
           break;
         case 'b':
-          AddChar('\x08');
+          AddLiteralChar('\x08');
           break;
         case 'f':
-          AddChar('\x0c');
+          AddLiteralChar('\x0c');
           break;
         case 'n':
-          AddChar('\x0a');
+          AddLiteralChar('\x0a');
           break;
         case 'r':
-          AddChar('\x0d');
+          AddLiteralChar('\x0d');
           break;
         case 't':
-          AddChar('\x09');
+          AddLiteralChar('\x09');
           break;
         case 'u': {
           uc32 value = 0;
@@ -707,7 +510,7 @@ Token::Value Scanner::ScanJsonString() {
             }
             value = value * 16 + digit;
           }
-          AddChar(value);
+          AddLiteralChar(value);
           break;
         }
         default:
@@ -727,31 +530,31 @@ Token::Value Scanner::ScanJsonString() {
 
 Token::Value Scanner::ScanJsonNumber() {
   LiteralScope literal(this);
-  if (c0_ == '-') AddCharAdvance();
+  if (c0_ == '-') AddLiteralCharAdvance();
   if (c0_ == '0') {
-    AddCharAdvance();
+    AddLiteralCharAdvance();
     // Prefix zero is only allowed if it's the only digit before
     // a decimal point or exponent.
     if ('0' <= c0_ && c0_ <= '9') return Token::ILLEGAL;
   } else {
     if (c0_ < '1' || c0_ > '9') return Token::ILLEGAL;
     do {
-      AddCharAdvance();
+      AddLiteralCharAdvance();
     } while (c0_ >= '0' && c0_ <= '9');
   }
   if (c0_ == '.') {
-    AddCharAdvance();
+    AddLiteralCharAdvance();
     if (c0_ < '0' || c0_ > '9') return Token::ILLEGAL;
     do {
-      AddCharAdvance();
+      AddLiteralCharAdvance();
     } while (c0_ >= '0' && c0_ <= '9');
   }
   if (AsciiAlphaToLower(c0_) == 'e') {
-    AddCharAdvance();
-    if (c0_ == '-' || c0_ == '+') AddCharAdvance();
+    AddLiteralCharAdvance();
+    if (c0_ == '-' || c0_ == '+') AddLiteralCharAdvance();
     if (c0_ < '0' || c0_ > '9') return Token::ILLEGAL;
     do {
-      AddCharAdvance();
+      AddLiteralCharAdvance();
     } while (c0_ >= '0' && c0_ <= '9');
   }
   literal.Complete();
@@ -767,7 +570,7 @@ Token::Value Scanner::ScanJsonIdentifier(const char* text,
     Advance();
     text++;
   }
-  if (kIsIdentifierPart.get(c0_)) return Token::ILLEGAL;
+  if (ScannerConstants::kIsIdentifierPart.get(c0_)) return Token::ILLEGAL;
   literal.Complete();
   return token;
 }
@@ -990,7 +793,7 @@ void Scanner::ScanJavaScript() {
         break;
 
       default:
-        if (kIsIdentifierStart.get(c0_)) {
+        if (ScannerConstants::kIsIdentifierStart.get(c0_)) {
           token = ScanIdentifier();
         } else if (IsDecimalDigit(c0_)) {
           token = ScanNumber(false);
@@ -1073,7 +876,7 @@ void Scanner::ScanEscape() {
   Advance();
 
   // Skip escaped newlines.
-  if (kIsLineTerminator.get(c)) {
+  if (ScannerConstants::kIsLineTerminator.get(c)) {
     // Allow CR+LF newlines in multiline string literals.
     if (IsCarriageReturn(c) && IsLineFeed(c0_)) Advance();
     // Allow LF+CR newlines in multiline string literals.
@@ -1106,7 +909,7 @@ void Scanner::ScanEscape() {
   // According to ECMA-262, 3rd, 7.8.4 (p 18ff) these
   // should be illegal, but they are commonly handled
   // as non-escaped characters by JS VMs.
-  AddChar(c);
+  AddLiteralChar(c);
 }
 
 
@@ -1115,14 +918,15 @@ Token::Value Scanner::ScanString() {
   Advance();  // consume quote
 
   LiteralScope literal(this);
-  while (c0_ != quote && c0_ >= 0 && !kIsLineTerminator.get(c0_)) {
+  while (c0_ != quote && c0_ >= 0
+         && !ScannerConstants::kIsLineTerminator.get(c0_)) {
     uc32 c = c0_;
     Advance();
     if (c == '\\') {
       if (c0_ < 0) return Token::ILLEGAL;
       ScanEscape();
     } else {
-      AddChar(c);
+      AddLiteralChar(c);
     }
   }
   if (c0_ != quote) return Token::ILLEGAL;
@@ -1153,7 +957,7 @@ Token::Value Scanner::Select(uc32 next, Token::Value then, Token::Value else_) {
 // Returns true if any decimal digits were scanned, returns false otherwise.
 void Scanner::ScanDecimalDigits() {
   while (IsDecimalDigit(c0_))
-    AddCharAdvance();
+    AddLiteralCharAdvance();
 }
 
 
@@ -1165,25 +969,25 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
   LiteralScope literal(this);
   if (seen_period) {
     // we have already seen a decimal point of the float
-    AddChar('.');
+    AddLiteralChar('.');
     ScanDecimalDigits();  // we know we have at least one digit
 
   } else {
     // if the first character is '0' we must check for octals and hex
     if (c0_ == '0') {
-      AddCharAdvance();
+      AddLiteralCharAdvance();
 
       // either 0, 0exxx, 0Exxx, 0.xxx, an octal number, or a hex number
       if (c0_ == 'x' || c0_ == 'X') {
         // hex number
         kind = HEX;
-        AddCharAdvance();
+        AddLiteralCharAdvance();
         if (!IsHexDigit(c0_)) {
           // we must have at least one hex digit after 'x'/'X'
           return Token::ILLEGAL;
         }
         while (IsHexDigit(c0_)) {
-          AddCharAdvance();
+          AddLiteralCharAdvance();
         }
       } else if ('0' <= c0_ && c0_ <= '7') {
         // (possible) octal number
@@ -1194,7 +998,7 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
             break;
           }
           if (c0_  < '0' || '7'  < c0_) break;
-          AddCharAdvance();
+          AddLiteralCharAdvance();
         }
       }
     }
@@ -1203,7 +1007,7 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
     if (kind == DECIMAL) {
       ScanDecimalDigits();  // optional
       if (c0_ == '.') {
-        AddCharAdvance();
+        AddLiteralCharAdvance();
         ScanDecimalDigits();  // optional
       }
     }
@@ -1214,9 +1018,9 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
     ASSERT(kind != HEX);  // 'e'/'E' must be scanned as part of the hex number
     if (kind == OCTAL) return Token::ILLEGAL;  // no exponent for octals allowed
     // scan exponent
-    AddCharAdvance();
+    AddLiteralCharAdvance();
     if (c0_ == '+' || c0_ == '-')
-      AddCharAdvance();
+      AddLiteralCharAdvance();
     if (!IsDecimalDigit(c0_)) {
       // we must have at least one decimal digit after 'e'/'E'
       return Token::ILLEGAL;
@@ -1228,7 +1032,7 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
   // not be an identifier start or a decimal digit; see ECMA-262
   // section 7.8.3, page 17 (note that we read only one decimal digit
   // if the value is 0).
-  if (IsDecimalDigit(c0_) || kIsIdentifierStart.get(c0_))
+  if (IsDecimalDigit(c0_) || ScannerConstants::kIsIdentifierStart.get(c0_))
     return Token::ILLEGAL;
 
   literal.Complete();
@@ -1250,7 +1054,7 @@ uc32 Scanner::ScanIdentifierUnicodeEscape() {
 
 
 Token::Value Scanner::ScanIdentifier() {
-  ASSERT(kIsIdentifierStart.get(c0_));
+  ASSERT(ScannerConstants::kIsIdentifierStart.get(c0_));
 
   LiteralScope literal(this);
   KeywordMatcher keyword_match;
@@ -1259,25 +1063,25 @@ Token::Value Scanner::ScanIdentifier() {
   if (c0_ == '\\') {
     uc32 c = ScanIdentifierUnicodeEscape();
     // Only allow legal identifier start characters.
-    if (!kIsIdentifierStart.get(c)) return Token::ILLEGAL;
-    AddChar(c);
+    if (!ScannerConstants::kIsIdentifierStart.get(c)) return Token::ILLEGAL;
+    AddLiteralChar(c);
     keyword_match.Fail();
   } else {
-    AddChar(c0_);
+    AddLiteralChar(c0_);
     keyword_match.AddChar(c0_);
     Advance();
   }
 
   // Scan the rest of the identifier characters.
-  while (kIsIdentifierPart.get(c0_)) {
+  while (ScannerConstants::kIsIdentifierPart.get(c0_)) {
     if (c0_ == '\\') {
       uc32 c = ScanIdentifierUnicodeEscape();
       // Only allow legal identifier part characters.
-      if (!kIsIdentifierPart.get(c)) return Token::ILLEGAL;
-      AddChar(c);
+      if (!ScannerConstants::kIsIdentifierPart.get(c)) return Token::ILLEGAL;
+      AddLiteralChar(c);
       keyword_match.Fail();
     } else {
-      AddChar(c0_);
+      AddLiteralChar(c0_);
       keyword_match.AddChar(c0_);
       Advance();
     }
@@ -1289,17 +1093,6 @@ Token::Value Scanner::ScanIdentifier() {
 
 
 
-bool Scanner::IsIdentifier(unibrow::CharacterStream* buffer) {
-  // Checks whether the buffer contains an identifier (no escape).
-  if (!buffer->has_more()) return false;
-  if (!kIsIdentifierStart.get(buffer->GetNext())) return false;
-  while (buffer->has_more()) {
-    if (!kIsIdentifierPart.get(buffer->GetNext())) return false;
-  }
-  return true;
-}
-
-
 bool Scanner::ScanRegExpPattern(bool seen_equal) {
   // Scan: ('/' | '/=') RegularExpressionBody '/' RegularExpressionFlags
   bool in_character_class = false;
@@ -1314,18 +1107,18 @@ bool Scanner::ScanRegExpPattern(bool seen_equal) {
   // constructor.
   LiteralScope literal(this);
   if (seen_equal)
-    AddChar('=');
+    AddLiteralChar('=');
 
   while (c0_ != '/' || in_character_class) {
-    if (kIsLineTerminator.get(c0_) || c0_ < 0) return false;
+    if (ScannerConstants::kIsLineTerminator.get(c0_) || c0_ < 0) return false;
     if (c0_ == '\\') {  // escaped character
-      AddCharAdvance();
-      if (kIsLineTerminator.get(c0_) || c0_ < 0) return false;
-      AddCharAdvance();
+      AddLiteralCharAdvance();
+      if (ScannerConstants::kIsLineTerminator.get(c0_) || c0_ < 0) return false;
+      AddLiteralCharAdvance();
     } else {  // unescaped character
       if (c0_ == '[') in_character_class = true;
       if (c0_ == ']') in_character_class = false;
-      AddCharAdvance();
+      AddLiteralCharAdvance();
     }
   }
   Advance();  // consume '/'
@@ -1338,17 +1131,17 @@ bool Scanner::ScanRegExpPattern(bool seen_equal) {
 bool Scanner::ScanRegExpFlags() {
   // Scan regular expression flags.
   LiteralScope literal(this);
-  while (kIsIdentifierPart.get(c0_)) {
+  while (ScannerConstants::kIsIdentifierPart.get(c0_)) {
     if (c0_ == '\\') {
       uc32 c = ScanIdentifierUnicodeEscape();
       if (c != static_cast<uc32>(unibrow::Utf8::kBadChar)) {
         // We allow any escaped character, unlike the restriction on
         // IdentifierPart when it is used to build an IdentifierName.
-        AddChar(c);
+        AddLiteralChar(c);
         continue;
       }
     }
-    AddCharAdvance();
+    AddLiteralCharAdvance();
   }
   literal.Complete();
 
index dab3d672815fb29803588bdf778226b2201797a3..df5cd729491de7c3aa61649935d28867cf4e941c 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "token.h"
 #include "char-predicates-inl.h"
+#include "scanner-base.h"
 
 namespace v8 {
 namespace internal {
@@ -41,25 +42,35 @@ class UTF8Buffer {
   ~UTF8Buffer();
 
   inline void AddChar(uc32 c) {
-    if (static_cast<unsigned>(c) <= unibrow::Utf8::kMaxOneByteChar) {
-      buffer_.Add(static_cast<char>(c));
-    } else {
-      AddCharSlow(c);
+    if (recording_) {
+      if (static_cast<unsigned>(c) <= unibrow::Utf8::kMaxOneByteChar) {
+        buffer_.Add(static_cast<char>(c));
+      } else {
+        AddCharSlow(c);
+      }
     }
   }
 
   void StartLiteral() {
     buffer_.StartSequence();
+    recording_ = true;
   }
 
   Vector<const char> EndLiteral() {
-    buffer_.Add(kEndMarker);
-    Vector<char> sequence = buffer_.EndSequence();
-    return Vector<const char>(sequence.start(), sequence.length());
+    if (recording_) {
+      recording_ = false;
+      buffer_.Add(kEndMarker);
+      Vector<char> sequence = buffer_.EndSequence();
+      return Vector<const char>(sequence.start(), sequence.length());
+    }
+    return Vector<const char>();
   }
 
   void DropLiteral() {
-    buffer_.DropSequence();
+    if (recording_) {
+      recording_ = false;
+      buffer_.DropSequence();
+    }
   }
 
   void Reset() {
@@ -78,30 +89,11 @@ class UTF8Buffer {
  private:
   static const int kInitialCapacity = 256;
   SequenceCollector<char, 4> buffer_;
-
+  bool recording_;
   void AddCharSlow(uc32 c);
 };
 
 
-// Interface through which the scanner reads characters from the input source.
-class UTF16Buffer {
- public:
-  UTF16Buffer();
-  virtual ~UTF16Buffer() {}
-
-  virtual void PushBack(uc32 ch) = 0;
-  // Returns a value < 0 when the buffer end is reached.
-  virtual uc32 Advance() = 0;
-  virtual void SeekForward(int pos) = 0;
-
-  int pos() const { return pos_; }
-
- protected:
-  int pos_;  // Current position in the buffer.
-  int end_;  // Position where scanning should stop (EOF).
-};
-
-
 // UTF16 buffer to read characters from a character stream.
 class CharacterStreamUTF16Buffer: public UTF16Buffer {
  public:
@@ -142,127 +134,6 @@ class ExternalStringUTF16Buffer: public UTF16Buffer {
 };
 
 
-class KeywordMatcher {
-//  Incrementally recognize keywords.
-//
-//  Recognized keywords:
-//      break case catch const* continue debugger* default delete do else
-//      finally false for function if in instanceof native* new null
-//      return switch this throw true try typeof var void while with
-//
-//  *: Actually "future reserved keywords". These are the only ones we
-//     recognized, the remaining are allowed as identifiers.
- public:
-  KeywordMatcher()
-      : state_(INITIAL),
-        token_(Token::IDENTIFIER),
-        keyword_(NULL),
-        counter_(0),
-        keyword_token_(Token::ILLEGAL) {}
-
-  Token::Value token() { return token_; }
-
-  inline void AddChar(uc32 input) {
-    if (state_ != UNMATCHABLE) {
-      Step(input);
-    }
-  }
-
-  void Fail() {
-    token_ = Token::IDENTIFIER;
-    state_ = UNMATCHABLE;
-  }
-
- private:
-  enum State {
-    UNMATCHABLE,
-    INITIAL,
-    KEYWORD_PREFIX,
-    KEYWORD_MATCHED,
-    C,
-    CA,
-    CO,
-    CON,
-    D,
-    DE,
-    F,
-    I,
-    IN,
-    N,
-    T,
-    TH,
-    TR,
-    V,
-    W
-  };
-
-  struct FirstState {
-    const char* keyword;
-    State state;
-    Token::Value token;
-  };
-
-  // Range of possible first characters of a keyword.
-  static const unsigned int kFirstCharRangeMin = 'b';
-  static const unsigned int kFirstCharRangeMax = 'w';
-  static const unsigned int kFirstCharRangeLength =
-      kFirstCharRangeMax - kFirstCharRangeMin + 1;
-  // State map for first keyword character range.
-  static FirstState first_states_[kFirstCharRangeLength];
-
-  // If input equals keyword's character at position, continue matching keyword
-  // from that position.
-  inline bool MatchKeywordStart(uc32 input,
-                                const char* keyword,
-                                int position,
-                                Token::Value token_if_match) {
-    if (input == keyword[position]) {
-      state_ = KEYWORD_PREFIX;
-      this->keyword_ = keyword;
-      this->counter_ = position + 1;
-      this->keyword_token_ = token_if_match;
-      return true;
-    }
-    return false;
-  }
-
-  // If input equals match character, transition to new state and return true.
-  inline bool MatchState(uc32 input, char match, State new_state) {
-    if (input == match) {
-      state_ = new_state;
-      return true;
-    }
-    return false;
-  }
-
-  inline bool MatchKeyword(uc32 input,
-                           char match,
-                           State new_state,
-                           Token::Value keyword_token) {
-    if (input != match) {
-      return false;
-    }
-    state_ = new_state;
-    token_ = keyword_token;
-    return true;
-  }
-
-  void Step(uc32 input);
-
-  // Current state.
-  State state_;
-  // Token for currently added characters.
-  Token::Value token_;
-
-  // Matching a specific keyword string (there is only one possible valid
-  // keyword with the current prefix).
-  const char* keyword_;
-  int counter_;
-  Token::Value keyword_token_;
-};
-
-
-enum ParserMode { PARSE, PREPARSE };
 enum ParserLanguage { JAVASCRIPT, JSON };
 
 
@@ -371,17 +242,10 @@ class Scanner {
 
   bool stack_overflow() { return stack_overflow_; }
 
-  static StaticResource<Utf8Decoder>* utf8_decoder() { return &utf8_decoder_; }
-
   // Tells whether the buffer contains an identifier (no escapes).
   // Used for checking if a property name is an identifier.
   static bool IsIdentifier(unibrow::CharacterStream* buffer);
 
-  static unibrow::Predicate<IdentifierStart, 128> kIsIdentifierStart;
-  static unibrow::Predicate<IdentifierPart, 128> kIsIdentifierPart;
-  static unibrow::Predicate<unibrow::LineTerminator, 128> kIsLineTerminator;
-  static unibrow::Predicate<unibrow::WhiteSpace, 128> kIsWhiteSpace;
-
   static const int kCharacterLookaheadBufferSize = 1;
   static const int kNoEndPosition = 1;
 
@@ -400,8 +264,8 @@ class Scanner {
 
   // Literal buffer support
   inline void StartLiteral();
-  inline void AddChar(uc32 ch);
-  inline void AddCharAdvance();
+  inline void AddLiteralChar(uc32 ch);
+  inline void AddLiteralCharAdvance();
   inline void TerminateLiteral();
   // Stops scanning of a literal, e.g., due to an encountered error.
   inline void DropLiteral();
@@ -511,12 +375,61 @@ class Scanner {
   UTF8Buffer literal_buffer_;
 
   bool stack_overflow_;
-  static StaticResource<Utf8Decoder> utf8_decoder_;
 
   // One Unicode character look-ahead; c0_ < 0 at the end of the input.
   uc32 c0_;
 };
 
+
+// ExternalStringUTF16Buffer
+template <typename StringType, typename CharType>
+ExternalStringUTF16Buffer<StringType, CharType>::ExternalStringUTF16Buffer()
+    : raw_data_(NULL) { }
+
+
+template <typename StringType, typename CharType>
+void ExternalStringUTF16Buffer<StringType, CharType>::Initialize(
+     Handle<StringType> data,
+     int start_position,
+     int end_position) {
+  ASSERT(!data.is_null());
+  raw_data_ = data->resource()->data();
+
+  ASSERT(end_position <= data->length());
+  if (start_position > 0) {
+    SeekForward(start_position);
+  }
+  end_ =
+      end_position != Scanner::kNoEndPosition ? end_position : data->length();
+}
+
+
+template <typename StringType, typename CharType>
+uc32 ExternalStringUTF16Buffer<StringType, CharType>::Advance() {
+  if (pos_ < end_) {
+    return raw_data_[pos_++];
+  } else {
+    // note: currently the following increment is necessary to avoid a
+    // test-parser problem!
+    pos_++;
+    return static_cast<uc32>(-1);
+  }
+}
+
+
+template <typename StringType, typename CharType>
+void ExternalStringUTF16Buffer<StringType, CharType>::PushBack(uc32 ch) {
+  pos_--;
+  ASSERT(pos_ >= Scanner::kCharacterLookaheadBufferSize);
+  ASSERT(raw_data_[pos_ - Scanner::kCharacterLookaheadBufferSize] == ch);
+}
+
+
+template <typename StringType, typename CharType>
+void ExternalStringUTF16Buffer<StringType, CharType>::SeekForward(int pos) {
+  pos_ = pos;
+}
+
 } }  // namespace v8::internal
 
 #endif  // V8_SCANNER_H_
index 763c12f4f576baf7e35ce71342e97110a7d925a0..15fed442b952aeb953e413d11132bb0e417492f9 100644 (file)
@@ -290,10 +290,6 @@ void ExternalReferenceTable::PopulateTable() {
     Add(Top::get_address_from_id((Top::AddressId)i), TOP_ADDRESS, i, chars);
   }
 
-  // Extensions
-  Add(FUNCTION_ADDR(GCExtension::GC), EXTENSION, 1,
-      "GCExtension::GC");
-
   // Accessors
 #define ACCESSOR_DESCRIPTOR_DECLARATION(name) \
   Add((Address)&Accessors::name, \
index e3fb923312911d6c2fdc495e3303dab5b1479e8a..239c9cd6c9a95b479981df24069f4cbd38ee3811 100644 (file)
@@ -270,8 +270,9 @@ void CodeRange::TearDown() {
 // -----------------------------------------------------------------------------
 // MemoryAllocator
 //
-intptr_t MemoryAllocator::capacity_   = 0;
-intptr_t MemoryAllocator::size_       = 0;
+intptr_t MemoryAllocator::capacity_ = 0;
+intptr_t MemoryAllocator::capacity_executable_ = 0;
+intptr_t MemoryAllocator::size_ = 0;
 intptr_t MemoryAllocator::size_executable_ = 0;
 
 List<MemoryAllocator::MemoryAllocationCallbackRegistration>
@@ -302,8 +303,10 @@ int MemoryAllocator::Pop() {
 }
 
 
-bool MemoryAllocator::Setup(intptr_t capacity) {
+bool MemoryAllocator::Setup(intptr_t capacity, intptr_t capacity_executable) {
   capacity_ = RoundUp(capacity, Page::kPageSize);
+  capacity_executable_ = RoundUp(capacity_executable, Page::kPageSize);
+  ASSERT_GE(capacity_, capacity_executable_);
 
   // Over-estimate the size of chunks_ array.  It assumes the expansion of old
   // space is always in the unit of a chunk (kChunkSize) except the last
@@ -346,6 +349,7 @@ void MemoryAllocator::TearDown() {
   ASSERT(top_ == max_nof_chunks_);  // all chunks are free
   top_ = 0;
   capacity_ = 0;
+  capacity_executable_ = 0;
   size_ = 0;
   max_nof_chunks_ = 0;
 }
@@ -357,16 +361,31 @@ void* MemoryAllocator::AllocateRawMemory(const size_t requested,
   if (size_ + static_cast<size_t>(requested) > static_cast<size_t>(capacity_)) {
     return NULL;
   }
+
   void* mem;
-  if (executable == EXECUTABLE  && CodeRange::exists()) {
-    mem = CodeRange::AllocateRawMemory(requested, allocated);
+  if (executable == EXECUTABLE) {
+    // Check executable memory limit.
+    if (size_executable_ + requested >
+        static_cast<size_t>(capacity_executable_)) {
+      LOG(StringEvent("MemoryAllocator::AllocateRawMemory",
+                      "V8 Executable Allocation capacity exceeded"));
+      return NULL;
+    }
+    // Allocate executable memory either from code range or from the
+    // OS.
+    if (CodeRange::exists()) {
+      mem = CodeRange::AllocateRawMemory(requested, allocated);
+    } else {
+      mem = OS::Allocate(requested, allocated, true);
+    }
+    // Update executable memory size.
+    size_executable_ += static_cast<int>(*allocated);
   } else {
-    mem = OS::Allocate(requested, allocated, (executable == EXECUTABLE));
+    mem = OS::Allocate(requested, allocated, false);
   }
   int alloced = static_cast<int>(*allocated);
   size_ += alloced;
 
-  if (executable == EXECUTABLE) size_executable_ += alloced;
 #ifdef DEBUG
   ZapBlock(reinterpret_cast<Address>(mem), alloced);
 #endif
@@ -391,6 +410,7 @@ void MemoryAllocator::FreeRawMemory(void* mem,
   if (executable == EXECUTABLE) size_executable_ -= static_cast<int>(length);
 
   ASSERT(size_ >= 0);
+  ASSERT(size_executable_ >= 0);
 }
 
 
@@ -1878,6 +1898,18 @@ MaybeObject* OldSpaceFreeList::Allocate(int size_in_bytes, int* wasted_bytes) {
 }
 
 
+void OldSpaceFreeList::MarkNodes() {
+  for (int i = 0; i < kFreeListsLength; i++) {
+    Address cur_addr = free_[i].head_node_;
+    while (cur_addr != NULL) {
+      FreeListNode* cur_node = FreeListNode::FromAddress(cur_addr);
+      cur_addr = cur_node->next();
+      cur_node->SetMark();
+    }
+  }
+}
+
+
 #ifdef DEBUG
 bool OldSpaceFreeList::Contains(FreeListNode* node) {
   for (int i = 0; i < kFreeListsLength; i++) {
@@ -1937,6 +1969,16 @@ MaybeObject* FixedSizeFreeList::Allocate() {
 }
 
 
+void FixedSizeFreeList::MarkNodes() {
+  Address cur_addr = head_;
+  while (cur_addr != NULL && cur_addr != tail_) {
+    FreeListNode* cur_node = FreeListNode::FromAddress(cur_addr);
+    cur_addr = cur_node->next();
+    cur_node->SetMark();
+  }
+}
+
+
 // -----------------------------------------------------------------------------
 // OldSpace implementation
 
@@ -2691,13 +2733,15 @@ LargeObjectSpace::LargeObjectSpace(AllocationSpace id)
     : Space(id, NOT_EXECUTABLE),  // Managed on a per-allocation basis
       first_chunk_(NULL),
       size_(0),
-      page_count_(0) {}
+      page_count_(0),
+      objects_size_(0) {}
 
 
 bool LargeObjectSpace::Setup() {
   first_chunk_ = NULL;
   size_ = 0;
   page_count_ = 0;
+  objects_size_ = 0;
   return true;
 }
 
@@ -2720,6 +2764,7 @@ void LargeObjectSpace::TearDown() {
 
   size_ = 0;
   page_count_ = 0;
+  objects_size_ = 0;
 }
 
 
@@ -2766,6 +2811,7 @@ MaybeObject* LargeObjectSpace::AllocateRawInternal(int requested_size,
   }
 
   size_ += static_cast<int>(chunk_size);
+  objects_size_ += requested_size;
   page_count_++;
   chunk->set_next(first_chunk_);
   chunk->set_size(chunk_size);
@@ -2928,6 +2974,7 @@ void LargeObjectSpace::FreeUnmarkedObjects() {
       // Free the chunk.
       MarkCompactCollector::ReportDeleteIfNeeded(object);
       size_ -= static_cast<int>(chunk_size);
+      objects_size_ -= object->Size();
       page_count_--;
       ObjectSpace space = kObjectSpaceLoSpace;
       if (executable == EXECUTABLE) space = kObjectSpaceCodeSpace;
@@ -3032,7 +3079,8 @@ void LargeObjectSpace::ReportStatistics() {
     CollectHistogramInfo(obj);
   }
 
-  PrintF("  number of objects %d\n", num_objects);
+  PrintF("  number of objects %d, "
+         "size of objects %" V8_PTR_PREFIX "d\n", num_objects, objects_size_);
   if (num_objects > 0) ReportHistogram(false);
 }
 
index 3ed2fe8b98a346798350c45a50d12754074487df..60068c3d9110387f933a54ffcdc056e116e5e233 100644 (file)
@@ -371,8 +371,13 @@ class Space : public Malloced {
   // Identity used in error reporting.
   AllocationSpace identity() { return id_; }
 
+  // Returns allocated size.
   virtual intptr_t Size() = 0;
 
+  // Returns size of objects. Can differ from the allocated size
+  // (e.g. see LargeObjectSpace).
+  virtual intptr_t SizeOfObjects() { return Size(); }
+
 #ifdef ENABLE_HEAP_PROTECTION
   // Protect/unprotect the space by marking it read-only/writable.
   virtual void Protect() = 0;
@@ -491,8 +496,8 @@ class CodeRange : public AllStatic {
 class MemoryAllocator : public AllStatic {
  public:
   // Initializes its internal bookkeeping structures.
-  // Max capacity of the total space.
-  static bool Setup(intptr_t max_capacity);
+  // Max capacity of the total space and executable memory limit.
+  static bool Setup(intptr_t max_capacity, intptr_t capacity_executable);
 
   // Deletes valid chunks.
   static void TearDown();
@@ -590,6 +595,12 @@ class MemoryAllocator : public AllStatic {
   // Returns allocated spaces in bytes.
   static intptr_t Size() { return size_; }
 
+  // Returns the maximum available executable bytes of heaps.
+  static intptr_t AvailableExecutable() {
+    if (capacity_executable_ < size_executable_) return 0;
+    return capacity_executable_ - size_executable_;
+  }
+
   // Returns allocated executable spaces in bytes.
   static intptr_t SizeExecutable() { return size_executable_; }
 
@@ -653,6 +664,8 @@ class MemoryAllocator : public AllStatic {
  private:
   // Maximum space size in bytes.
   static intptr_t capacity_;
+  // Maximum subset of capacity_ that can be executable
+  static intptr_t capacity_executable_;
 
   // Allocated space size in bytes.
   static intptr_t size_;
@@ -1707,6 +1720,8 @@ class OldSpaceFreeList BASE_EMBEDDED {
   // 'wasted_bytes'.  The size should be a non-zero multiple of the word size.
   MUST_USE_RESULT MaybeObject* Allocate(int size_in_bytes, int* wasted_bytes);
 
+  void MarkNodes();
+
  private:
   // The size range of blocks, in bytes. (Smaller allocations are allowed, but
   // will always result in waste.)
@@ -1805,6 +1820,8 @@ class FixedSizeFreeList BASE_EMBEDDED {
   // A failure is returned if no block is available.
   MUST_USE_RESULT MaybeObject* Allocate();
 
+  void MarkNodes();
+
  private:
   // Available bytes on the free list.
   intptr_t available_;
@@ -1876,6 +1893,8 @@ class OldSpace : public PagedSpace {
 
   virtual void PutRestOfCurrentPageOnFreeList(Page* current_page);
 
+  void MarkFreeListNodes() { free_list_.MarkNodes(); }
+
 #ifdef DEBUG
   // Reports statistics for the space
   void ReportStatistics();
@@ -1943,6 +1962,9 @@ class FixedSpace : public PagedSpace {
   virtual void DeallocateBlock(Address start,
                                int size_in_bytes,
                                bool add_to_freelist);
+
+  void MarkFreeListNodes() { free_list_.MarkNodes(); }
+
 #ifdef DEBUG
   // Reports statistic info of the space
   void ReportStatistics();
@@ -2183,6 +2205,10 @@ class LargeObjectSpace : public Space {
     return size_;
   }
 
+  virtual intptr_t SizeOfObjects() {
+    return objects_size_;
+  }
+
   int PageCount() {
     return page_count_;
   }
@@ -2234,7 +2260,7 @@ class LargeObjectSpace : public Space {
   LargeObjectChunk* first_chunk_;
   intptr_t size_;  // allocated bytes
   int page_count_;  // number of chunks
-
+  intptr_t objects_size_;  // size of objects
 
   // Shared implementation of AllocateRaw, AllocateRawCode and
   // AllocateRawFixedArray.
index d97f632b88dc32975830ecc2f50186199c1768ce..d82ce05237ef2def6e2050d9520098db50edeb54 100644 (file)
@@ -144,16 +144,6 @@ function StringLastIndexOf(searchString /* position */) {  // length == 1
 }
 
 
-function CloneDenseArray(array) {
-  if (array === null) return null;
-  var clone = new $Array(array.length);
-  for (var i = 0; i < array.length; i++) {
-    clone[i] = array[i];
-  }
-  return clone;
-}
-
-
 // ECMA-262 section 15.5.4.9
 //
 // This function is implementation specific.  For now, we do not
@@ -172,33 +162,12 @@ function StringMatch(regexp) {
   var subject = TO_STRING_INLINE(this);
   if (IS_REGEXP(regexp)) {
     if (!regexp.global) return regexp.exec(subject);
-
-    var cache = regExpCache;
-    var saveAnswer = false;
-
-    if (%_ObjectEquals(cache.type, 'match') &&
-        %_IsRegExpEquivalent(cache.regExp, regexp) &&
-        %_ObjectEquals(cache.subject, subject)) {
-      if (cache.answerSaved) {
-        return CloneDenseArray(cache.answer);
-      } else {
-        saveAnswer = true;
-      }
-    }
     %_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]);
     // lastMatchInfo is defined in regexp.js.
-    var result = %StringMatch(subject, regexp, lastMatchInfo);
-    cache.type = 'match';
-    cache.regExp = regexp;
-    cache.subject = subject;
-    if (saveAnswer) cache.answer = CloneDenseArray(result);
-    cache.answerSaved = saveAnswer;
-    return result;
+    return %StringMatch(subject, regexp, lastMatchInfo);
   }
   // Non-regexp argument.
   regexp = new $RegExp(regexp);
-  // Don't check regexp exec cache, since the regexp is new.
-  // TODO(lrn): Change this if we start caching regexps here.
   return RegExpExecNoTests(regexp, subject, 0);
 }
 
@@ -231,7 +200,6 @@ function StringReplace(search, replace) {
   if (IS_REGEXP(search)) {
     %_Log('regexp', 'regexp-replace,%0r,%1S', [search, subject]);
     if (IS_FUNCTION(replace)) {
-      regExpCache.type = 'none';
       if (search.global) {
         return StringReplaceGlobalRegExpWithFunction(subject, search, replace);
       } else {
@@ -273,24 +241,10 @@ function StringReplace(search, replace) {
 
 // Helper function for regular expressions in String.prototype.replace.
 function StringReplaceRegExp(subject, regexp, replace) {
-  var cache = regExpCache;
-  if (%_ObjectEquals(cache.type, 'replace') &&
-      %_IsRegExpEquivalent(cache.regExp, regexp) &&
-      %_ObjectEquals(cache.replaceString, replace) &&
-      %_ObjectEquals(cache.subject, subject)) {
-    return cache.answer;
-  }
-  replace = TO_STRING_INLINE(replace);
-  var answer = %StringReplaceRegExpWithString(subject,
-                                              regexp,
-                                              replace,
-                                              lastMatchInfo);
-  cache.subject = subject;
-  cache.regExp = regexp;
-  cache.replaceString = replace;
-  cache.answer = answer;
-  cache.type = 'replace';
-  return answer;
+  return %StringReplaceRegExpWithString(subject,
+                                        regexp,
+                                        TO_STRING_INLINE(replace),
+                                        lastMatchInfo);
 }
 
 
@@ -605,34 +559,12 @@ function StringSplit(separator, limit) {
     return result;
   }
 
-  var cache = regExpCache;
-  var saveAnswer = false;
-
-  if (%_ObjectEquals(cache.type, 'split') &&
-      %_IsRegExpEquivalent(cache.regExp, separator) &&
-      %_ObjectEquals(cache.subject, subject) &&
-      %_ObjectEquals(cache.splitLimit, limit)) {
-    if (cache.answerSaved) {
-      return CloneDenseArray(cache.answer);
-    } else {
-      saveAnswer = true;
-    }
-  }
-
-  cache.type = 'split';
-  cache.regExp = separator;
-  cache.subject = subject;
-  cache.splitLimit = limit;
-
   %_Log('regexp', 'regexp-split,%0S,%1r', [subject, separator]);
 
   if (length === 0) {
-    cache.answerSaved = true;
-    if (splitMatch(separator, subject, 0, 0) != null) {
-      cache.answer = [];
+    if (DoRegExpExec(separator, subject, 0, 0) != null) {
       return [];
     }
-    cache.answer = [subject];
     return [subject];
   }
 
@@ -680,8 +612,6 @@ function StringSplit(separator, limit) {
 
     startIndex = currentIndex = endIndex;
   }
-  if (saveAnswer) cache.answer = CloneDenseArray(result);
-  cache.answerSaved = saveAnswer;
   return result;
 }
 
index 0ed1b0d914791280dea19a54837ebc6673f164ec..cedbff91ea5fd7b5f0fe63f434c654513117befe 100644 (file)
@@ -31,6 +31,7 @@
 #include "v8.h"
 
 #include "strtod.h"
+#include "bignum.h"
 #include "cached-powers.h"
 #include "double.h"
 
@@ -83,44 +84,12 @@ static const double exact_powers_of_ten[] = {
   // 10^22 = 0x21e19e0c9bab2400000 = 0x878678326eac9 * 2^22
   10000000000000000000000.0
 };
-
 static const int kExactPowersOfTenSize = ARRAY_SIZE(exact_powers_of_ten);
 
-
-extern "C" double gay_strtod(const char* s00, const char** se);
-
-static double old_strtod(Vector<const char> buffer, int exponent) {
-  // gay_strtod is broken on Linux,x86. For numbers with few decimal digits
-  // the computation is done using floating-point operations which (on Linux)
-  // are prone to double-rounding errors.
-  // By adding several zeroes to the buffer gay_strtod falls back to a slower
-  // (but correct) algorithm.
-  const int kInsertedZeroesCount = 20;
-  char gay_buffer[1024];
-  Vector<char> gay_buffer_vector(gay_buffer, sizeof(gay_buffer));
-  int pos = 0;
-  for (int i = 0; i < buffer.length(); ++i) {
-    gay_buffer_vector[pos++] = buffer[i];
-  }
-  for (int i = 0; i < kInsertedZeroesCount; ++i) {
-    gay_buffer_vector[pos++] = '0';
-  }
-  exponent -= kInsertedZeroesCount;
-  gay_buffer_vector[pos++] = 'e';
-  if (exponent < 0) {
-    gay_buffer_vector[pos++] = '-';
-    exponent = -exponent;
-  }
-  const int kNumberOfExponentDigits = 5;
-  for (int i = kNumberOfExponentDigits - 1; i >= 0; i--) {
-    gay_buffer_vector[pos + i] = exponent % 10 + '0';
-    exponent /= 10;
-  }
-  pos += kNumberOfExponentDigits;
-  gay_buffer_vector[pos] = '\0';
-  return gay_strtod(gay_buffer, NULL);
-}
-
+// Maximum number of significant digits in the decimal representation.
+// In fact the value is 772 (see conversions.cc), but to give us some margin
+// we round up to 780.
+static const int kMaxSignificantDecimalDigits = 780;
 
 static Vector<const char> TrimLeadingZeros(Vector<const char> buffer) {
   for (int i = 0; i < buffer.length(); i++) {
@@ -142,6 +111,23 @@ static Vector<const char> TrimTrailingZeros(Vector<const char> buffer) {
 }
 
 
+static void TrimToMaxSignificantDigits(Vector<const char> buffer,
+                                       int exponent,
+                                       char* significant_buffer,
+                                       int* significant_exponent) {
+  for (int i = 0; i < kMaxSignificantDecimalDigits - 1; ++i) {
+    significant_buffer[i] = buffer[i];
+  }
+  // The input buffer has been trimmed. Therefore the last digit must be
+  // different from '0'.
+  ASSERT(buffer[buffer.length() - 1] != '0');
+  // Set the last digit to be non-zero. This is sufficient to guarantee
+  // correct rounding.
+  significant_buffer[kMaxSignificantDecimalDigits - 1] = '1';
+  *significant_exponent =
+      exponent + (buffer.length() - kMaxSignificantDecimalDigits);
+}
+
 // Reads digits from the buffer and converts them to a uint64.
 // Reads in as many digits as fit into a uint64.
 // When the string starts with "1844674407370955161" no further digit is read.
@@ -374,20 +360,81 @@ static bool DiyFpStrtod(Vector<const char> buffer,
 }
 
 
+// Returns the correct double for the buffer*10^exponent.
+// The variable guess should be a close guess that is either the correct double
+// or its lower neighbor (the nearest double less than the correct one).
+// Preconditions:
+//   buffer.length() + exponent <= kMaxDecimalPower + 1
+//   buffer.length() + exponent > kMinDecimalPower
+//   buffer.length() <= kMaxDecimalSignificantDigits
+static double BignumStrtod(Vector<const char> buffer,
+                           int exponent,
+                           double guess) {
+  if (guess == V8_INFINITY) {
+    return guess;
+  }
+
+  DiyFp upper_boundary = Double(guess).UpperBoundary();
+
+  ASSERT(buffer.length() + exponent <= kMaxDecimalPower + 1);
+  ASSERT(buffer.length() + exponent > kMinDecimalPower);
+  ASSERT(buffer.length() <= kMaxSignificantDecimalDigits);
+  // Make sure that the Bignum will be able to hold all our numbers.
+  // Our Bignum implementation has a separate field for exponents. Shifts will
+  // consume at most one bigit (< 64 bits).
+  // ln(10) == 3.3219...
+  ASSERT(((kMaxDecimalPower + 1) * 333 / 100) < Bignum::kMaxSignificantBits);
+  Bignum input;
+  Bignum boundary;
+  input.AssignDecimalString(buffer);
+  boundary.AssignUInt64(upper_boundary.f());
+  if (exponent >= 0) {
+    input.MultiplyByPowerOfTen(exponent);
+  } else {
+    boundary.MultiplyByPowerOfTen(-exponent);
+  }
+  if (upper_boundary.e() > 0) {
+    boundary.ShiftLeft(upper_boundary.e());
+  } else {
+    input.ShiftLeft(-upper_boundary.e());
+  }
+  int comparison = Bignum::Compare(input, boundary);
+  if (comparison < 0) {
+    return guess;
+  } else if (comparison > 0) {
+    return Double(guess).NextDouble();
+  } else if ((Double(guess).Significand() & 1) == 0) {
+    // Round towards even.
+    return guess;
+  } else {
+    return Double(guess).NextDouble();
+  }
+}
+
+
 double Strtod(Vector<const char> buffer, int exponent) {
   Vector<const char> left_trimmed = TrimLeadingZeros(buffer);
   Vector<const char> trimmed = TrimTrailingZeros(left_trimmed);
   exponent += left_trimmed.length() - trimmed.length();
   if (trimmed.length() == 0) return 0.0;
+  if (trimmed.length() > kMaxSignificantDecimalDigits) {
+    char significant_buffer[kMaxSignificantDecimalDigits];
+    int significant_exponent;
+    TrimToMaxSignificantDigits(trimmed, exponent,
+                               significant_buffer, &significant_exponent);
+    return Strtod(Vector<const char>(significant_buffer,
+                                     kMaxSignificantDecimalDigits),
+                  significant_exponent);
+  }
   if (exponent + trimmed.length() - 1 >= kMaxDecimalPower) return V8_INFINITY;
   if (exponent + trimmed.length() <= kMinDecimalPower) return 0.0;
 
-  double result;
-  if (DoubleStrtod(trimmed, exponent, &result) ||
-      DiyFpStrtod(trimmed, exponent, &result)) {
-    return result;
+  double guess;
+  if (DoubleStrtod(trimmed, exponent, &guess) ||
+      DiyFpStrtod(trimmed, exponent, &guess)) {
+    return guess;
   }
-  return old_strtod(trimmed, exponent);
+  return BignumStrtod(trimmed, exponent, guess);
 }
 
 } }  // namespace v8::internal
index e794f0932db56305e8fad0e44286bfccf22aac15..b7c769c7a25c1f3f96c4fd7ba01ae8b1d87eb897 100644 (file)
@@ -820,6 +820,34 @@ MaybeObject* StubCache::ComputeCallInitialize(int argc,
 }
 
 
+Handle<Code> StubCache::ComputeCallInitialize(int argc, InLoopFlag in_loop) {
+  if (in_loop == IN_LOOP) {
+    // Force the creation of the corresponding stub outside loops,
+    // because it may be used when clearing the ICs later - it is
+    // possible for a series of IC transitions to lose the in-loop
+    // information, and the IC clearing code can't generate a stub
+    // that it needs so we need to ensure it is generated already.
+    ComputeCallInitialize(argc, NOT_IN_LOOP);
+  }
+  CALL_HEAP_FUNCTION(ComputeCallInitialize(argc, in_loop, Code::CALL_IC), Code);
+}
+
+
+Handle<Code> StubCache::ComputeKeyedCallInitialize(int argc,
+                                                   InLoopFlag in_loop) {
+  if (in_loop == IN_LOOP) {
+    // Force the creation of the corresponding stub outside loops,
+    // because it may be used when clearing the ICs later - it is
+    // possible for a series of IC transitions to lose the in-loop
+    // information, and the IC clearing code can't generate a stub
+    // that it needs so we need to ensure it is generated already.
+    ComputeKeyedCallInitialize(argc, NOT_IN_LOOP);
+  }
+  CALL_HEAP_FUNCTION(
+      ComputeCallInitialize(argc, in_loop, Code::KEYED_CALL_IC), Code);
+}
+
+
 MaybeObject* StubCache::ComputeCallPreMonomorphic(int argc,
                                                   InLoopFlag in_loop,
                                                   Code::Kind kind) {
index 9d947e404b1a4425becaef526d2ec8259d28251c..4886c7eb29d2d74875932c338145443e7d1176e1 100644 (file)
@@ -204,6 +204,10 @@ class StubCache : public AllStatic {
                                                             InLoopFlag in_loop,
                                                             Code::Kind kind);
 
+  static Handle<Code> ComputeCallInitialize(int argc, InLoopFlag in_loop);
+
+  static Handle<Code> ComputeKeyedCallInitialize(int argc, InLoopFlag in_loop);
+
   MUST_USE_RESULT static MaybeObject* ComputeCallPreMonomorphic(
       int argc,
       InLoopFlag in_loop,
index ebc7fea1cd5170fa1cd4d870c09c66c089a43dfd..74d9539f4983b1c2a30b1d6d9436a5fb187a053d 100644 (file)
@@ -28,6 +28,8 @@
 #ifndef V8_TOKEN_H_
 #define V8_TOKEN_H_
 
+#include "checks.h"
+
 namespace v8 {
 namespace internal {
 
index 45a4cd60f8d830fc153c6876a6dd867975c6852f..7096ba35ab26ea37f9d758050a5ea904fb084440 100644 (file)
@@ -37,34 +37,6 @@ namespace v8 {
 namespace internal {
 
 
-// Implementation is from "Hacker's Delight" by Henry S. Warren, Jr.,
-// figure 3-3, page 48, where the function is called clp2.
-uint32_t RoundUpToPowerOf2(uint32_t x) {
-  ASSERT(x <= 0x80000000u);
-  x = x - 1;
-  x = x | (x >> 1);
-  x = x | (x >> 2);
-  x = x | (x >> 4);
-  x = x | (x >> 8);
-  x = x | (x >> 16);
-  return x + 1;
-}
-
-
-// Thomas Wang, Integer Hash Functions.
-// http://www.concentric.net/~Ttwang/tech/inthash.htm
-uint32_t ComputeIntegerHash(uint32_t key) {
-  uint32_t hash = key;
-  hash = ~hash + (hash << 15);  // hash = (hash << 15) - hash - 1;
-  hash = hash ^ (hash >> 12);
-  hash = hash + (hash << 2);
-  hash = hash ^ (hash >> 4);
-  hash = hash * 2057;  // hash = (hash + (hash << 3)) + (hash << 11);
-  hash = hash ^ (hash >> 16);
-  return hash;
-}
-
-
 void PrintF(const char* format, ...) {
   va_list arguments;
   va_start(arguments, format);
@@ -274,12 +246,4 @@ char* StringBuilder::Finalize() {
 }
 
 
-int TenToThe(int exponent) {
-  ASSERT(exponent <= 9);
-  ASSERT(exponent >= 1);
-  int answer = 10;
-  for (int i = 1; i < exponent; i++) answer *= 10;
-  return answer;
-}
-
 } }  // namespace v8::internal
index 0521767788550c7b842ab2c75ec68e79d662a96f..6270f8efaf0f754a1c839d326716ec0bf960e884 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
+#include "globals.h"
+#include "checks.h"
+#include "allocation.h"
+
 namespace v8 {
 namespace internal {
 
@@ -142,7 +146,19 @@ static int PointerValueCompare(const T* a, const T* b) {
 
 // Returns the smallest power of two which is >= x. If you pass in a
 // number that is already a power of two, it is returned as is.
-uint32_t RoundUpToPowerOf2(uint32_t x);
+// Implementation is from "Hacker's Delight" by Henry S. Warren, Jr.,
+// figure 3-3, page 48, where the function is called clp2.
+static inline uint32_t RoundUpToPowerOf2(uint32_t x) {
+  ASSERT(x <= 0x80000000u);
+  x = x - 1;
+  x = x | (x >> 1);
+  x = x | (x >> 2);
+  x = x | (x >> 4);
+  x = x | (x >> 8);
+  x = x | (x >> 16);
+  return x + 1;
+}
+
 
 
 template <typename T>
@@ -216,65 +232,18 @@ class BitField {
 // ----------------------------------------------------------------------------
 // Hash function.
 
-uint32_t ComputeIntegerHash(uint32_t key);
-
-
-// ----------------------------------------------------------------------------
-// I/O support.
-
-#if __GNUC__ >= 4
-// On gcc we can ask the compiler to check the types of %d-style format
-// specifiers and their associated arguments.  TODO(erikcorry) fix this
-// so it works on MacOSX.
-#if defined(__MACH__) && defined(__APPLE__)
-#define PRINTF_CHECKING
-#else  // MacOsX.
-#define PRINTF_CHECKING __attribute__ ((format (printf, 1, 2)))
-#endif
-#else
-#define PRINTF_CHECKING
-#endif
-
-// Our version of printf().
-void PRINTF_CHECKING PrintF(const char* format, ...);
-
-// Our version of fflush.
-void Flush();
-
-
-// Read a line of characters after printing the prompt to stdout. The resulting
-// char* needs to be disposed off with DeleteArray by the caller.
-char* ReadLine(const char* prompt);
-
-
-// Read and return the raw bytes in a file. the size of the buffer is returned
-// in size.
-// The returned buffer must be freed by the caller.
-byte* ReadBytes(const char* filename, int* size, bool verbose = true);
-
-
-// Write size chars from str to the file given by filename.
-// The file is overwritten. Returns the number of chars written.
-int WriteChars(const char* filename,
-               const char* str,
-               int size,
-               bool verbose = true);
-
-
-// Write size bytes to the file given by filename.
-// The file is overwritten. Returns the number of bytes written.
-int WriteBytes(const char* filename,
-               const byte* bytes,
-               int size,
-               bool verbose = true);
-
-
-// Write the C code
-// const char* <varname> = "<str>";
-// const int <varname>_len = <len>;
-// to the file given by filename. Only the first len chars are written.
-int WriteAsCFile(const char* filename, const char* varname,
-                 const char* str, int size, bool verbose = true);
+// Thomas Wang, Integer Hash Functions.
+// http://www.concentric.net/~Ttwang/tech/inthash.htm
+static inline uint32_t ComputeIntegerHash(uint32_t key) {
+  uint32_t hash = key;
+  hash = ~hash + (hash << 15);  // hash = (hash << 15) - hash - 1;
+  hash = hash ^ (hash >> 12);
+  hash = hash + (hash << 2);
+  hash = hash ^ (hash >> 4);
+  hash = hash * 2057;  // hash = (hash + (hash << 3)) + (hash << 11);
+  hash = hash ^ (hash >> 16);
+  return hash;
+}
 
 
 // ----------------------------------------------------------------------------
@@ -416,23 +385,6 @@ class Vector {
 };
 
 
-// A temporary assignment sets a (non-local) variable to a value on
-// construction and resets it the value on destruction.
-template <typename T>
-class TempAssign {
- public:
-  TempAssign(T* var, T value): var_(var), old_value_(*var) {
-    *var = value;
-  }
-
-  ~TempAssign() { *var_ = old_value_; }
-
- private:
-  T* var_;
-  T old_value_;
-};
-
-
 template <typename T, int kSize>
 class EmbeddedVector : public Vector<T> {
  public:
@@ -484,13 +436,6 @@ inline Vector<char> MutableCStrVector(char* data, int max) {
   return Vector<char>(data, (length < max) ? length : max);
 }
 
-template <typename T>
-inline Vector< Handle<Object> > HandleVector(v8::internal::Handle<T>* elms,
-                                             int length) {
-  return Vector< Handle<Object> >(
-      reinterpret_cast<v8::internal::Handle<Object>*>(elms), length);
-}
-
 
 /*
  * A class that collects values into a backing store.
@@ -699,156 +644,6 @@ class SequenceCollector : public Collector<T, growth_factor, max_growth> {
 };
 
 
-// Simple support to read a file into a 0-terminated C-string.
-// The returned buffer must be freed by the caller.
-// On return, *exits tells whether the file existed.
-Vector<const char> ReadFile(const char* filename,
-                            bool* exists,
-                            bool verbose = true);
-
-
-// Simple wrapper that allows an ExternalString to refer to a
-// Vector<const char>. Doesn't assume ownership of the data.
-class AsciiStringAdapter: public v8::String::ExternalAsciiStringResource {
- public:
-  explicit AsciiStringAdapter(Vector<const char> data) : data_(data) {}
-
-  virtual const char* data() const { return data_.start(); }
-
-  virtual size_t length() const { return data_.length(); }
-
- private:
-  Vector<const char> data_;
-};
-
-
-// Helper class for building result strings in a character buffer. The
-// purpose of the class is to use safe operations that checks the
-// buffer bounds on all operations in debug mode.
-class StringBuilder {
- public:
-  // Create a string builder with a buffer of the given size. The
-  // buffer is allocated through NewArray<char> and must be
-  // deallocated by the caller of Finalize().
-  explicit StringBuilder(int size);
-
-  StringBuilder(char* buffer, int size)
-      : buffer_(buffer, size), position_(0) { }
-
-  ~StringBuilder() { if (!is_finalized()) Finalize(); }
-
-  int size() const { return buffer_.length(); }
-
-  // Get the current position in the builder.
-  int position() const {
-    ASSERT(!is_finalized());
-    return position_;
-  }
-
-  // Reset the position.
-  void Reset() { position_ = 0; }
-
-  // Add a single character to the builder. It is not allowed to add
-  // 0-characters; use the Finalize() method to terminate the string
-  // instead.
-  void AddCharacter(char c) {
-    ASSERT(c != '\0');
-    ASSERT(!is_finalized() && position_ < buffer_.length());
-    buffer_[position_++] = c;
-  }
-
-  // Add an entire string to the builder. Uses strlen() internally to
-  // compute the length of the input string.
-  void AddString(const char* s);
-
-  // Add the first 'n' characters of the given string 's' to the
-  // builder. The input string must have enough characters.
-  void AddSubstring(const char* s, int n);
-
-  // Add formatted contents to the builder just like printf().
-  void AddFormatted(const char* format, ...);
-
-  // Add character padding to the builder. If count is non-positive,
-  // nothing is added to the builder.
-  void AddPadding(char c, int count);
-
-  // Finalize the string by 0-terminating it and returning the buffer.
-  char* Finalize();
-
- private:
-  Vector<char> buffer_;
-  int position_;
-
-  bool is_finalized() const { return position_ < 0; }
-
-  DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder);
-};
-
-
-// Custom memcpy implementation for platforms where the standard version
-// may not be good enough.
-// TODO(lrn): Check whether some IA32 platforms should be excluded.
-#if defined(V8_TARGET_ARCH_IA32)
-
-// TODO(lrn): Extend to other platforms as needed.
-
-typedef void (*MemCopyFunction)(void* dest, const void* src, size_t size);
-
-// Implemented in codegen-<arch>.cc.
-MemCopyFunction CreateMemCopyFunction();
-
-// Copy memory area to disjoint memory area.
-static inline void MemCopy(void* dest, const void* src, size_t size) {
-  static MemCopyFunction memcopy = CreateMemCopyFunction();
-  (*memcopy)(dest, src, size);
-#ifdef DEBUG
-  CHECK_EQ(0, memcmp(dest, src, size));
-#endif
-}
-
-
-// Limit below which the extra overhead of the MemCopy function is likely
-// to outweigh the benefits of faster copying.
-// TODO(lrn): Try to find a more precise value.
-static const int kMinComplexMemCopy = 64;
-
-#else  // V8_TARGET_ARCH_IA32
-
-static inline void MemCopy(void* dest, const void* src, size_t size) {
-  memcpy(dest, src, size);
-}
-
-static const int kMinComplexMemCopy = 256;
-
-#endif  // V8_TARGET_ARCH_IA32
-
-
-// Copy from ASCII/16bit chars to ASCII/16bit chars.
-template <typename sourcechar, typename sinkchar>
-static inline void CopyChars(sinkchar* dest, const sourcechar* src, int chars) {
-  sinkchar* limit = dest + chars;
-#ifdef V8_HOST_CAN_READ_UNALIGNED
-  if (sizeof(*dest) == sizeof(*src)) {
-    if (chars >= static_cast<int>(kMinComplexMemCopy / sizeof(*dest))) {
-      MemCopy(dest, src, chars * sizeof(*dest));
-      return;
-    }
-    // Number of characters in a uintptr_t.
-    static const int kStepSize = sizeof(uintptr_t) / sizeof(*dest);  // NOLINT
-    while (dest <= limit - kStepSize) {
-      *reinterpret_cast<uintptr_t*>(dest) =
-          *reinterpret_cast<const uintptr_t*>(src);
-      dest += kStepSize;
-      src += kStepSize;
-    }
-  }
-#endif
-  while (dest < limit) {
-    *dest++ = static_cast<sinkchar>(*src++);
-  }
-}
-
-
 // Compare ASCII/16bit chars to ASCII/16bit chars.
 template <typename lchar, typename rchar>
 static inline int CompareChars(const lchar* lhs, const rchar* rhs, int chars) {
@@ -877,54 +672,14 @@ static inline int CompareChars(const lchar* lhs, const rchar* rhs, int chars) {
 }
 
 
-template <typename T>
-static inline void MemsetPointer(T** dest, T* value, int counter) {
-#if defined(V8_HOST_ARCH_IA32)
-#define STOS "stosl"
-#elif defined(V8_HOST_ARCH_X64)
-#define STOS "stosq"
-#endif
-
-#if defined(__GNUC__) && defined(STOS)
-  asm volatile(
-      "cld;"
-      "rep ; " STOS
-      : "+&c" (counter), "+&D" (dest)
-      : "a" (value)
-      : "memory", "cc");
-#else
-  for (int i = 0; i < counter; i++) {
-    dest[i] = value;
-  }
-#endif
-
-#undef STOS
-}
-
-
-// Copies data from |src| to |dst|.  The data spans MUST not overlap.
-inline void CopyWords(Object** dst, Object** src, int num_words) {
-  ASSERT(Min(dst, src) + num_words <= Max(dst, src));
-  ASSERT(num_words > 0);
-
-  // Use block copying memcpy if the segment we're copying is
-  // enough to justify the extra call/setup overhead.
-  static const int kBlockCopyLimit = 16;
-
-  if (num_words >= kBlockCopyLimit) {
-    memcpy(dst, src, num_words * kPointerSize);
-  } else {
-    int remaining = num_words;
-    do {
-      remaining--;
-      *dst++ = *src++;
-    } while (remaining > 0);
-  }
-}
-
-
 // Calculate 10^exponent.
-int TenToThe(int exponent);
+static inline int TenToThe(int exponent) {
+  ASSERT(exponent <= 9);
+  ASSERT(exponent >= 1);
+  int answer = 10;
+  for (int i = 1; i < exponent; i++) answer *= 10;
+  return answer;
+}
 
 
 // The type-based aliasing rule allows the compiler to assume that pointers of
index 0623400abbd372665103fd027d049b111145f2cd..c8d719b1447e2b1a7275870726c644b423d6d782 100644 (file)
@@ -44,6 +44,7 @@ bool V8::has_been_setup_ = false;
 bool V8::has_been_disposed_ = false;
 bool V8::has_fatal_error_ = false;
 
+
 bool V8::Initialize(Deserializer* des) {
   bool create_heap_objects = des == NULL;
   if (has_been_disposed_ || has_fatal_error_) return false;
@@ -176,22 +177,41 @@ static uint32_t random_seed() {
 }
 
 
-uint32_t V8::Random() {
-  // Random number generator using George Marsaglia's MWC algorithm.
-  static uint32_t hi = 0;
-  static uint32_t lo = 0;
+typedef struct {
+  uint32_t hi;
+  uint32_t lo;
+} random_state;
+
 
+// Random number generator using George Marsaglia's MWC algorithm.
+static uint32_t random_base(random_state *state) {
   // Initialize seed using the system random(). If one of the seeds
   // should ever become zero again, or if random() returns zero, we
   // avoid getting stuck with zero bits in hi or lo by re-initializing
   // them on demand.
-  if (hi == 0) hi = random_seed();
-  if (lo == 0) lo = random_seed();
+  if (state->hi == 0) state->hi = random_seed();
+  if (state->lo == 0) state->lo = random_seed();
 
   // Mix the bits.
-  hi = 36969 * (hi & 0xFFFF) + (hi >> 16);
-  lo = 18273 * (lo & 0xFFFF) + (lo >> 16);
-  return (hi << 16) + (lo & 0xFFFF);
+  state->hi = 36969 * (state->hi & 0xFFFF) + (state->hi >> 16);
+  state->lo = 18273 * (state->lo & 0xFFFF) + (state->lo >> 16);
+  return (state->hi << 16) + (state->lo & 0xFFFF);
+}
+
+
+// Used by JavaScript APIs
+uint32_t V8::Random() {
+  static random_state state = {0, 0};
+  return random_base(&state);
+}
+
+
+// Used internally by the JIT and memory allocator for security
+// purposes. So, we keep a different state to prevent informations
+// leaks that could be used in an exploit.
+uint32_t V8::RandomPrivate() {
+  static random_state state = {0, 0};
+  return random_base(&state);
 }
 
 
index 9dbdf4c28a9ff51ce40ea5ebb1494611c6afdde5..74e98f151de09972fa0ca65216543eea6a5ed7e6 100644 (file)
 
 // Basic includes
 #include "../include/v8.h"
-#include "globals.h"
+#include "v8globals.h"
 #include "checks.h"
 #include "allocation.h"
-#include "utils.h"
+#include "v8utils.h"
 #include "flags.h"
 
 // Objects & heap
@@ -94,6 +94,11 @@ class V8 : public AllStatic {
 
   // Random number generation support. Not cryptographically safe.
   static uint32_t Random();
+  // We use random numbers internally in memory allocation and in the
+  // compilers for security. In order to prevent information leaks we
+  // use a separate random state for internal random number
+  // generation.
+  static uint32_t RandomPrivate();
   static Object* FillHeapNumberWithRandom(Object* heap_number);
 
   // Idle notification directly from the API.
diff --git a/deps/v8/src/v8globals.h b/deps/v8/src/v8globals.h
new file mode 100644 (file)
index 0000000..2815771
--- /dev/null
@@ -0,0 +1,464 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_V8GLOBALS_H_
+#define V8_V8GLOBALS_H_
+
+#include "globals.h"
+
+namespace v8 {
+namespace internal {
+
+// This file contains constants and global declarations related to the
+// V8 system.
+
+// Mask for the sign bit in a smi.
+const intptr_t kSmiSignMask = kIntptrSignBit;
+
+const int kObjectAlignmentBits = kPointerSizeLog2;
+const intptr_t kObjectAlignment = 1 << kObjectAlignmentBits;
+const intptr_t kObjectAlignmentMask = kObjectAlignment - 1;
+
+// Desired alignment for pointers.
+const intptr_t kPointerAlignment = (1 << kPointerSizeLog2);
+const intptr_t kPointerAlignmentMask = kPointerAlignment - 1;
+
+// Desired alignment for maps.
+#if V8_HOST_ARCH_64_BIT
+const intptr_t kMapAlignmentBits = kObjectAlignmentBits;
+#else
+const intptr_t kMapAlignmentBits = kObjectAlignmentBits + 3;
+#endif
+const intptr_t kMapAlignment = (1 << kMapAlignmentBits);
+const intptr_t kMapAlignmentMask = kMapAlignment - 1;
+
+// Desired alignment for generated code is 32 bytes (to improve cache line
+// utilization).
+const int kCodeAlignmentBits = 5;
+const intptr_t kCodeAlignment = 1 << kCodeAlignmentBits;
+const intptr_t kCodeAlignmentMask = kCodeAlignment - 1;
+
+// Tag information for Failure.
+const int kFailureTag = 3;
+const int kFailureTagSize = 2;
+const intptr_t kFailureTagMask = (1 << kFailureTagSize) - 1;
+
+
+// Zap-value: The value used for zapping dead objects.
+// Should be a recognizable hex value tagged as a heap object pointer.
+#ifdef V8_HOST_ARCH_64_BIT
+const Address kZapValue =
+    reinterpret_cast<Address>(V8_UINT64_C(0xdeadbeedbeadbeed));
+const Address kHandleZapValue =
+    reinterpret_cast<Address>(V8_UINT64_C(0x1baddead0baddead));
+const Address kFromSpaceZapValue =
+    reinterpret_cast<Address>(V8_UINT64_C(0x1beefdad0beefdad));
+const uint64_t kDebugZapValue = 0xbadbaddbbadbaddb;
+#else
+const Address kZapValue = reinterpret_cast<Address>(0xdeadbeed);
+const Address kHandleZapValue = reinterpret_cast<Address>(0xbaddead);
+const Address kFromSpaceZapValue = reinterpret_cast<Address>(0xbeefdad);
+const uint32_t kDebugZapValue = 0xbadbaddb;
+#endif
+
+
+// Number of bits to represent the page size for paged spaces. The value of 13
+// gives 8K bytes per page.
+const int kPageSizeBits = 13;
+
+// On Intel architecture, cache line size is 64 bytes.
+// On ARM it may be less (32 bytes), but as far this constant is
+// used for aligning data, it doesn't hurt to align on a greater value.
+const int kProcessorCacheLineSize = 64;
+
+// Constants relevant to double precision floating point numbers.
+
+// Quiet NaNs have bits 51 to 62 set, possibly the sign bit, and no
+// other bits set.
+const uint64_t kQuietNaNMask = static_cast<uint64_t>(0xfff) << 51;
+// If looking only at the top 32 bits, the QNaN mask is bits 19 to 30.
+const uint32_t kQuietNaNHighBitsMask = 0xfff << (51 - 32);
+
+
+// -----------------------------------------------------------------------------
+// Forward declarations for frequently used classes
+// (sorted alphabetically)
+
+class AccessorInfo;
+class Allocation;
+class Arguments;
+class Assembler;
+class AssertNoAllocation;
+class BreakableStatement;
+class Code;
+class CodeGenerator;
+class CodeStub;
+class Context;
+class Debug;
+class Debugger;
+class DebugInfo;
+class Descriptor;
+class DescriptorArray;
+class Expression;
+class ExternalReference;
+class FixedArray;
+class FunctionEntry;
+class FunctionLiteral;
+class FunctionTemplateInfo;
+class NumberDictionary;
+class StringDictionary;
+template <typename T> class Handle;
+class Heap;
+class HeapObject;
+class IC;
+class InterceptorInfo;
+class IterationStatement;
+class JSArray;
+class JSFunction;
+class JSObject;
+class LargeObjectSpace;
+class LookupResult;
+class MacroAssembler;
+class Map;
+class MapSpace;
+class MarkCompactCollector;
+class NewSpace;
+class NodeVisitor;
+class Object;
+class MaybeObject;
+class OldSpace;
+class Property;
+class Proxy;
+class RegExpNode;
+struct RegExpCompileData;
+class RegExpTree;
+class RegExpCompiler;
+class RegExpVisitor;
+class Scope;
+template<class Allocator = FreeStoreAllocationPolicy> class ScopeInfo;
+class SerializedScopeInfo;
+class Script;
+class Slot;
+class Smi;
+template <typename Config, class Allocator = FreeStoreAllocationPolicy>
+    class SplayTree;
+class Statement;
+class String;
+class Struct;
+class SwitchStatement;
+class AstVisitor;
+class Variable;
+class VariableProxy;
+class RelocInfo;
+class Deserializer;
+class MessageLocation;
+class ObjectGroup;
+class TickSample;
+class VirtualMemory;
+class Mutex;
+
+typedef bool (*WeakSlotCallback)(Object** pointer);
+
+// -----------------------------------------------------------------------------
+// Miscellaneous
+
+// NOTE: SpaceIterator depends on AllocationSpace enumeration values being
+// consecutive.
+enum AllocationSpace {
+  NEW_SPACE,            // Semispaces collected with copying collector.
+  OLD_POINTER_SPACE,    // May contain pointers to new space.
+  OLD_DATA_SPACE,       // Must not have pointers to new space.
+  CODE_SPACE,           // No pointers to new space, marked executable.
+  MAP_SPACE,            // Only and all map objects.
+  CELL_SPACE,           // Only and all cell objects.
+  LO_SPACE,             // Promoted large objects.
+
+  FIRST_SPACE = NEW_SPACE,
+  LAST_SPACE = LO_SPACE,
+  FIRST_PAGED_SPACE = OLD_POINTER_SPACE,
+  LAST_PAGED_SPACE = CELL_SPACE
+};
+const int kSpaceTagSize = 3;
+const int kSpaceTagMask = (1 << kSpaceTagSize) - 1;
+
+
+// A flag that indicates whether objects should be pretenured when
+// allocated (allocated directly into the old generation) or not
+// (allocated in the young generation if the object size and type
+// allows).
+enum PretenureFlag { NOT_TENURED, TENURED };
+
+enum GarbageCollector { SCAVENGER, MARK_COMPACTOR };
+
+enum Executability { NOT_EXECUTABLE, EXECUTABLE };
+
+enum VisitMode { VISIT_ALL, VISIT_ALL_IN_SCAVENGE, VISIT_ONLY_STRONG };
+
+// Flag indicating whether code is built into the VM (one of the natives files).
+enum NativesFlag { NOT_NATIVES_CODE, NATIVES_CODE };
+
+
+// A CodeDesc describes a buffer holding instructions and relocation
+// information. The instructions start at the beginning of the buffer
+// and grow forward, the relocation information starts at the end of
+// the buffer and grows backward.
+//
+//  |<--------------- buffer_size ---------------->|
+//  |<-- instr_size -->|        |<-- reloc_size -->|
+//  +==================+========+==================+
+//  |   instructions   |  free  |    reloc info    |
+//  +==================+========+==================+
+//  ^
+//  |
+//  buffer
+
+struct CodeDesc {
+  byte* buffer;
+  int buffer_size;
+  int instr_size;
+  int reloc_size;
+  Assembler* origin;
+};
+
+
+// Callback function on object slots, used for iterating heap object slots in
+// HeapObjects, global pointers to heap objects, etc. The callback allows the
+// callback function to change the value of the slot.
+typedef void (*ObjectSlotCallback)(HeapObject** pointer);
+
+
+// Callback function used for iterating objects in heap spaces,
+// for example, scanning heap objects.
+typedef int (*HeapObjectCallback)(HeapObject* obj);
+
+
+// Callback function used for checking constraints when copying/relocating
+// objects. Returns true if an object can be copied/relocated from its
+// old_addr to a new_addr.
+typedef bool (*ConstraintCallback)(Address new_addr, Address old_addr);
+
+
+// Callback function on inline caches, used for iterating over inline caches
+// in compiled code.
+typedef void (*InlineCacheCallback)(Code* code, Address ic);
+
+
+// State for inline cache call sites. Aliased as IC::State.
+enum InlineCacheState {
+  // Has never been executed.
+  UNINITIALIZED,
+  // Has been executed but monomorhic state has been delayed.
+  PREMONOMORPHIC,
+  // Has been executed and only one receiver type has been seen.
+  MONOMORPHIC,
+  // Like MONOMORPHIC but check failed due to prototype.
+  MONOMORPHIC_PROTOTYPE_FAILURE,
+  // Multiple receiver types have been seen.
+  MEGAMORPHIC,
+  // Special states for debug break or step in prepare stubs.
+  DEBUG_BREAK,
+  DEBUG_PREPARE_STEP_IN
+};
+
+
+enum InLoopFlag {
+  NOT_IN_LOOP,
+  IN_LOOP
+};
+
+
+enum CallFunctionFlags {
+  NO_CALL_FUNCTION_FLAGS = 0,
+  RECEIVER_MIGHT_BE_VALUE = 1 << 0  // Receiver might not be a JSObject.
+};
+
+
+enum InlineCacheHolderFlag {
+  OWN_MAP,  // For fast properties objects.
+  PROTOTYPE_MAP  // For slow properties objects (except GlobalObjects).
+};
+
+
+// Type of properties.
+// Order of properties is significant.
+// Must fit in the BitField PropertyDetails::TypeField.
+// A copy of this is in mirror-debugger.js.
+enum PropertyType {
+  NORMAL              = 0,  // only in slow mode
+  FIELD               = 1,  // only in fast mode
+  CONSTANT_FUNCTION   = 2,  // only in fast mode
+  CALLBACKS           = 3,
+  INTERCEPTOR         = 4,  // only in lookup results, not in descriptors.
+  MAP_TRANSITION      = 5,  // only in fast mode
+  CONSTANT_TRANSITION = 6,  // only in fast mode
+  NULL_DESCRIPTOR     = 7,  // only in fast mode
+  // All properties before MAP_TRANSITION are real.
+  FIRST_PHANTOM_PROPERTY_TYPE = MAP_TRANSITION,
+  // There are no IC stubs for NULL_DESCRIPTORS. Therefore,
+  // NULL_DESCRIPTOR can be used as the type flag for IC stubs for
+  // nonexistent properties.
+  NONEXISTENT = NULL_DESCRIPTOR
+};
+
+
+// Whether to remove map transitions and constant transitions from a
+// DescriptorArray.
+enum TransitionFlag {
+  REMOVE_TRANSITIONS,
+  KEEP_TRANSITIONS
+};
+
+
+// Union used for fast testing of specific double values.
+union DoubleRepresentation {
+  double  value;
+  int64_t bits;
+  DoubleRepresentation(double x) { value = x; }
+};
+
+
+// Union used for customized checking of the IEEE double types
+// inlined within v8 runtime, rather than going to the underlying
+// platform headers and libraries
+union IeeeDoubleLittleEndianArchType {
+  double d;
+  struct {
+    unsigned int man_low  :32;
+    unsigned int man_high :20;
+    unsigned int exp      :11;
+    unsigned int sign     :1;
+  } bits;
+};
+
+
+union IeeeDoubleBigEndianArchType {
+  double d;
+  struct {
+    unsigned int sign     :1;
+    unsigned int exp      :11;
+    unsigned int man_high :20;
+    unsigned int man_low  :32;
+  } bits;
+};
+
+
+// AccessorCallback
+struct AccessorDescriptor {
+  MaybeObject* (*getter)(Object* object, void* data);
+  MaybeObject* (*setter)(JSObject* object, Object* value, void* data);
+  void* data;
+};
+
+
+// Logging and profiling.
+// A StateTag represents a possible state of the VM.  When compiled with
+// ENABLE_VMSTATE_TRACKING, the logger maintains a stack of these.
+// Creating a VMState object enters a state by pushing on the stack, and
+// destroying a VMState object leaves a state by popping the current state
+// from the stack.
+
+#define STATE_TAG_LIST(V) \
+  V(JS)                   \
+  V(GC)                   \
+  V(COMPILER)             \
+  V(OTHER)                \
+  V(EXTERNAL)
+
+enum StateTag {
+#define DEF_STATE_TAG(name) name,
+  STATE_TAG_LIST(DEF_STATE_TAG)
+#undef DEF_STATE_TAG
+  // Pseudo-types.
+  state_tag_count
+};
+
+
+// -----------------------------------------------------------------------------
+// Macros
+
+// Testers for test.
+
+#define HAS_SMI_TAG(value) \
+  ((reinterpret_cast<intptr_t>(value) & kSmiTagMask) == kSmiTag)
+
+#define HAS_FAILURE_TAG(value) \
+  ((reinterpret_cast<intptr_t>(value) & kFailureTagMask) == kFailureTag)
+
+// OBJECT_POINTER_ALIGN returns the value aligned as a HeapObject pointer
+#define OBJECT_POINTER_ALIGN(value)                             \
+  (((value) + kObjectAlignmentMask) & ~kObjectAlignmentMask)
+
+// POINTER_SIZE_ALIGN returns the value aligned as a pointer.
+#define POINTER_SIZE_ALIGN(value)                               \
+  (((value) + kPointerAlignmentMask) & ~kPointerAlignmentMask)
+
+// MAP_POINTER_ALIGN returns the value aligned as a map pointer.
+#define MAP_POINTER_ALIGN(value)                                \
+  (((value) + kMapAlignmentMask) & ~kMapAlignmentMask)
+
+// CODE_POINTER_ALIGN returns the value aligned as a generated code segment.
+#define CODE_POINTER_ALIGN(value)                               \
+  (((value) + kCodeAlignmentMask) & ~kCodeAlignmentMask)
+
+// Support for tracking C++ memory allocation.  Insert TRACK_MEMORY("Fisk")
+// inside a C++ class and new and delete will be overloaded so logging is
+// performed.
+// This file (globals.h) is included before log.h, so we use direct calls to
+// the Logger rather than the LOG macro.
+#ifdef DEBUG
+#define TRACK_MEMORY(name) \
+  void* operator new(size_t size) { \
+    void* result = ::operator new(size); \
+    Logger::NewEvent(name, result, size); \
+    return result; \
+  } \
+  void operator delete(void* object) { \
+    Logger::DeleteEvent(name, object); \
+    ::operator delete(object); \
+  }
+#else
+#define TRACK_MEMORY(name)
+#endif
+
+
+// Feature flags bit positions. They are mostly based on the CPUID spec.
+// (We assign CPUID itself to one of the currently reserved bits --
+// feel free to change this if needed.)
+// On X86/X64, values below 32 are bits in EDX, values above 32 are bits in ECX.
+enum CpuFeature { SSE4_1 = 32 + 19,  // x86
+                  SSE3 = 32 + 0,     // x86
+                  SSE2 = 26,   // x86
+                  CMOV = 15,   // x86
+                  RDTSC = 4,   // x86
+                  CPUID = 10,  // x86
+                  VFP3 = 1,    // ARM
+                  ARMv7 = 2,   // ARM
+                  SAHF = 0};   // x86
+
+} }  // namespace v8::internal
+
+#endif  // V8_V8GLOBALS_H_
diff --git a/deps/v8/src/v8utils.h b/deps/v8/src/v8utils.h
new file mode 100644 (file)
index 0000000..a907c9f
--- /dev/null
@@ -0,0 +1,301 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_V8UTILS_H_
+#define V8_V8UTILS_H_
+
+#include "utils.h"
+
+namespace v8 {
+namespace internal {
+
+// ----------------------------------------------------------------------------
+// I/O support.
+
+#if __GNUC__ >= 4
+// On gcc we can ask the compiler to check the types of %d-style format
+// specifiers and their associated arguments.  TODO(erikcorry) fix this
+// so it works on MacOSX.
+#if defined(__MACH__) && defined(__APPLE__)
+#define PRINTF_CHECKING
+#else  // MacOsX.
+#define PRINTF_CHECKING __attribute__ ((format (printf, 1, 2)))
+#endif
+#else
+#define PRINTF_CHECKING
+#endif
+
+// Our version of printf().
+void PRINTF_CHECKING PrintF(const char* format, ...);
+
+// Our version of fflush.
+void Flush();
+
+
+// Read a line of characters after printing the prompt to stdout. The resulting
+// char* needs to be disposed off with DeleteArray by the caller.
+char* ReadLine(const char* prompt);
+
+
+// Read and return the raw bytes in a file. the size of the buffer is returned
+// in size.
+// The returned buffer must be freed by the caller.
+byte* ReadBytes(const char* filename, int* size, bool verbose = true);
+
+
+// Write size chars from str to the file given by filename.
+// The file is overwritten. Returns the number of chars written.
+int WriteChars(const char* filename,
+               const char* str,
+               int size,
+               bool verbose = true);
+
+
+// Write size bytes to the file given by filename.
+// The file is overwritten. Returns the number of bytes written.
+int WriteBytes(const char* filename,
+               const byte* bytes,
+               int size,
+               bool verbose = true);
+
+
+// Write the C code
+// const char* <varname> = "<str>";
+// const int <varname>_len = <len>;
+// to the file given by filename. Only the first len chars are written.
+int WriteAsCFile(const char* filename, const char* varname,
+                 const char* str, int size, bool verbose = true);
+
+
+// Data structures
+
+template <typename T>
+inline Vector< Handle<Object> > HandleVector(v8::internal::Handle<T>* elms,
+                                             int length) {
+  return Vector< Handle<Object> >(
+      reinterpret_cast<v8::internal::Handle<Object>*>(elms), length);
+}
+
+// Memory
+
+// Copies data from |src| to |dst|.  The data spans MUST not overlap.
+inline void CopyWords(Object** dst, Object** src, int num_words) {
+  ASSERT(Min(dst, src) + num_words <= Max(dst, src));
+  ASSERT(num_words > 0);
+
+  // Use block copying memcpy if the segment we're copying is
+  // enough to justify the extra call/setup overhead.
+  static const int kBlockCopyLimit = 16;
+
+  if (num_words >= kBlockCopyLimit) {
+    memcpy(dst, src, num_words * kPointerSize);
+  } else {
+    int remaining = num_words;
+    do {
+      remaining--;
+      *dst++ = *src++;
+    } while (remaining > 0);
+  }
+}
+
+
+template <typename T>
+static inline void MemsetPointer(T** dest, T* value, int counter) {
+#if defined(V8_HOST_ARCH_IA32)
+#define STOS "stosl"
+#elif defined(V8_HOST_ARCH_X64)
+#define STOS "stosq"
+#endif
+
+#if defined(__GNUC__) && defined(STOS)
+  asm volatile(
+      "cld;"
+      "rep ; " STOS
+      : "+&c" (counter), "+&D" (dest)
+      : "a" (value)
+      : "memory", "cc");
+#else
+  for (int i = 0; i < counter; i++) {
+    dest[i] = value;
+  }
+#endif
+
+#undef STOS
+}
+
+
+// Simple wrapper that allows an ExternalString to refer to a
+// Vector<const char>. Doesn't assume ownership of the data.
+class AsciiStringAdapter: public v8::String::ExternalAsciiStringResource {
+ public:
+  explicit AsciiStringAdapter(Vector<const char> data) : data_(data) {}
+
+  virtual const char* data() const { return data_.start(); }
+
+  virtual size_t length() const { return data_.length(); }
+
+ private:
+  Vector<const char> data_;
+};
+
+
+// Simple support to read a file into a 0-terminated C-string.
+// The returned buffer must be freed by the caller.
+// On return, *exits tells whether the file existed.
+Vector<const char> ReadFile(const char* filename,
+                            bool* exists,
+                            bool verbose = true);
+
+
+// Helper class for building result strings in a character buffer. The
+// purpose of the class is to use safe operations that checks the
+// buffer bounds on all operations in debug mode.
+class StringBuilder {
+ public:
+  // Create a string builder with a buffer of the given size. The
+  // buffer is allocated through NewArray<char> and must be
+  // deallocated by the caller of Finalize().
+  explicit StringBuilder(int size);
+
+  StringBuilder(char* buffer, int size)
+      : buffer_(buffer, size), position_(0) { }
+
+  ~StringBuilder() { if (!is_finalized()) Finalize(); }
+
+  int size() const { return buffer_.length(); }
+
+  // Get the current position in the builder.
+  int position() const {
+    ASSERT(!is_finalized());
+    return position_;
+  }
+
+  // Reset the position.
+  void Reset() { position_ = 0; }
+
+  // Add a single character to the builder. It is not allowed to add
+  // 0-characters; use the Finalize() method to terminate the string
+  // instead.
+  void AddCharacter(char c) {
+    ASSERT(c != '\0');
+    ASSERT(!is_finalized() && position_ < buffer_.length());
+    buffer_[position_++] = c;
+  }
+
+  // Add an entire string to the builder. Uses strlen() internally to
+  // compute the length of the input string.
+  void AddString(const char* s);
+
+  // Add the first 'n' characters of the given string 's' to the
+  // builder. The input string must have enough characters.
+  void AddSubstring(const char* s, int n);
+
+  // Add formatted contents to the builder just like printf().
+  void AddFormatted(const char* format, ...);
+
+  // Add character padding to the builder. If count is non-positive,
+  // nothing is added to the builder.
+  void AddPadding(char c, int count);
+
+  // Finalize the string by 0-terminating it and returning the buffer.
+  char* Finalize();
+
+ private:
+  Vector<char> buffer_;
+  int position_;
+
+  bool is_finalized() const { return position_ < 0; }
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder);
+};
+
+
+// Custom memcpy implementation for platforms where the standard version
+// may not be good enough.
+#if defined(V8_TARGET_ARCH_IA32)
+
+// The default memcpy on ia32 architectures is generally not as efficient
+// as possible. (If any further ia32 platforms are introduced where the
+// memcpy function is efficient, exclude them from this branch).
+
+typedef void (*MemCopyFunction)(void* dest, const void* src, size_t size);
+
+// Implemented in codegen-<arch>.cc.
+MemCopyFunction CreateMemCopyFunction();
+
+// Copy memory area to disjoint memory area.
+static inline void MemCopy(void* dest, const void* src, size_t size) {
+  static MemCopyFunction memcopy = CreateMemCopyFunction();
+  (*memcopy)(dest, src, size);
+#ifdef DEBUG
+  CHECK_EQ(0, memcmp(dest, src, size));
+#endif
+}
+
+// Limit below which the extra overhead of the MemCopy function is likely
+// to outweigh the benefits of faster copying.
+static const int kMinComplexMemCopy = 64;
+
+#else  // V8_TARGET_ARCH_IA32
+
+static inline void MemCopy(void* dest, const void* src, size_t size) {
+  memcpy(dest, src, size);
+}
+
+static const int kMinComplexMemCopy = 256;
+
+#endif  // V8_TARGET_ARCH_IA32
+
+
+// Copy from ASCII/16bit chars to ASCII/16bit chars.
+template <typename sourcechar, typename sinkchar>
+static inline void CopyChars(sinkchar* dest, const sourcechar* src, int chars) {
+  sinkchar* limit = dest + chars;
+#ifdef V8_HOST_CAN_READ_UNALIGNED
+  if (sizeof(*dest) == sizeof(*src)) {
+    if (chars >= static_cast<int>(kMinComplexMemCopy / sizeof(*dest))) {
+      MemCopy(dest, src, chars * sizeof(*dest));
+      return;
+    }
+    // Number of characters in a uintptr_t.
+    static const int kStepSize = sizeof(uintptr_t) / sizeof(*dest);  // NOLINT
+    while (dest <= limit - kStepSize) {
+      *reinterpret_cast<uintptr_t*>(dest) =
+          *reinterpret_cast<const uintptr_t*>(src);
+      dest += kStepSize;
+      src += kStepSize;
+    }
+  }
+#endif
+  while (dest < limit) {
+    *dest++ = static_cast<sinkchar>(*src++);
+  }
+}
+
+} }  // namespace v8::internal
+
+#endif  // V8_V8UTILS_H_
index e27b9153fcce167bc164eeeaa240115fce6028ff..ae3250fb872378d3a781321d492fb1f56c48cd3a 100644 (file)
@@ -34,7 +34,7 @@
 // cannot be changed without changing the SCons build script.
 #define MAJOR_VERSION     2
 #define MINOR_VERSION     5
-#define BUILD_NUMBER      3
+#define BUILD_NUMBER      7
 #define PATCH_LEVEL       0
 #define CANDIDATE_VERSION false
 
index 220823ed4b1ea71fdb7d8b7e8d3e2be6b96dcfc3..65d1009899a564d92a4689edb94188d52e26aa9a 100644 (file)
@@ -31,6 +31,9 @@
 #include "frame-element.h"
 #include "macro-assembler.h"
 
+#include "list-inl.h"
+#include "utils.h"
+
 #if V8_TARGET_ARCH_IA32
 #include "ia32/virtual-frame-ia32.h"
 #elif V8_TARGET_ARCH_X64
 #error Unsupported target architecture.
 #endif
 
+namespace v8 {
+namespace internal {
+
+// Add() on List is inlined, ResizeAdd() called by Add() is inlined except for
+// Lists of FrameElements, and ResizeAddInternal() is inlined in ResizeAdd().
+template <>
+void List<FrameElement,
+          FreeStoreAllocationPolicy>::ResizeAdd(const FrameElement& element);
+} }  // namespace v8::internal
+
 #endif  // V8_VIRTUAL_FRAME_H_
index bf5ee5bbb77aeb3b89e506b615d9e014057c131c..caed7c8aa9bca113cab900354aeca1c4b691fb28 100644 (file)
@@ -296,7 +296,7 @@ static void InitCoverageLog();
 byte* Assembler::spare_buffer_ = NULL;
 
 Assembler::Assembler(void* buffer, int buffer_size)
-    : code_targets_(100) {
+    : code_targets_(100), positions_recorder_(this) {
   if (buffer == NULL) {
     // Do our own buffer management.
     if (buffer_size <= kMinimalBufferSize) {
@@ -337,10 +337,7 @@ Assembler::Assembler(void* buffer, int buffer_size)
   reloc_info_writer.Reposition(buffer_ + buffer_size, pc_);
 
   last_pc_ = NULL;
-  current_statement_position_ = RelocInfo::kNoPosition;
-  current_position_ = RelocInfo::kNoPosition;
-  written_statement_position_ = current_statement_position_;
-  written_position_ = current_position_;
+
 #ifdef GENERATED_CODE_COVERAGE
   InitCoverageLog();
 #endif
@@ -845,7 +842,7 @@ void Assembler::call(Label* L) {
 
 
 void Assembler::call(Handle<Code> target, RelocInfo::Mode rmode) {
-  WriteRecordedPositions();
+  positions_recorder()->WriteRecordedPositions();
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
   // 1110 1000 #32-bit disp.
@@ -2935,14 +2932,14 @@ void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
 }
 
 void Assembler::RecordJSReturn() {
-  WriteRecordedPositions();
+  positions_recorder()->WriteRecordedPositions();
   EnsureSpace ensure_space(this);
   RecordRelocInfo(RelocInfo::JS_RETURN);
 }
 
 
 void Assembler::RecordDebugBreakSlot() {
-  WriteRecordedPositions();
+  positions_recorder()->WriteRecordedPositions();
   EnsureSpace ensure_space(this);
   RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
 }
@@ -2956,47 +2953,6 @@ void Assembler::RecordComment(const char* msg) {
 }
 
 
-void Assembler::RecordPosition(int pos) {
-  ASSERT(pos != RelocInfo::kNoPosition);
-  ASSERT(pos >= 0);
-  current_position_ = pos;
-}
-
-
-void Assembler::RecordStatementPosition(int pos) {
-  ASSERT(pos != RelocInfo::kNoPosition);
-  ASSERT(pos >= 0);
-  current_statement_position_ = pos;
-}
-
-
-bool Assembler::WriteRecordedPositions() {
-  bool written = false;
-
-  // Write the statement position if it is different from what was written last
-  // time.
-  if (current_statement_position_ != written_statement_position_) {
-    EnsureSpace ensure_space(this);
-    RecordRelocInfo(RelocInfo::STATEMENT_POSITION, current_statement_position_);
-    written_statement_position_ = current_statement_position_;
-    written = true;
-  }
-
-  // Write the position if it is different from what was written last time and
-  // also different from the written statement position.
-  if (current_position_ != written_position_ &&
-      current_position_ != written_statement_position_) {
-    EnsureSpace ensure_space(this);
-    RecordRelocInfo(RelocInfo::POSITION, current_position_);
-    written_position_ = current_position_;
-    written = true;
-  }
-
-  // Return whether something was written.
-  return written;
-}
-
-
 const int RelocInfo::kApplyMask = RelocInfo::kCodeTargetMask |
                                   1 << RelocInfo::INTERNAL_REFERENCE;
 
index bbc101062760f84eac4b1e2d6fa4a08a8dd858ec..c7f763222e6f2f53b7d17149808753b0311565ad 100644 (file)
@@ -1174,13 +1174,9 @@ class Assembler : public Malloced {
   // Use --debug_code to enable.
   void RecordComment(const char* msg);
 
-  void RecordPosition(int pos);
-  void RecordStatementPosition(int pos);
-  bool WriteRecordedPositions();
-
   int pc_offset() const { return static_cast<int>(pc_ - buffer_); }
-  int current_statement_position() const { return current_statement_position_; }
-  int current_position() const { return current_position_; }
+
+  PositionsRecorder* positions_recorder() { return &positions_recorder_; }
 
   // Check if there is less than kGap bytes available in the buffer.
   // If this is the case, we need to grow the buffer before emitting
@@ -1404,11 +1400,8 @@ class Assembler : public Malloced {
   // push-pop elimination
   byte* last_pc_;
 
-  // source position information
-  int current_statement_position_;
-  int current_position_;
-  int written_statement_position_;
-  int written_position_;
+  PositionsRecorder positions_recorder_;
+  friend class PositionsRecorder;
 };
 
 
index c179769b8a5dab67cbce9159379f5d2d5b4fc2dd..04173e1afb34a39a9ee275a4d7668e380b3ee745 100644 (file)
@@ -2483,20 +2483,6 @@ void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
 }
 
 
-void ApiGetterEntryStub::Generate(MacroAssembler* masm) {
-  __ PrepareCallApiFunction(kStackSpace);
-#ifdef _WIN64
-  // All the parameters should be set up by a caller.
-#else
-  // Set 1st parameter register with property name.
-  __ movq(rsi, rdx);
-  // Second parameter register rdi should be set with pointer to AccessorInfo
-  // by a caller.
-#endif
-  __ CallApiFunctionAndReturn(fun());
-}
-
-
 void CEntryStub::GenerateCore(MacroAssembler* masm,
                               Label* throw_normal_exception,
                               Label* throw_termination_exception,
@@ -2549,18 +2535,18 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
 #ifdef _WIN64
   // Windows 64-bit ABI passes arguments in rcx, rdx, r8, r9
   // Store Arguments object on stack, below the 4 WIN64 ABI parameter slots.
-  __ movq(Operand(rsp, 4 * kPointerSize), r14);  // argc.
-  __ movq(Operand(rsp, 5 * kPointerSize), r12);  // argv.
+  __ movq(StackSpaceOperand(0), r14);  // argc.
+  __ movq(StackSpaceOperand(1), r12);  // argv.
   if (result_size_ < 2) {
     // Pass a pointer to the Arguments object as the first argument.
     // Return result in single register (rax).
-    __ lea(rcx, Operand(rsp, 4 * kPointerSize));
+    __ lea(rcx, StackSpaceOperand(0));
   } else {
     ASSERT_EQ(2, result_size_);
     // Pass a pointer to the result location as the first argument.
-    __ lea(rcx, Operand(rsp, 6 * kPointerSize));
+    __ lea(rcx, StackSpaceOperand(2));
     // Pass a pointer to the Arguments object as the second argument.
-    __ lea(rdx, Operand(rsp, 4 * kPointerSize));
+    __ lea(rdx, StackSpaceOperand(0));
   }
 
 #else  // _WIN64
@@ -2596,7 +2582,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
   __ j(zero, &failure_returned);
 
   // Exit the JavaScript to C++ exit frame.
-  __ LeaveExitFrame(result_size_);
+  __ LeaveExitFrame();
   __ ret(0);
 
   // Handling of failure.
@@ -2700,7 +2686,12 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   // builtin once.
 
   // Enter the exit frame that transitions from JavaScript to C++.
-  __ EnterExitFrame(result_size_);
+#ifdef _WIN64
+  int arg_stack_space = (result_size_ < 2 ? 2 : 4);
+#else
+  int arg_stack_space = 0;
+#endif
+  __ EnterExitFrame(arg_stack_space);
 
   // rax: Holds the context at this point, but should not be used.
   //      On entry to code generated by GenerateCore, it must hold
index 0faf775d51cb2fadc5b50df30557c42854d4e2f9..6e98a00900f53c4dd70ca71a9122d4b23941847b 100644 (file)
@@ -568,10 +568,10 @@ void CodeGenerator::Load(Expression* expr) {
 
 void CodeGenerator::LoadGlobal() {
   if (in_spilled_code()) {
-    frame_->EmitPush(GlobalObject());
+    frame_->EmitPush(GlobalObjectOperand());
   } else {
     Result temp = allocator_->Allocate();
-    __ movq(temp.reg(), GlobalObject());
+    __ movq(temp.reg(), GlobalObjectOperand());
     frame_->Push(&temp);
   }
 }
@@ -580,7 +580,7 @@ void CodeGenerator::LoadGlobal() {
 void CodeGenerator::LoadGlobalReceiver() {
   Result temp = allocator_->Allocate();
   Register reg = temp.reg();
-  __ movq(reg, GlobalObject());
+  __ movq(reg, GlobalObjectOperand());
   __ movq(reg, FieldOperand(reg, GlobalObject::kGlobalReceiverOffset));
   frame_->Push(&temp);
 }
@@ -2956,7 +2956,7 @@ void CodeGenerator::VisitReturnStatement(ReturnStatement* node) {
   CodeForStatementPosition(node);
   Load(node->expression());
   Result return_value = frame_->Pop();
-  masm()->WriteRecordedPositions();
+  masm()->positions_recorder()->WriteRecordedPositions();
   if (function_return_is_shadowed_) {
     function_return_.Jump(&return_value);
   } else {
@@ -5592,6 +5592,18 @@ void CodeGenerator::VisitCall(Call* node) {
         // Push the receiver onto the frame.
         Load(property->obj());
 
+        // Load the name of the function.
+        Load(property->key());
+
+        // Swap the name of the function and the receiver on the stack to follow
+        // the calling convention for call ICs.
+        Result key = frame_->Pop();
+        Result receiver = frame_->Pop();
+        frame_->Push(&key);
+        frame_->Push(&receiver);
+        key.Unuse();
+        receiver.Unuse();
+
         // Load the arguments.
         int arg_count = args->length();
         for (int i = 0; i < arg_count; i++) {
@@ -5599,14 +5611,13 @@ void CodeGenerator::VisitCall(Call* node) {
           frame_->SpillTop();
         }
 
-        // Load the name of the function.
-        Load(property->key());
-
-        // Call the IC initialization code.
+        // Place the key on top of stack and call the IC initialization code.
+        frame_->PushElementAt(arg_count + 1);
         CodeForSourcePosition(node->position());
         Result result = frame_->CallKeyedCallIC(RelocInfo::CODE_TARGET,
                                                 arg_count,
                                                 loop_nesting());
+        frame_->Drop();  // Drop the key still on the stack.
         frame_->RestoreContextRegister();
         frame_->Push(&result);
       }
@@ -6062,7 +6073,7 @@ class DeferredIsStringWrapperSafeForDefaultValueOf : public DeferredCode {
     __ movq(scratch2_,
             FieldOperand(scratch2_, GlobalObject::kGlobalContextOffset));
     __ cmpq(scratch1_,
-            CodeGenerator::ContextOperand(
+            ContextOperand(
                 scratch2_, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
     __ j(not_equal, &false_result);
     // Set the bit in the map to indicate that it has been checked safe for
@@ -6564,86 +6575,6 @@ void CodeGenerator::GenerateRegExpConstructResult(ZoneList<Expression*>* args) {
 }
 
 
-void CodeGenerator::GenerateRegExpCloneResult(ZoneList<Expression*>* args) {
-  ASSERT_EQ(1, args->length());
-
-  Load(args->at(0));
-  Result object_result = frame_->Pop();
-  object_result.ToRegister(rax);
-  object_result.Unuse();
-  {
-    VirtualFrame::SpilledScope spilled_scope;
-
-    Label done;
-    __ JumpIfSmi(rax, &done);
-
-    // Load JSRegExpResult map into rdx.
-    // Arguments to this function should be results of calling RegExp exec,
-    // which is either an unmodified JSRegExpResult or null. Anything not having
-    // the unmodified JSRegExpResult map is returned unmodified.
-    // This also ensures that elements are fast.
-
-    __ movq(rdx, ContextOperand(rsi, Context::GLOBAL_INDEX));
-    __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalContextOffset));
-    __ movq(rdx, ContextOperand(rdx, Context::REGEXP_RESULT_MAP_INDEX));
-    __ cmpq(rdx, FieldOperand(rax, HeapObject::kMapOffset));
-    __ j(not_equal, &done);
-
-    if (FLAG_debug_code) {
-      // Check that object really has empty properties array, as the map
-      // should guarantee.
-      __ CompareRoot(FieldOperand(rax, JSObject::kPropertiesOffset),
-                     Heap::kEmptyFixedArrayRootIndex);
-      __ Check(equal, "JSRegExpResult: default map but non-empty properties.");
-    }
-
-    DeferredAllocateInNewSpace* allocate_fallback =
-        new DeferredAllocateInNewSpace(JSRegExpResult::kSize,
-                                       rbx,
-                                       rdx.bit() | rax.bit());
-
-    // All set, copy the contents to a new object.
-    __ AllocateInNewSpace(JSRegExpResult::kSize,
-                          rbx,
-                          no_reg,
-                          no_reg,
-                          allocate_fallback->entry_label(),
-                          TAG_OBJECT);
-    __ bind(allocate_fallback->exit_label());
-
-    STATIC_ASSERT(JSRegExpResult::kSize % (2 * kPointerSize) == 0);
-    // There is an even number of fields, so unroll the loop once
-    // for efficiency.
-    for (int i = 0; i < JSRegExpResult::kSize; i += 2 * kPointerSize) {
-      STATIC_ASSERT(JSObject::kMapOffset % (2 * kPointerSize) == 0);
-      if (i != JSObject::kMapOffset) {
-        // The map was already loaded into edx.
-        __ movq(rdx, FieldOperand(rax, i));
-      }
-      __ movq(rcx, FieldOperand(rax, i + kPointerSize));
-
-      STATIC_ASSERT(JSObject::kElementsOffset % (2 * kPointerSize) == 0);
-      if (i == JSObject::kElementsOffset) {
-        // If the elements array isn't empty, make it copy-on-write
-        // before copying it.
-        Label empty;
-        __ CompareRoot(rdx, Heap::kEmptyFixedArrayRootIndex);
-        __ j(equal, &empty);
-        __ LoadRoot(kScratchRegister, Heap::kFixedCOWArrayMapRootIndex);
-        __ movq(FieldOperand(rdx, HeapObject::kMapOffset), kScratchRegister);
-        __ bind(&empty);
-      }
-      __ movq(FieldOperand(rbx, i), rdx);
-      __ movq(FieldOperand(rbx, i + kPointerSize), rcx);
-    }
-    __ movq(rax, rbx);
-
-    __ bind(&done);
-  }
-  frame_->Push(rax);
-}
-
-
 class DeferredSearchCache: public DeferredCode {
  public:
   DeferredSearchCache(Register dst,
@@ -7299,7 +7230,7 @@ void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
     // Push the builtins object found in the current global object.
     Result temp = allocator()->Allocate();
     ASSERT(temp.is_valid());
-    __ movq(temp.reg(), GlobalObject());
+    __ movq(temp.reg(), GlobalObjectOperand());
     __ movq(temp.reg(),
             FieldOperand(temp.reg(), GlobalObject::kBuiltinsOffset));
     frame_->Push(&temp);
index 795732451c35182411c7ca7393e814cf163764b2..c3270add2618d91065079ce967e08f2288698421 100644 (file)
@@ -341,10 +341,6 @@ class CodeGenerator: public AstVisitor {
   bool in_spilled_code() const { return in_spilled_code_; }
   void set_in_spilled_code(bool flag) { in_spilled_code_ = flag; }
 
-  static Operand ContextOperand(Register context, int index) {
-    return Operand(context, Context::SlotOffset(index));
-  }
-
  private:
   // Type of a member function that generates inline code for a native function.
   typedef void (CodeGenerator::*InlineFunctionGenerator)
@@ -417,10 +413,6 @@ class CodeGenerator: public AstVisitor {
                                             JumpTarget* slow);
 
   // Expressions
-  static Operand GlobalObject() {
-    return ContextOperand(rsi, Context::GLOBAL_INDEX);
-  }
-
   void LoadCondition(Expression* x,
                      ControlDestination* destination,
                      bool force_control);
@@ -588,10 +580,6 @@ class CodeGenerator: public AstVisitor {
 
   void ProcessDeclarations(ZoneList<Declaration*>* declarations);
 
-  static Handle<Code> ComputeCallInitialize(int argc, InLoopFlag in_loop);
-
-  static Handle<Code> ComputeKeyedCallInitialize(int argc, InLoopFlag in_loop);
-
   // Declare global variables and functions in the given array of
   // name/value pairs.
   void DeclareGlobals(Handle<FixedArray> pairs);
@@ -656,8 +644,6 @@ class CodeGenerator: public AstVisitor {
 
   void GenerateRegExpConstructResult(ZoneList<Expression*>* args);
 
-  void GenerateRegExpCloneResult(ZoneList<Expression*>* args);
-
   // Support for fast native caches.
   void GenerateGetFromCache(ZoneList<Expression*>* args);
 
index 4e0f6d4b6244ed327e654b617888285a589be63f..e4b24ff4cdb05d5d696a585712fea34ccce06220 100644 (file)
@@ -36,6 +36,7 @@
 #include "full-codegen.h"
 #include "parser.h"
 #include "scopes.h"
+#include "stub-cache.h"
 
 namespace v8 {
 namespace internal {
@@ -912,7 +913,7 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
 
   // All extension objects were empty and it is safe to use a global
   // load IC call.
-  __ movq(rax, CodeGenerator::GlobalObject());
+  __ movq(rax, GlobalObjectOperand());
   __ Move(rcx, slot->var()->name());
   Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
   RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
@@ -1016,7 +1017,7 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var) {
     // Use inline caching. Variable name is passed in rcx and the global
     // object on the stack.
     __ Move(rcx, var->name());
-    __ movq(rax, CodeGenerator::GlobalObject());
+    __ movq(rax, GlobalObjectOperand());
     Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
     EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
     context()->Plug(rax);
@@ -1555,7 +1556,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
     // assignment.  Right-hand-side value is passed in rax, variable name in
     // rcx, and the global object on the stack.
     __ Move(rcx, var->name());
-    __ movq(rdx, CodeGenerator::GlobalObject());
+    __ movq(rdx, GlobalObjectOperand());
     Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
     EmitCallIC(ic, RelocInfo::CODE_TARGET);
 
@@ -1717,16 +1718,17 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
   // Code common for calls using the IC.
   ZoneList<Expression*>* args = expr->arguments();
   int arg_count = args->length();
-  for (int i = 0; i < arg_count; i++) {
-    VisitForStackValue(args->at(i));
+  { PreserveStatementPositionScope scope(masm()->positions_recorder());
+    for (int i = 0; i < arg_count; i++) {
+      VisitForStackValue(args->at(i));
+    }
+    __ Move(rcx, name);
   }
-  __ Move(rcx, name);
   // Record source position for debugger.
-  SetSourcePosition(expr->position());
+  SetSourcePosition(expr->position(), FORCED_POSITION);
   // Call the IC initialization code.
   InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
-  Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
-                                                         in_loop);
+  Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, in_loop);
   EmitCallIC(ic, mode);
   // Restore context register.
   __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
@@ -1737,24 +1739,33 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
                                             Expression* key,
                                             RelocInfo::Mode mode) {
-  // Code common for calls using the IC.
+  // Load the key.
+  VisitForAccumulatorValue(key);
+
+  // Swap the name of the function and the receiver on the stack to follow
+  // the calling convention for call ICs.
+  __ pop(rcx);
+  __ push(rax);
+  __ push(rcx);
+
+  // Load the arguments.
   ZoneList<Expression*>* args = expr->arguments();
   int arg_count = args->length();
-  for (int i = 0; i < arg_count; i++) {
-    VisitForStackValue(args->at(i));
+  { PreserveStatementPositionScope scope(masm()->positions_recorder());
+    for (int i = 0; i < arg_count; i++) {
+      VisitForStackValue(args->at(i));
+    }
   }
-  VisitForAccumulatorValue(key);
-  __ movq(rcx, rax);
   // Record source position for debugger.
-  SetSourcePosition(expr->position());
+  SetSourcePosition(expr->position(), FORCED_POSITION);
   // Call the IC initialization code.
   InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
-  Handle<Code> ic = CodeGenerator::ComputeKeyedCallInitialize(arg_count,
-                                                              in_loop);
+  Handle<Code> ic = StubCache::ComputeKeyedCallInitialize(arg_count, in_loop);
+  __ movq(rcx, Operand(rsp, (arg_count + 1) * kPointerSize));  // Key.
   EmitCallIC(ic, mode);
   // Restore context register.
   __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
-  context()->Plug(rax);
+  context()->DropAndPlug(1, rax);  // Drop the key still on the stack.
 }
 
 
@@ -1762,11 +1773,13 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr) {
   // Code common for calls using the call stub.
   ZoneList<Expression*>* args = expr->arguments();
   int arg_count = args->length();
-  for (int i = 0; i < arg_count; i++) {
-    VisitForStackValue(args->at(i));
+  { PreserveStatementPositionScope scope(masm()->positions_recorder());
+    for (int i = 0; i < arg_count; i++) {
+      VisitForStackValue(args->at(i));
+    }
   }
   // Record source position for debugger.
-  SetSourcePosition(expr->position());
+  SetSourcePosition(expr->position(), FORCED_POSITION);
   InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
   CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
   __ CallStub(&stub);
@@ -1787,37 +1800,38 @@ void FullCodeGenerator::VisitCall(Call* expr) {
     // resolve the function we need to call and the receiver of the
     // call.  The we call the resolved function using the given
     // arguments.
-    VisitForStackValue(fun);
-    __ PushRoot(Heap::kUndefinedValueRootIndex);  // Reserved receiver slot.
-
-    // Push the arguments.
     ZoneList<Expression*>* args = expr->arguments();
     int arg_count = args->length();
-    for (int i = 0; i < arg_count; i++) {
-      VisitForStackValue(args->at(i));
-    }
+    { PreserveStatementPositionScope pos_scope(masm()->positions_recorder());
+      VisitForStackValue(fun);
+      __ PushRoot(Heap::kUndefinedValueRootIndex);  // Reserved receiver slot.
 
-    // Push copy of the function - found below the arguments.
-    __ push(Operand(rsp, (arg_count + 1) * kPointerSize));
+      // Push the arguments.
+      for (int i = 0; i < arg_count; i++) {
+        VisitForStackValue(args->at(i));
+      }
 
-    // Push copy of the first argument or undefined if it doesn't exist.
-    if (arg_count > 0) {
-      __ push(Operand(rsp, arg_count * kPointerSize));
-    } else {
-      __ PushRoot(Heap::kUndefinedValueRootIndex);
-    }
+      // Push copy of the function - found below the arguments.
+      __ push(Operand(rsp, (arg_count + 1) * kPointerSize));
 
-    // Push the receiver of the enclosing function and do runtime call.
-    __ push(Operand(rbp, (2 + scope()->num_parameters()) * kPointerSize));
-    __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
+      // Push copy of the first argument or undefined if it doesn't exist.
+      if (arg_count > 0) {
+        __ push(Operand(rsp, arg_count * kPointerSize));
+      } else {
+      __ PushRoot(Heap::kUndefinedValueRootIndex);
+      }
 
-    // The runtime call returns a pair of values in rax (function) and
-    // rdx (receiver). Touch up the stack with the right values.
-    __ movq(Operand(rsp, (arg_count + 0) * kPointerSize), rdx);
-    __ movq(Operand(rsp, (arg_count + 1) * kPointerSize), rax);
+      // Push the receiver of the enclosing function and do runtime call.
+      __ push(Operand(rbp, (2 + scope()->num_parameters()) * kPointerSize));
+      __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
 
+      // The runtime call returns a pair of values in rax (function) and
+      // rdx (receiver). Touch up the stack with the right values.
+      __ movq(Operand(rsp, (arg_count + 0) * kPointerSize), rdx);
+      __ movq(Operand(rsp, (arg_count + 1) * kPointerSize), rax);
+    }
     // Record source position for debugger.
-    SetSourcePosition(expr->position());
+    SetSourcePosition(expr->position(), FORCED_POSITION);
     InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
     CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
     __ CallStub(&stub);
@@ -1827,42 +1841,44 @@ void FullCodeGenerator::VisitCall(Call* expr) {
   } else if (var != NULL && !var->is_this() && var->is_global()) {
     // Call to a global variable.
     // Push global object as receiver for the call IC lookup.
-    __ push(CodeGenerator::GlobalObject());
+    __ push(GlobalObjectOperand());
     EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
   } else if (var != NULL && var->AsSlot() != NULL &&
              var->AsSlot()->type() == Slot::LOOKUP) {
     // Call to a lookup slot (dynamically introduced variable).
     Label slow, done;
 
-    // Generate code for loading from variables potentially shadowed
-    // by eval-introduced variables.
-    EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
-                                    NOT_INSIDE_TYPEOF,
-                                    &slow,
-                                    &done);
-
-    __ bind(&slow);
-    // Call the runtime to find the function to call (returned in rax)
-    // and the object holding it (returned in rdx).
-    __ push(context_register());
-    __ Push(var->name());
-    __ CallRuntime(Runtime::kLoadContextSlot, 2);
-    __ push(rax);  // Function.
-    __ push(rdx);  // Receiver.
-
-    // If fast case code has been generated, emit code to push the
-    // function and receiver and have the slow path jump around this
-    // code.
-    if (done.is_linked()) {
-      NearLabel call;
-      __ jmp(&call);
-      __ bind(&done);
-      // Push function.
-      __ push(rax);
-      // Push global receiver.
-      __ movq(rbx, CodeGenerator::GlobalObject());
-      __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
-      __ bind(&call);
+    { PreserveStatementPositionScope scope(masm()->positions_recorder());
+      // Generate code for loading from variables potentially shadowed
+      // by eval-introduced variables.
+      EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
+                                      NOT_INSIDE_TYPEOF,
+                                      &slow,
+                                      &done);
+
+      __ bind(&slow);
+      // Call the runtime to find the function to call (returned in rax)
+      // and the object holding it (returned in rdx).
+      __ push(context_register());
+      __ Push(var->name());
+      __ CallRuntime(Runtime::kLoadContextSlot, 2);
+      __ push(rax);  // Function.
+      __ push(rdx);  // Receiver.
+
+      // If fast case code has been generated, emit code to push the
+      // function and receiver and have the slow path jump around this
+      // code.
+      if (done.is_linked()) {
+        NearLabel call;
+        __ jmp(&call);
+        __ bind(&done);
+        // Push function.
+        __ push(rax);
+        // Push global receiver.
+        __ movq(rbx, GlobalObjectOperand());
+        __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
+        __ bind(&call);
+      }
     }
 
     EmitCallWithStub(expr);
@@ -1873,18 +1889,24 @@ void FullCodeGenerator::VisitCall(Call* expr) {
     Literal* key = prop->key()->AsLiteral();
     if (key != NULL && key->handle()->IsSymbol()) {
       // Call to a named property, use call IC.
-      VisitForStackValue(prop->obj());
+      { PreserveStatementPositionScope scope(masm()->positions_recorder());
+        VisitForStackValue(prop->obj());
+      }
       EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
     } else {
       // Call to a keyed property.
       // For a synthetic property use keyed load IC followed by function call,
       // for a regular property use KeyedCallIC.
-      VisitForStackValue(prop->obj());
+      { PreserveStatementPositionScope scope(masm()->positions_recorder());
+        VisitForStackValue(prop->obj());
+      }
       if (prop->is_synthetic()) {
-        VisitForAccumulatorValue(prop->key());
-        __ movq(rdx, Operand(rsp, 0));
+        { PreserveStatementPositionScope scope(masm()->positions_recorder());
+          VisitForAccumulatorValue(prop->key());
+          __ movq(rdx, Operand(rsp, 0));
+        }
         // Record source code position for IC call.
-        SetSourcePosition(prop->position());
+        SetSourcePosition(prop->position(), FORCED_POSITION);
         Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
         EmitCallIC(ic, RelocInfo::CODE_TARGET);
         // Pop receiver.
@@ -1892,7 +1914,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
         // Push result (function).
         __ push(rax);
         // Push receiver object on stack.
-        __ movq(rcx, CodeGenerator::GlobalObject());
+        __ movq(rcx, GlobalObjectOperand());
         __ push(FieldOperand(rcx, GlobalObject::kGlobalReceiverOffset));
         EmitCallWithStub(expr);
       } else {
@@ -1909,9 +1931,11 @@ void FullCodeGenerator::VisitCall(Call* expr) {
         loop_depth() == 0) {
       lit->set_try_full_codegen(true);
     }
-    VisitForStackValue(fun);
+    { PreserveStatementPositionScope scope(masm()->positions_recorder());
+      VisitForStackValue(fun);
+    }
     // Load global receiver object.
-    __ movq(rbx, CodeGenerator::GlobalObject());
+    __ movq(rbx, GlobalObjectOperand());
     __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
     // Emit function call.
     EmitCallWithStub(expr);
@@ -2784,7 +2808,7 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
 
   if (expr->is_jsruntime()) {
     // Prepare for calling JS runtime function.
-    __ movq(rax, CodeGenerator::GlobalObject());
+    __ movq(rax, GlobalObjectOperand());
     __ push(FieldOperand(rax, GlobalObject::kBuiltinsOffset));
   }
 
@@ -2798,7 +2822,7 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
     // Call the JS runtime function using a call IC.
     __ Move(rcx, expr->name());
     InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
-    Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop);
+    Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, in_loop);
     EmitCallIC(ic, RelocInfo::CODE_TARGET);
     // Restore context register.
     __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
@@ -2834,7 +2858,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
           VisitForStackValue(prop->obj());
           VisitForStackValue(prop->key());
         } else if (var->is_global()) {
-          __ push(CodeGenerator::GlobalObject());
+          __ push(GlobalObjectOperand());
           __ Push(var->name());
         } else {
           // Non-global variable.  Call the runtime to look up the context
@@ -3105,7 +3129,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
   if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) {
     Comment cmnt(masm_, "Global variable");
     __ Move(rcx, proxy->name());
-    __ movq(rax, CodeGenerator::GlobalObject());
+    __ movq(rax, GlobalObjectOperand());
     Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
     // Use a regular load, not a contextual load, to avoid a reference
     // error.
index 1d95b7f663d16e7c780093561ffacba9aac86797..9ec781487be65b69fe22ff239b18830f1bcaaa4e 100644 (file)
@@ -33,7 +33,6 @@
 #include "ic-inl.h"
 #include "runtime.h"
 #include "stub-cache.h"
-#include "utils.h"
 
 namespace v8 {
 namespace internal {
index 293d8a5633f6ed33e40a47dc864cc305cf1654c1..834a6f6ef593db08f7c4d3eeb8ffe6ba5bd6ac59 100644 (file)
@@ -327,7 +327,7 @@ MaybeObject* MacroAssembler::TryCallStub(CodeStub* stub) {
 
 
 void MacroAssembler::TailCallStub(CodeStub* stub) {
-  ASSERT(allow_stub_calls());  // calls are not allowed in some stubs
+  ASSERT(allow_stub_calls());  // Calls are not allowed in some stubs.
   Jump(stub->GetCode(), RelocInfo::CODE_TARGET);
 }
 
@@ -456,6 +456,24 @@ void MacroAssembler::TailCallExternalReference(const ExternalReference& ext,
 }
 
 
+MaybeObject* MacroAssembler::TryTailCallExternalReference(
+    const ExternalReference& ext, int num_arguments, int result_size) {
+  // ----------- S t a t e -------------
+  //  -- rsp[0] : return address
+  //  -- rsp[8] : argument num_arguments - 1
+  //  ...
+  //  -- rsp[8 * num_arguments] : argument 0 (receiver)
+  // -----------------------------------
+
+  // TODO(1236192): Most runtime routines don't need the number of
+  // arguments passed in because it is constant. At some point we
+  // should remove this need and make the runtime routine entry code
+  // smarter.
+  Set(rax, num_arguments);
+  return TryJumpToExternalReference(ext, result_size);
+}
+
+
 void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
                                      int num_arguments,
                                      int result_size) {
@@ -463,6 +481,15 @@ void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
 }
 
 
+MaybeObject* MacroAssembler::TryTailCallRuntime(Runtime::FunctionId fid,
+                                                int num_arguments,
+                                                int result_size) {
+  return TryTailCallExternalReference(ExternalReference(fid),
+                                      num_arguments,
+                                      result_size);
+}
+
+
 static int Offset(ExternalReference ref0, ExternalReference ref1) {
   int64_t offset = (ref0.address() - ref1.address());
   // Check that fits into int.
@@ -471,12 +498,22 @@ static int Offset(ExternalReference ref0, ExternalReference ref1) {
 }
 
 
-void MacroAssembler::PrepareCallApiFunction(int stack_space) {
-  EnterApiExitFrame(stack_space, 0);
+void MacroAssembler::PrepareCallApiFunction(int arg_stack_space) {
+#ifdef _WIN64
+  // We need to prepare a slot for result handle on stack and put
+  // a pointer to it into 1st arg register.
+  EnterApiExitFrame(arg_stack_space + 1);
+
+  // rcx must be used to pass the pointer to the return value slot.
+  lea(rcx, StackSpaceOperand(arg_stack_space));
+#else
+  EnterApiExitFrame(arg_stack_space);
+#endif
 }
 
 
-void MacroAssembler::CallApiFunctionAndReturn(ApiFunction* function) {
+MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(
+    ApiFunction* function, int stack_space) {
   Label empty_result;
   Label prologue;
   Label promote_scheduled_exception;
@@ -499,7 +536,7 @@ void MacroAssembler::CallApiFunctionAndReturn(ApiFunction* function) {
   // Allocate HandleScope in callee-save registers.
   Register prev_next_address_reg = r14;
   Register prev_limit_reg = rbx;
-  Register base_reg = kSmiConstantRegister;
+  Register base_reg = r12;
   movq(base_reg, next_address);
   movq(prev_next_address_reg, Operand(base_reg, kNextOffset));
   movq(prev_limit_reg, Operand(base_reg, kLimitOffset));
@@ -528,18 +565,21 @@ void MacroAssembler::CallApiFunctionAndReturn(ApiFunction* function) {
   cmpq(prev_limit_reg, Operand(base_reg, kLimitOffset));
   j(not_equal, &delete_allocated_handles);
   bind(&leave_exit_frame);
-  InitializeSmiConstantRegister();
 
   // Check if the function scheduled an exception.
   movq(rsi, scheduled_exception_address);
   Cmp(Operand(rsi, 0), Factory::the_hole_value());
   j(not_equal, &promote_scheduled_exception);
 
-  LeaveExitFrame();
-  ret(0);
+  LeaveApiExitFrame();
+  ret(stack_space * kPointerSize);
 
   bind(&promote_scheduled_exception);
-  TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
+  MaybeObject* result = TryTailCallRuntime(Runtime::kPromoteScheduledException,
+                                           0, 1);
+  if (result->IsFailure()) {
+    return result;
+  }
 
   bind(&empty_result);
   // It was zero; the result is undefined.
@@ -554,6 +594,8 @@ void MacroAssembler::CallApiFunctionAndReturn(ApiFunction* function) {
   call(rax);
   movq(rax, prev_limit_reg);
   jmp(&leave_exit_frame);
+
+  return result;
 }
 
 
@@ -566,6 +608,15 @@ void MacroAssembler::JumpToExternalReference(const ExternalReference& ext,
 }
 
 
+MaybeObject* MacroAssembler::TryJumpToExternalReference(
+    const ExternalReference& ext, int result_size) {
+  // Set the entry point and jump to the C entry runtime stub.
+  movq(rbx, ext);
+  CEntryStub ces(result_size);
+  return TryTailCallStub(&ces);
+}
+
+
 void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag) {
   // Calls are not allowed in some stubs.
   ASSERT(flag == JUMP_FUNCTION || allow_stub_calls());
@@ -1690,22 +1741,15 @@ void MacroAssembler::EnterExitFramePrologue(bool save_rax) {
   store_rax(context_address);
 }
 
-void MacroAssembler::EnterExitFrameEpilogue(int result_size,
-                                            int argc) {
+
+void MacroAssembler::EnterExitFrameEpilogue(int arg_stack_space) {
 #ifdef _WIN64
-  // Reserve space on stack for result and argument structures, if necessary.
-  int result_stack_space = (result_size < 2) ? 0 : result_size * kPointerSize;
-  // Reserve space for the Arguments object.  The Windows 64-bit ABI
-  // requires us to pass this structure as a pointer to its location on
-  // the stack.  The structure contains 2 values.
-  int argument_stack_space = argc * kPointerSize;
-  // We also need backing space for 4 parameters, even though
-  // we only pass one or two parameter, and it is in a register.
-  int argument_mirror_space = 4 * kPointerSize;
-  int total_stack_space =
-      argument_mirror_space + argument_stack_space + result_stack_space;
-  subq(rsp, Immediate(total_stack_space));
+  const int kShaddowSpace = 4;
+  arg_stack_space += kShaddowSpace;
 #endif
+  if (arg_stack_space > 0) {
+    subq(rsp, Immediate(arg_stack_space * kPointerSize));
+  }
 
   // Get the required frame alignment for the OS.
   static const int kFrameAlignment = OS::ActivationFrameAlignment();
@@ -1720,7 +1764,7 @@ void MacroAssembler::EnterExitFrameEpilogue(int result_size,
 }
 
 
-void MacroAssembler::EnterExitFrame(int result_size) {
+void MacroAssembler::EnterExitFrame(int arg_stack_space) {
   EnterExitFramePrologue(true);
 
   // Setup argv in callee-saved register r12. It is reused in LeaveExitFrame,
@@ -1728,25 +1772,17 @@ void MacroAssembler::EnterExitFrame(int result_size) {
   int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
   lea(r12, Operand(rbp, r14, times_pointer_size, offset));
 
-  EnterExitFrameEpilogue(result_size, 2);
+  EnterExitFrameEpilogue(arg_stack_space);
 }
 
 
-void MacroAssembler::EnterApiExitFrame(int stack_space,
-                                       int argc,
-                                       int result_size) {
+void MacroAssembler::EnterApiExitFrame(int arg_stack_space) {
   EnterExitFramePrologue(false);
-
-  // Setup argv in callee-saved register r12. It is reused in LeaveExitFrame,
-  // so it must be retained across the C-call.
-  int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
-  lea(r12, Operand(rbp, (stack_space * kPointerSize) + offset));
-
-  EnterExitFrameEpilogue(result_size, argc);
+  EnterExitFrameEpilogue(arg_stack_space);
 }
 
 
-void MacroAssembler::LeaveExitFrame(int result_size) {
+void MacroAssembler::LeaveExitFrame() {
   // Registers:
   // r12 : argv
 
@@ -1758,6 +1794,22 @@ void MacroAssembler::LeaveExitFrame(int result_size) {
   // from the caller stack.
   lea(rsp, Operand(r12, 1 * kPointerSize));
 
+  // Push the return address to get ready to return.
+  push(rcx);
+
+  LeaveExitFrameEpilogue();
+}
+
+
+void MacroAssembler::LeaveApiExitFrame() {
+  movq(rsp, rbp);
+  pop(rbp);
+
+  LeaveExitFrameEpilogue();
+}
+
+
+void MacroAssembler::LeaveExitFrameEpilogue() {
   // Restore current context from top and clear it in debug mode.
   ExternalReference context_address(Top::k_context_address);
   movq(kScratchRegister, context_address);
@@ -1766,9 +1818,6 @@ void MacroAssembler::LeaveExitFrame(int result_size) {
   movq(Operand(kScratchRegister, 0), Immediate(0));
 #endif
 
-  // Push the return address to get ready to return.
-  push(rcx);
-
   // Clear the top frame.
   ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
   movq(kScratchRegister, c_entry_fp_address);
index 2f6e9561653225bc51a085b7464aaef77a564f66..5b082fd627e22fe62e41fa3a68e2474e2de44d59 100644 (file)
@@ -155,17 +155,23 @@ class MacroAssembler: public Assembler {
   // debug mode. Expects the number of arguments in register rax and
   // sets up the number of arguments in register rdi and the pointer
   // to the first argument in register rsi.
-  void EnterExitFrame(int result_size = 1);
+  //
+  // Allocates arg_stack_space * kPointerSize memory (not GCed) on the stack
+  // accessible via StackSpaceOperand.
+  void EnterExitFrame(int arg_stack_space = 0);
 
-  void EnterApiExitFrame(int stack_space,
-                         int argc,
-                         int result_size = 1);
+  // Enter specific kind of exit frame. Allocates arg_stack_space * kPointerSize
+  // memory (not GCed) on the stack accessible via StackSpaceOperand.
+  void EnterApiExitFrame(int arg_stack_space);
 
   // Leave the current exit frame. Expects/provides the return value in
   // register rax:rdx (untouched) and the pointer to the first
   // argument in register rsi.
-  void LeaveExitFrame(int result_size = 1);
+  void LeaveExitFrame();
 
+  // Leave the current exit frame. Expects/provides the return value in
+  // register rax (untouched).
+  void LeaveApiExitFrame();
 
   // ---------------------------------------------------------------------------
   // JavaScript invokes
@@ -813,22 +819,38 @@ class MacroAssembler: public Assembler {
                                  int num_arguments,
                                  int result_size);
 
+  MUST_USE_RESULT MaybeObject* TryTailCallExternalReference(
+      const ExternalReference& ext, int num_arguments, int result_size);
+
   // Convenience function: tail call a runtime routine (jump).
   void TailCallRuntime(Runtime::FunctionId fid,
                        int num_arguments,
                        int result_size);
 
+  MUST_USE_RESULT  MaybeObject* TryTailCallRuntime(Runtime::FunctionId fid,
+                                                   int num_arguments,
+                                                   int result_size);
+
   // Jump to a runtime routine.
   void JumpToExternalReference(const ExternalReference& ext, int result_size);
 
-  // Prepares stack to put arguments (aligns and so on).
-  // Uses calle-saved esi to restore stack state after call.
-  void PrepareCallApiFunction(int stack_space);
+  // Jump to a runtime routine.
+  MaybeObject* TryJumpToExternalReference(const ExternalReference& ext,
+                                          int result_size);
 
-  // Tail call an API function (jump). Allocates HandleScope, extracts
-  // returned value from handle and propogates exceptions.
-  // Clobbers ebx, edi and caller-save registers.
-  void CallApiFunctionAndReturn(ApiFunction* function);
+  // Prepares stack to put arguments (aligns and so on).
+  // WIN64 calling convention requires to put the pointer to the return value
+  // slot into rcx (rcx must be preserverd until TryCallApiFunctionAndReturn).
+  // Saves context (rsi). Clobbers rax. Allocates arg_stack_space * kPointerSize
+  // inside the exit frame (not GCed) accessible via StackSpaceOperand.
+  void PrepareCallApiFunction(int arg_stack_space);
+
+  // Calls an API function. Allocates HandleScope, extracts
+  // returned value from handle and propagates exceptions.
+  // Clobbers r12, r14, rbx and caller-save registers. Restores context.
+  // On return removes stack_space * kPointerSize (GCed).
+  MUST_USE_RESULT MaybeObject* TryCallApiFunctionAndReturn(
+      ApiFunction* function, int stack_space);
 
   // Before calling a C-function from generated code, align arguments on stack.
   // After aligning the frame, arguments must be stored in esp[0], esp[4],
@@ -919,7 +941,12 @@ class MacroAssembler: public Assembler {
   void LeaveFrame(StackFrame::Type type);
 
   void EnterExitFramePrologue(bool save_rax);
-  void EnterExitFrameEpilogue(int result_size, int argc);
+
+  // Allocates arg_stack_space * kPointerSize memory (not GCed) on the stack
+  // accessible via StackSpaceOperand.
+  void EnterExitFrameEpilogue(int arg_stack_space);
+
+  void LeaveExitFrameEpilogue();
 
   // Allocation support helpers.
   // Loads the top of new-space into the result register.
@@ -982,6 +1009,28 @@ static inline Operand FieldOperand(Register object,
 }
 
 
+static inline Operand ContextOperand(Register context, int index) {
+  return Operand(context, Context::SlotOffset(index));
+}
+
+
+static inline Operand GlobalObjectOperand() {
+  return ContextOperand(rsi, Context::GLOBAL_INDEX);
+}
+
+
+// Provides access to exit frame stack space (not GCed).
+static inline Operand StackSpaceOperand(int index) {
+#ifdef _WIN64
+  const int kShaddowSpace = 4;
+  return Operand(rsp, (index + kShaddowSpace) * kPointerSize);
+#else
+  return Operand(rsp, index * kPointerSize);
+#endif
+}
+
+
+
 #ifdef GENERATED_CODE_COVERAGE
 extern void LogGeneratedCodeCoverage(const char* file_line);
 #define CODE_COVERAGE_STRINGIFY(x) #x
index 24609bf642beaae6e059a2f94594059be5a35d0b..2e60dd53b46fc6a46c9152f1bef22f9c91168732 100644 (file)
@@ -497,8 +497,10 @@ void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
   __ ret(0);
 }
 
+// Number of pointers to be reserved on stack for fast API call.
+static const int kFastApiCallArguments = 3;
 
-// Reserves space for the extra arguments to FastHandleApiCall in the
+// Reserves space for the extra arguments to API function in the
 // caller's frame.
 //
 // These arguments are set by CheckPrototypes and GenerateFastApiCall.
@@ -508,48 +510,48 @@ static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
   //  -- rsp[8] : last argument in the internal frame of the caller
   // -----------------------------------
   __ movq(scratch, Operand(rsp, 0));
-  __ subq(rsp, Immediate(4 * kPointerSize));
+  __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
   __ movq(Operand(rsp, 0), scratch);
   __ Move(scratch, Smi::FromInt(0));
-  __ movq(Operand(rsp, 1 * kPointerSize), scratch);
-  __ movq(Operand(rsp, 2 * kPointerSize), scratch);
-  __ movq(Operand(rsp, 3 * kPointerSize), scratch);
-  __ movq(Operand(rsp, 4 * kPointerSize), scratch);
+  for (int i = 1; i <= kFastApiCallArguments; i++) {
+     __ movq(Operand(rsp, i * kPointerSize), scratch);
+  }
 }
 
 
 // Undoes the effects of ReserveSpaceForFastApiCall.
 static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
   // ----------- S t a t e -------------
-  //  -- rsp[0]  : return address
-  //  -- rsp[8]  : last fast api call extra argument
+  //  -- rsp[0]  : return address.
+  //  -- rsp[8]  : last fast api call extra argument.
   //  -- ...
-  //  -- rsp[32] : first fast api call extra argument
-  //  -- rsp[40] : last argument in the internal frame
+  //  -- rsp[kFastApiCallArguments * 8] : first fast api call extra argument.
+  //  -- rsp[kFastApiCallArguments * 8 + 8] : last argument in the internal
+  //                                          frame.
   // -----------------------------------
   __ movq(scratch, Operand(rsp, 0));
-  __ movq(Operand(rsp, 4 * kPointerSize), scratch);
-  __ addq(rsp, Immediate(kPointerSize * 4));
+  __ movq(Operand(rsp, kFastApiCallArguments * kPointerSize), scratch);
+  __ addq(rsp, Immediate(kPointerSize * kFastApiCallArguments));
 }
 
 
-// Generates call to FastHandleApiCall builtin.
-static void GenerateFastApiCall(MacroAssembler* masm,
+// Generates call to API function.
+static bool GenerateFastApiCall(MacroAssembler* masm,
                                 const CallOptimization& optimization,
-                                int argc) {
+                                int argc,
+                                Failure** failure) {
   // ----------- S t a t e -------------
   //  -- rsp[0]              : return address
   //  -- rsp[8]              : object passing the type check
   //                           (last fast api call extra argument,
   //                            set by CheckPrototypes)
-  //  -- rsp[16]             : api call data
-  //  -- rsp[24]             : api callback
-  //  -- rsp[32]             : api function
+  //  -- rsp[16]             : api function
   //                           (first fast api call extra argument)
-  //  -- rsp[40]             : last argument
+  //  -- rsp[24]             : api call data
+  //  -- rsp[32]             : last argument
   //  -- ...
-  //  -- rsp[(argc + 5) * 8] : first argument
-  //  -- rsp[(argc + 6) * 8] : receiver
+  //  -- rsp[(argc + 3) * 8] : first argument
+  //  -- rsp[(argc + 4) * 8] : receiver
   // -----------------------------------
 
   // Get the function and setup the context.
@@ -557,38 +559,58 @@ static void GenerateFastApiCall(MacroAssembler* masm,
   __ Move(rdi, Handle<JSFunction>(function));
   __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
 
-  // Pass the additional arguments FastHandleApiCall expects.
-  __ movq(Operand(rsp, 4 * kPointerSize), rdi);
-  bool info_loaded = false;
-  Object* callback = optimization.api_call_info()->callback();
-  if (Heap::InNewSpace(callback)) {
-    info_loaded = true;
-    __ Move(rcx, Handle<CallHandlerInfo>(optimization.api_call_info()));
-    __ movq(rbx, FieldOperand(rcx, CallHandlerInfo::kCallbackOffset));
-    __ movq(Operand(rsp, 3 * kPointerSize), rbx);
-  } else {
-    __ Move(Operand(rsp, 3 * kPointerSize), Handle<Object>(callback));
-  }
+  // Pass the additional arguments.
+  __ movq(Operand(rsp, 2 * kPointerSize), rdi);
   Object* call_data = optimization.api_call_info()->data();
+  Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info());
   if (Heap::InNewSpace(call_data)) {
-    if (!info_loaded) {
-      __ Move(rcx, Handle<CallHandlerInfo>(optimization.api_call_info()));
-    }
+    __ Move(rcx, api_call_info_handle);
     __ movq(rbx, FieldOperand(rcx, CallHandlerInfo::kDataOffset));
-    __ movq(Operand(rsp, 2 * kPointerSize), rbx);
+    __ movq(Operand(rsp, 3 * kPointerSize), rbx);
   } else {
-    __ Move(Operand(rsp, 2 * kPointerSize), Handle<Object>(call_data));
+    __ Move(Operand(rsp, 3 * kPointerSize), Handle<Object>(call_data));
   }
 
-  // Set the number of arguments.
-  __ movq(rax, Immediate(argc + 4));
+  // Prepare arguments.
+  __ lea(rbx, Operand(rsp, 3 * kPointerSize));
 
-  // Jump to the fast api call builtin (tail call).
-  Handle<Code> code = Handle<Code>(
-      Builtins::builtin(Builtins::FastHandleApiCall));
-  ParameterCount expected(0);
-  __ InvokeCode(code, expected, expected,
-                RelocInfo::CODE_TARGET, JUMP_FUNCTION);
+  Object* callback = optimization.api_call_info()->callback();
+  Address api_function_address = v8::ToCData<Address>(callback);
+  ApiFunction fun(api_function_address);
+
+#ifdef _WIN64
+  // Win64 uses first register--rcx--for returned value.
+  Register arguments_arg = rdx;
+#else
+  Register arguments_arg = rdi;
+#endif
+
+  // Allocate the v8::Arguments structure in the arguments' space since
+  // it's not controlled by GC.
+  const int kApiStackSpace = 4;
+
+  __ PrepareCallApiFunction(kApiStackSpace);
+
+  __ movq(StackSpaceOperand(0), rbx);  // v8::Arguments::implicit_args_.
+  __ addq(rbx, Immediate(argc * kPointerSize));
+  __ movq(StackSpaceOperand(1), rbx);  // v8::Arguments::values_.
+  __ Set(StackSpaceOperand(2), argc);  // v8::Arguments::length_.
+  // v8::Arguments::is_construct_call_.
+  __ Set(StackSpaceOperand(3), 0);
+
+  // v8::InvocationCallback's argument.
+  __ lea(arguments_arg, StackSpaceOperand(0));
+  // Emitting a stub call may try to allocate (if the code is not
+  // already generated).  Do not allow the assembler to perform a
+  // garbage collection but instead return the allocation failure
+  // object.
+  MaybeObject* result =
+      masm->TryCallApiFunctionAndReturn(&fun, argc + kFastApiCallArguments + 1);
+  if (result->IsFailure()) {
+    *failure = Failure::cast(result);
+    return false;
+  }
+  return true;
 }
 
 
@@ -601,7 +623,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
         arguments_(arguments),
         name_(name) {}
 
-  void Compile(MacroAssembler* masm,
+  bool Compile(MacroAssembler* masm,
                JSObject* object,
                JSObject* holder,
                String* name,
@@ -610,7 +632,8 @@ class CallInterceptorCompiler BASE_EMBEDDED {
                Register scratch1,
                Register scratch2,
                Register scratch3,
-               Label* miss) {
+               Label* miss,
+               Failure** failure) {
     ASSERT(holder->HasNamedInterceptor());
     ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
 
@@ -620,17 +643,18 @@ class CallInterceptorCompiler BASE_EMBEDDED {
     CallOptimization optimization(lookup);
 
     if (optimization.is_constant_call()) {
-      CompileCacheable(masm,
-                       object,
-                       receiver,
-                       scratch1,
-                       scratch2,
-                       scratch3,
-                       holder,
-                       lookup,
-                       name,
-                       optimization,
-                       miss);
+      return CompileCacheable(masm,
+                              object,
+                              receiver,
+                              scratch1,
+                              scratch2,
+                              scratch3,
+                              holder,
+                              lookup,
+                              name,
+                              optimization,
+                              miss,
+                              failure);
     } else {
       CompileRegular(masm,
                      object,
@@ -641,11 +665,12 @@ class CallInterceptorCompiler BASE_EMBEDDED {
                      name,
                      holder,
                      miss);
+      return true;
     }
   }
 
  private:
-  void CompileCacheable(MacroAssembler* masm,
+  bool CompileCacheable(MacroAssembler* masm,
                         JSObject* object,
                         Register receiver,
                         Register scratch1,
@@ -655,7 +680,8 @@ class CallInterceptorCompiler BASE_EMBEDDED {
                         LookupResult* lookup,
                         String* name,
                         const CallOptimization& optimization,
-                        Label* miss_label) {
+                        Label* miss_label,
+                        Failure** failure) {
     ASSERT(optimization.is_constant_call());
     ASSERT(!lookup->holder()->IsGlobalObject());
 
@@ -717,7 +743,13 @@ class CallInterceptorCompiler BASE_EMBEDDED {
 
     // Invoke function.
     if (can_do_fast_api_call) {
-      GenerateFastApiCall(masm, optimization, arguments_.immediate());
+      bool success = GenerateFastApiCall(masm,
+                                         optimization,
+                                         arguments_.immediate(),
+                                         failure);
+      if (!success) {
+        return false;
+      }
     } else {
       __ InvokeFunction(optimization.constant_function(), arguments_,
                         JUMP_FUNCTION);
@@ -735,6 +767,8 @@ class CallInterceptorCompiler BASE_EMBEDDED {
     if (can_do_fast_api_call) {
       FreeSpaceForFastApiCall(masm, scratch1);
     }
+
+    return true;
   }
 
   void CompileRegular(MacroAssembler* masm,
@@ -958,7 +992,9 @@ MaybeObject* CallStubCompiler::CompileCallConstant(
 
       if (depth != kInvalidProtoDepth) {
         __ IncrementCounter(&Counters::call_const_fast_api, 1);
-        ReserveSpaceForFastApiCall(masm(), rax);
+        // Allocate space for v8::Arguments implicit values. Must be initialized
+        // before to call any runtime function.
+        __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
       }
 
       // Check that the maps haven't changed.
@@ -1036,7 +1072,17 @@ MaybeObject* CallStubCompiler::CompileCallConstant(
   }
 
   if (depth != kInvalidProtoDepth) {
-    GenerateFastApiCall(masm(), optimization, argc);
+    Failure* failure;
+    // Move the return address on top of the stack.
+    __ movq(rax, Operand(rsp, 3 * kPointerSize));
+    __ movq(Operand(rsp, 0 * kPointerSize), rax);
+
+    // rsp[2 * kPointerSize] is uninitialized, rsp[3 * kPointerSize] contains
+    // duplicate of return address and will be overwritten.
+    bool success = GenerateFastApiCall(masm(), optimization, argc, &failure);
+    if (!success) {
+      return failure;
+    }
   } else {
     __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
   }
@@ -1044,7 +1090,7 @@ MaybeObject* CallStubCompiler::CompileCallConstant(
   // Handle call cache miss.
   __ bind(&miss);
   if (depth != kInvalidProtoDepth) {
-    FreeSpaceForFastApiCall(masm(), rax);
+    __ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
   }
 
   // Handle call cache miss.
@@ -1723,16 +1769,21 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
   __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
 
   CallInterceptorCompiler compiler(this, arguments(), rcx);
-  compiler.Compile(masm(),
-                   object,
-                   holder,
-                   name,
-                   &lookup,
-                   rdx,
-                   rbx,
-                   rdi,
-                   rax,
-                   &miss);
+  Failure* failure;
+  bool success = compiler.Compile(masm(),
+                                  object,
+                                  holder,
+                                  name,
+                                  &lookup,
+                                  rdx,
+                                  rbx,
+                                  rdi,
+                                  rax,
+                                  &miss,
+                                  &failure);
+  if (!success) {
+    return failure;
+  }
 
   // Restore receiver.
   __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
@@ -1844,7 +1895,7 @@ MaybeObject* LoadStubCompiler::CompileLoadCallback(String* name,
   Label miss;
 
   Failure* failure = Failure::InternalError();
-  bool success = GenerateLoadCallback(object, holder, rax, rcx, rbx, rdx, rdi,
+  bool success = GenerateLoadCallback(object, holder, rax, rcx, rdx, rbx, rdi,
                                       callback, name, &miss, &failure);
   if (!success) {
     miss.Unuse();
@@ -2585,16 +2636,15 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object,
 
   Handle<AccessorInfo> callback_handle(callback);
 
-  __ EnterInternalFrame();
-  // Push the stack address where the list of arguments ends.
-  __ movq(scratch2, rsp);
-  __ subq(scratch2, Immediate(2 * kPointerSize));
-  __ push(scratch2);
+  // Insert additional parameters into the stack frame above return address.
+  ASSERT(!scratch2.is(reg));
+  __ pop(scratch2);  // Get return address to place it below.
+
   __ push(receiver);  // receiver
   __ push(reg);  // holder
   if (Heap::InNewSpace(callback_handle->data())) {
-    __ Move(scratch2, callback_handle);
-    __ push(FieldOperand(scratch2, AccessorInfo::kDataOffset));  // data
+    __ Move(scratch1, callback_handle);
+    __ push(FieldOperand(scratch1, AccessorInfo::kDataOffset));  // data
   } else {
     __ Push(Handle<Object>(callback_handle->data()));
   }
@@ -2607,42 +2657,43 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object,
   Register accessor_info_arg = r8;
   Register name_arg = rdx;
 #else
-  Register accessor_info_arg = rdx;  // temporary, copied to rsi by the stub.
+  Register accessor_info_arg = rsi;
   Register name_arg = rdi;
 #endif
 
-  __ movq(accessor_info_arg, rsp);
-  __ addq(accessor_info_arg, Immediate(4 * kPointerSize));
+  ASSERT(!name_arg.is(scratch2));
   __ movq(name_arg, rsp);
+  __ push(scratch2);  // Restore return address.
 
   // Do call through the api.
-  ASSERT_EQ(5, ApiGetterEntryStub::kStackSpace);
   Address getter_address = v8::ToCData<Address>(callback->getter());
   ApiFunction fun(getter_address);
-  ApiGetterEntryStub stub(callback_handle, &fun);
-#ifdef _WIN64
-  // We need to prepare a slot for result handle on stack and put
-  // a pointer to it into 1st arg register.
-  __ push(Immediate(0));
-  __ movq(rcx, rsp);
-#endif
+
+  // 3 elements array for v8::Agruments::values_ and handler for name.
+  const int kStackSpace = 4;
+
+  // Allocate v8::AccessorInfo in non-GCed stack space.
+  const int kArgStackSpace = 1;
+
+  __ PrepareCallApiFunction(kArgStackSpace);
+  __ lea(rax, Operand(name_arg, 3 * kPointerSize));
+
+  // v8::AccessorInfo::args_.
+  __ movq(StackSpaceOperand(0), rax);
+
+  // The context register (rsi) has been saved in PrepareCallApiFunction and
+  // could be used to pass arguments.
+  __ lea(accessor_info_arg, StackSpaceOperand(0));
+
   // Emitting a stub call may try to allocate (if the code is not
   // already generated).  Do not allow the assembler to perform a
   // garbage collection but instead return the allocation failure
   // object.
-  MaybeObject* result = masm()->TryCallStub(&stub);
+  MaybeObject* result = masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace);
   if (result->IsFailure()) {
     *failure = Failure::cast(result);
     return false;
   }
-#ifdef _WIN64
-  // Discard allocated slot.
-  __ addq(rsp, Immediate(kPointerSize));
-#endif
-  __ LeaveInternalFrame();
-
-  __ ret(0);
-
   return true;
 }
 
index e88a993b25c864d003999360d6df8e7f48f71250..3f7b1db7e5c0d6060bdc5b9a9630d172e5d8f5f0 100644 (file)
@@ -32,6 +32,7 @@
 #include "codegen-inl.h"
 #include "register-allocator-inl.h"
 #include "scopes.h"
+#include "stub-cache.h"
 #include "virtual-frame-inl.h"
 
 namespace v8 {
@@ -1194,7 +1195,7 @@ Result VirtualFrame::CallCallIC(RelocInfo::Mode mode,
   // and dropped by the call.  The IC expects the name in rcx and the rest
   // on the stack, and drops them all.
   InLoopFlag in_loop = loop_nesting > 0 ? IN_LOOP : NOT_IN_LOOP;
-  Handle<Code> ic = cgen()->ComputeCallInitialize(arg_count, in_loop);
+  Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, in_loop);
   Result name = Pop();
   // Spill args, receiver, and function.  The call will drop args and
   // receiver.
@@ -1213,7 +1214,7 @@ Result VirtualFrame::CallKeyedCallIC(RelocInfo::Mode mode,
   // on the stack, and drops them all.
   InLoopFlag in_loop = loop_nesting > 0 ? IN_LOOP : NOT_IN_LOOP;
   Handle<Code> ic =
-      cgen()->ComputeKeyedCallInitialize(arg_count, in_loop);
+      StubCache::ComputeKeyedCallInitialize(arg_count, in_loop);
   Result name = Pop();
   // Spill args, receiver, and function.  The call will drop args and
   // receiver.
index 006653c2e8e4156536155a3f0a5b1b103b38209f..ba3466deec1f03e9aa3c550ebfcd9df2450c5381 100644 (file)
@@ -41,6 +41,8 @@ SOURCES = {
     'test-alloc.cc',
     'test-api.cc',
     'test-ast.cc',
+    'test-bignum.cc',
+    'test-bignum-dtoa.cc',
     'test-circular-queue.cc',
     'test-compiler.cc',
     'test-conversions.cc',
@@ -50,6 +52,7 @@ SOURCES = {
     'test-decls.cc',
     'test-diy-fp.cc',
     'test-double.cc',
+    'test-dtoa.cc',
     'test-fast-dtoa.cc',
     'test-fixed-dtoa.cc',
     'test-flags.cc',
index 6eb15d8fbfa778b61ce050b6be8a96dd12102c5e..b4f6914ed789edc19a9e2ed319309a08e85a44c4 100644 (file)
@@ -38,6 +38,7 @@
 #include "utils.h"
 #include "cctest.h"
 #include "parser.h"
+#include "unicode-inl.h"
 
 static const bool kLogThreading = true;
 
@@ -10629,7 +10630,7 @@ THREADED_TEST(IdleNotification) {
 static uint32_t* stack_limit;
 
 static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
-  stack_limit = reinterpret_cast<uint32_t*>(i::StackGuard::climit());
+  stack_limit = reinterpret_cast<uint32_t*>(i::StackGuard::real_climit());
   return v8::Undefined();
 }
 
index 4f90b613a83b7dcd59c753a23483a20d2a6437fc..0f12f985a36f2136bdf8a13db85b8b0b21d2ad07 100644 (file)
@@ -397,4 +397,72 @@ TEST(6) {
   }
 }
 
+
+static void TestRoundingMode(int32_t mode, double value, int expected) {
+  InitializeVM();
+  v8::HandleScope scope;
+
+  Assembler assm(NULL, 0);
+
+  __ vmrs(r1);
+  // Set custom FPSCR.
+  __ bic(r2, r1, Operand(((mode ^ 3) << 22) | 0xf));
+  __ orr(r2, r2, Operand(mode << 22));
+  __ vmsr(r2);
+
+  // Load value, convert, and move back result to r0.
+  __ vmov(d1, value);
+  __ vcvt_s32_f64(s0, d1, Assembler::FPSCRRounding, al);
+  __ vmov(r0, s0);
+
+  __ mov(pc, Operand(lr));
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Object* code = Heap::CreateCode(
+      desc,
+      Code::ComputeFlags(Code::STUB),
+      Handle<Object>(Heap::undefined_value()))->ToObjectChecked();
+  CHECK(code->IsCode());
+#ifdef DEBUG
+  Code::cast(code)->Print();
+#endif
+  F1 f = FUNCTION_CAST<F1>(Code::cast(code)->entry());
+  int res = reinterpret_cast<int>(
+              CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
+  ::printf("res = %d\n", res);
+  CHECK_EQ(expected, res);
+}
+
+
+TEST(7) {
+  // Test vfp rounding modes.
+
+  // See ARM DDI 0406B Page A2-29.
+  enum FPSCRRoungingMode {
+    RN,   // Round to Nearest.
+    RP,   // Round towards Plus Infinity.
+    RM,   // Round towards Minus Infinity.
+    RZ    // Round towards zero.
+  };
+
+  if (CpuFeatures::IsSupported(VFP3)) {
+    CpuFeatures::Scope scope(VFP3);
+
+    TestRoundingMode(RZ,  0.5, 0);
+    TestRoundingMode(RZ, -0.5, 0);
+    TestRoundingMode(RZ,  123.7,  123);
+    TestRoundingMode(RZ, -123.7, -123);
+    TestRoundingMode(RZ,  123456.2,  123456);
+    TestRoundingMode(RZ, -123456.2, -123456);
+
+    TestRoundingMode(RM,  0.5, 0);
+    TestRoundingMode(RM, -0.5, -1);
+    TestRoundingMode(RM,  123.7, 123);
+    TestRoundingMode(RM, -123.7, -124);
+    TestRoundingMode(RM,  123456.2,  123456);
+    TestRoundingMode(RM, -123456.2, -123457);
+  }
+}
+
 #undef __
diff --git a/deps/v8/test/cctest/test-bignum-dtoa.cc b/deps/v8/test/cctest/test-bignum-dtoa.cc
new file mode 100644 (file)
index 0000000..51a9057
--- /dev/null
@@ -0,0 +1,315 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "bignum-dtoa.h"
+
+#include "cctest.h"
+#include "double.h"
+#include "gay-fixed.h"
+#include "gay-precision.h"
+#include "gay-shortest.h"
+#include "platform.h"
+
+using namespace v8::internal;
+
+
+// Removes trailing '0' digits.
+// Can return the empty string if all digits are 0.
+static void TrimRepresentation(Vector<char> representation) {
+  int len = strlen(representation.start());
+  int i;
+  for (i = len - 1; i >= 0; --i) {
+    if (representation[i] != '0') break;
+  }
+  representation[i + 1] = '\0';
+}
+
+
+static const int kBufferSize = 100;
+
+
+TEST(BignumDtoaVariousDoubles) {
+  char buffer_container[kBufferSize];
+  Vector<char> buffer(buffer_container, kBufferSize);
+  int length;
+  int point;
+
+  BignumDtoa(1.0, BIGNUM_DTOA_SHORTEST, 0, buffer, &length, &point);
+  CHECK_EQ("1", buffer.start());
+  CHECK_EQ(1, point);
+
+  BignumDtoa(1.0, BIGNUM_DTOA_FIXED, 3, buffer, &length, &point);
+  CHECK_GE(3, length - point);
+  TrimRepresentation(buffer);
+  CHECK_EQ("1", buffer.start());
+  CHECK_EQ(1, point);
+
+  BignumDtoa(1.0, BIGNUM_DTOA_PRECISION, 3, buffer, &length, &point);
+  CHECK_GE(3, length);
+  TrimRepresentation(buffer);
+  CHECK_EQ("1", buffer.start());
+  CHECK_EQ(1, point);
+
+  BignumDtoa(1.5, BIGNUM_DTOA_SHORTEST, 0, buffer, &length, &point);
+  CHECK_EQ("15", buffer.start());
+  CHECK_EQ(1, point);
+
+  BignumDtoa(1.5, BIGNUM_DTOA_FIXED, 10, buffer, &length, &point);
+  CHECK_GE(10, length - point);
+  TrimRepresentation(buffer);
+  CHECK_EQ("15", buffer.start());
+  CHECK_EQ(1, point);
+
+  BignumDtoa(1.5, BIGNUM_DTOA_PRECISION, 10, buffer, &length, &point);
+  CHECK_GE(10, length);
+  TrimRepresentation(buffer);
+  CHECK_EQ("15", buffer.start());
+  CHECK_EQ(1, point);
+
+  double min_double = 5e-324;
+  BignumDtoa(min_double, BIGNUM_DTOA_SHORTEST, 0, buffer, &length, &point);
+  CHECK_EQ("5", buffer.start());
+  CHECK_EQ(-323, point);
+
+  BignumDtoa(min_double, BIGNUM_DTOA_FIXED, 5, buffer, &length, &point);
+  CHECK_GE(5, length - point);
+  TrimRepresentation(buffer);
+  CHECK_EQ("", buffer.start());
+
+  BignumDtoa(min_double, BIGNUM_DTOA_PRECISION, 5, buffer, &length, &point);
+  CHECK_GE(5, length);
+  TrimRepresentation(buffer);
+  CHECK_EQ("49407", buffer.start());
+  CHECK_EQ(-323, point);
+
+  double max_double = 1.7976931348623157e308;
+  BignumDtoa(max_double, BIGNUM_DTOA_SHORTEST, 0, buffer, &length, &point);
+  CHECK_EQ("17976931348623157", buffer.start());
+  CHECK_EQ(309, point);
+
+  BignumDtoa(max_double, BIGNUM_DTOA_PRECISION, 7, buffer, &length, &point);
+  CHECK_GE(7, length);
+  TrimRepresentation(buffer);
+  CHECK_EQ("1797693", buffer.start());
+  CHECK_EQ(309, point);
+
+  BignumDtoa(4294967272.0, BIGNUM_DTOA_SHORTEST, 0, buffer, &length, &point);
+  CHECK_EQ("4294967272", buffer.start());
+  CHECK_EQ(10, point);
+
+  BignumDtoa(4294967272.0, BIGNUM_DTOA_FIXED, 5, buffer, &length, &point);
+  CHECK_EQ("429496727200000", buffer.start());
+  CHECK_EQ(10, point);
+
+
+  BignumDtoa(4294967272.0, BIGNUM_DTOA_PRECISION, 14, buffer, &length, &point);
+  CHECK_GE(14, length);
+  TrimRepresentation(buffer);
+  CHECK_EQ("4294967272", buffer.start());
+  CHECK_EQ(10, point);
+
+  BignumDtoa(4.1855804968213567e298, BIGNUM_DTOA_SHORTEST, 0,
+             buffer, &length, &point);
+  CHECK_EQ("4185580496821357", buffer.start());
+  CHECK_EQ(299, point);
+
+  BignumDtoa(4.1855804968213567e298, BIGNUM_DTOA_PRECISION, 20,
+             buffer, &length, &point);
+  CHECK_GE(20, length);
+  TrimRepresentation(buffer);
+  CHECK_EQ("41855804968213567225", buffer.start());
+  CHECK_EQ(299, point);
+
+  BignumDtoa(5.5626846462680035e-309, BIGNUM_DTOA_SHORTEST, 0,
+             buffer, &length, &point);
+  CHECK_EQ("5562684646268003", buffer.start());
+  CHECK_EQ(-308, point);
+
+  BignumDtoa(5.5626846462680035e-309, BIGNUM_DTOA_PRECISION, 1,
+             buffer, &length, &point);
+  CHECK_GE(1, length);
+  TrimRepresentation(buffer);
+  CHECK_EQ("6", buffer.start());
+  CHECK_EQ(-308, point);
+
+  BignumDtoa(2147483648.0, BIGNUM_DTOA_SHORTEST, 0,
+             buffer, &length, &point);
+  CHECK_EQ("2147483648", buffer.start());
+  CHECK_EQ(10, point);
+
+
+  BignumDtoa(2147483648.0, BIGNUM_DTOA_FIXED, 2,
+             buffer, &length, &point);
+  CHECK_GE(2, length - point);
+  TrimRepresentation(buffer);
+  CHECK_EQ("2147483648", buffer.start());
+  CHECK_EQ(10, point);
+
+  BignumDtoa(2147483648.0, BIGNUM_DTOA_PRECISION, 5,
+             buffer, &length, &point);
+  CHECK_GE(5, length);
+  TrimRepresentation(buffer);
+  CHECK_EQ("21475", buffer.start());
+  CHECK_EQ(10, point);
+
+  BignumDtoa(3.5844466002796428e+298, BIGNUM_DTOA_SHORTEST, 0,
+             buffer, &length, &point);
+  CHECK_EQ("35844466002796428", buffer.start());
+  CHECK_EQ(299, point);
+
+  BignumDtoa(3.5844466002796428e+298, BIGNUM_DTOA_PRECISION, 10,
+             buffer, &length, &point);
+  CHECK_GE(10, length);
+  TrimRepresentation(buffer);
+  CHECK_EQ("35844466", buffer.start());
+  CHECK_EQ(299, point);
+
+  uint64_t smallest_normal64 = V8_2PART_UINT64_C(0x00100000, 00000000);
+  double v = Double(smallest_normal64).value();
+  BignumDtoa(v, BIGNUM_DTOA_SHORTEST, 0, buffer, &length, &point);
+  CHECK_EQ("22250738585072014", buffer.start());
+  CHECK_EQ(-307, point);
+
+  BignumDtoa(v, BIGNUM_DTOA_PRECISION, 20, buffer, &length, &point);
+  CHECK_GE(20, length);
+  TrimRepresentation(buffer);
+  CHECK_EQ("22250738585072013831", buffer.start());
+  CHECK_EQ(-307, point);
+
+  uint64_t largest_denormal64 = V8_2PART_UINT64_C(0x000FFFFF, FFFFFFFF);
+  v = Double(largest_denormal64).value();
+  BignumDtoa(v, BIGNUM_DTOA_SHORTEST, 0, buffer, &length, &point);
+  CHECK_EQ("2225073858507201", buffer.start());
+  CHECK_EQ(-307, point);
+
+  BignumDtoa(v, BIGNUM_DTOA_PRECISION, 20, buffer, &length, &point);
+  CHECK_GE(20, length);
+  TrimRepresentation(buffer);
+  CHECK_EQ("2225073858507200889", buffer.start());
+  CHECK_EQ(-307, point);
+
+  BignumDtoa(4128420500802942e-24, BIGNUM_DTOA_SHORTEST, 0,
+             buffer, &length, &point);
+  CHECK_EQ("4128420500802942", buffer.start());
+  CHECK_EQ(-8, point);
+
+  v = 3.9292015898194142585311918e-10;
+  BignumDtoa(v, BIGNUM_DTOA_SHORTEST, 0, buffer, &length, &point);
+  CHECK_EQ("39292015898194143", buffer.start());
+
+  v = 4194304.0;
+  BignumDtoa(v, BIGNUM_DTOA_FIXED, 5, buffer, &length, &point);
+  CHECK_GE(5, length - point);
+  TrimRepresentation(buffer);
+  CHECK_EQ("4194304", buffer.start());
+
+  v = 3.3161339052167390562200598e-237;
+  BignumDtoa(v, BIGNUM_DTOA_PRECISION, 19, buffer, &length, &point);
+  CHECK_GE(19, length);
+  TrimRepresentation(buffer);
+  CHECK_EQ("3316133905216739056", buffer.start());
+  CHECK_EQ(-236, point);
+
+  v = 7.9885183916008099497815232e+191;
+  BignumDtoa(v, BIGNUM_DTOA_PRECISION, 4, buffer, &length, &point);
+  CHECK_GE(4, length);
+  TrimRepresentation(buffer);
+  CHECK_EQ("7989", buffer.start());
+  CHECK_EQ(192, point);
+
+  v = 1.0000000000000012800000000e+17;
+  BignumDtoa(v, BIGNUM_DTOA_FIXED, 1, buffer, &length, &point);
+  CHECK_GE(1, length - point);
+  TrimRepresentation(buffer);
+  CHECK_EQ("100000000000000128", buffer.start());
+  CHECK_EQ(18, point);
+}
+
+
+TEST(BignumDtoaGayShortest) {
+  char buffer_container[kBufferSize];
+  Vector<char> buffer(buffer_container, kBufferSize);
+  int length;
+  int point;
+
+  Vector<const PrecomputedShortest> precomputed =
+      PrecomputedShortestRepresentations();
+  for (int i = 0; i < precomputed.length(); ++i) {
+    const PrecomputedShortest current_test = precomputed[i];
+    double v = current_test.v;
+    BignumDtoa(v, BIGNUM_DTOA_SHORTEST, 0, buffer, &length, &point);
+    CHECK_EQ(current_test.decimal_point, point);
+    CHECK_EQ(current_test.representation, buffer.start());
+  }
+}
+
+
+TEST(BignumDtoaGayFixed) {
+  char buffer_container[kBufferSize];
+  Vector<char> buffer(buffer_container, kBufferSize);
+  int length;
+  int point;
+
+  Vector<const PrecomputedFixed> precomputed =
+      PrecomputedFixedRepresentations();
+  for (int i = 0; i < precomputed.length(); ++i) {
+    const PrecomputedFixed current_test = precomputed[i];
+    double v = current_test.v;
+    int number_digits = current_test.number_digits;
+    BignumDtoa(v, BIGNUM_DTOA_FIXED, number_digits, buffer, &length, &point);
+    CHECK_EQ(current_test.decimal_point, point);
+    CHECK_GE(number_digits, length - point);
+    TrimRepresentation(buffer);
+    CHECK_EQ(current_test.representation, buffer.start());
+  }
+}
+
+
+TEST(BignumDtoaGayPrecision) {
+  char buffer_container[kBufferSize];
+  Vector<char> buffer(buffer_container, kBufferSize);
+  int length;
+  int point;
+
+  Vector<const PrecomputedPrecision> precomputed =
+      PrecomputedPrecisionRepresentations();
+  for (int i = 0; i < precomputed.length(); ++i) {
+    const PrecomputedPrecision current_test = precomputed[i];
+    double v = current_test.v;
+    int number_digits = current_test.number_digits;
+    BignumDtoa(v, BIGNUM_DTOA_PRECISION, number_digits,
+               buffer, &length, &point);
+    CHECK_EQ(current_test.decimal_point, point);
+    CHECK_GE(number_digits, length);
+    TrimRepresentation(buffer);
+    CHECK_EQ(current_test.representation, buffer.start());
+  }
+}
diff --git a/deps/v8/test/cctest/test-bignum.cc b/deps/v8/test/cctest/test-bignum.cc
new file mode 100644 (file)
index 0000000..9aa5ef3
--- /dev/null
@@ -0,0 +1,1502 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "platform.h"
+#include "cctest.h"
+#include "bignum.h"
+
+using namespace v8::internal;
+
+
+static const int kBufferSize = 1024;
+
+static void AssignHexString(Bignum* bignum, const char* str) {
+  bignum->AssignHexString(Vector<const char>(str, StrLength(str)));
+}
+
+
+static void AssignDecimalString(Bignum* bignum, const char* str) {
+  bignum->AssignDecimalString(Vector<const char>(str, StrLength(str)));
+}
+
+
+TEST(Assign) {
+  char buffer[kBufferSize];
+  Bignum bignum;
+  Bignum bignum2;
+  bignum.AssignUInt16(0);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("0", buffer);
+  bignum.AssignUInt16(0xA);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("A", buffer);
+  bignum.AssignUInt16(0x20);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("20", buffer);
+
+
+  bignum.AssignUInt64(0);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("0", buffer);
+  bignum.AssignUInt64(0xA);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("A", buffer);
+  bignum.AssignUInt64(0x20);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("20", buffer);
+  bignum.AssignUInt64(0x100);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("100", buffer);
+
+  // The first real test, since this will not fit into one bigit.
+  bignum.AssignUInt64(0x12345678);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("12345678", buffer);
+
+  uint64_t big = V8_2PART_UINT64_C(0xFFFFFFFF, FFFFFFFF);
+  bignum.AssignUInt64(big);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFFFFFFFFFFFFFF", buffer);
+
+  big = V8_2PART_UINT64_C(0x12345678, 9ABCDEF0);
+  bignum.AssignUInt64(big);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("123456789ABCDEF0", buffer);
+
+  bignum2.AssignBignum(bignum);
+  CHECK(bignum2.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("123456789ABCDEF0", buffer);
+
+  AssignDecimalString(&bignum, "0");
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("0", buffer);
+
+  AssignDecimalString(&bignum, "1");
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1", buffer);
+
+  AssignDecimalString(&bignum, "1234567890");
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("499602D2", buffer);
+
+  AssignHexString(&bignum, "0");
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("0", buffer);
+
+  AssignHexString(&bignum, "123456789ABCDEF0");
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("123456789ABCDEF0", buffer);
+}
+
+
+TEST(ShiftLeft) {
+  char buffer[kBufferSize];
+  Bignum bignum;
+  AssignHexString(&bignum, "0");
+  bignum.ShiftLeft(100);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("0", buffer);
+
+  AssignHexString(&bignum, "1");
+  bignum.ShiftLeft(1);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("2", buffer);
+
+  AssignHexString(&bignum, "1");
+  bignum.ShiftLeft(4);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10", buffer);
+
+  AssignHexString(&bignum, "1");
+  bignum.ShiftLeft(32);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("100000000", buffer);
+
+  AssignHexString(&bignum, "1");
+  bignum.ShiftLeft(64);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000000000000", buffer);
+
+  AssignHexString(&bignum, "123456789ABCDEF");
+  bignum.ShiftLeft(64);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("123456789ABCDEF0000000000000000", buffer);
+  bignum.ShiftLeft(1);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("2468ACF13579BDE0000000000000000", buffer);
+}
+
+
+TEST(AddUInt64) {
+  char buffer[kBufferSize];
+  Bignum bignum;
+  AssignHexString(&bignum, "0");
+  bignum.AddUInt64(0xA);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("A", buffer);
+
+  AssignHexString(&bignum, "1");
+  bignum.AddUInt64(0xA);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("B", buffer);
+
+  AssignHexString(&bignum, "1");
+  bignum.AddUInt64(0x100);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("101", buffer);
+
+  AssignHexString(&bignum, "1");
+  bignum.AddUInt64(0xFFFF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000", buffer);
+
+  AssignHexString(&bignum, "FFFFFFF");
+  bignum.AddUInt64(0x1);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000", buffer);
+
+  AssignHexString(&bignum, "10000000000000000000000000000000000000000000");
+  bignum.AddUInt64(0xFFFF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1000000000000000000000000000000000000000FFFF", buffer);
+
+  AssignHexString(&bignum, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+  bignum.AddUInt64(0x1);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("100000000000000000000000000000000000000000000", buffer);
+
+  bignum.AssignUInt16(0x1);
+  bignum.ShiftLeft(100);
+  bignum.AddUInt64(1);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000000000000000000001", buffer);
+
+  bignum.AssignUInt16(0x1);
+  bignum.ShiftLeft(100);
+  bignum.AddUInt64(0xFFFF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1000000000000000000000FFFF", buffer);
+
+  AssignHexString(&bignum, "0");
+  bignum.AddUInt64(V8_2PART_UINT64_C(0xA, 00000000));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("A00000000", buffer);
+
+  AssignHexString(&bignum, "1");
+  bignum.AddUInt64(V8_2PART_UINT64_C(0xA, 00000000));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("A00000001", buffer);
+
+  AssignHexString(&bignum, "1");
+  bignum.AddUInt64(V8_2PART_UINT64_C(0x100, 00000000));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000001", buffer);
+
+  AssignHexString(&bignum, "1");
+  bignum.AddUInt64(V8_2PART_UINT64_C(0xFFFF, 00000000));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFF00000001", buffer);
+
+  AssignHexString(&bignum, "FFFFFFF");
+  bignum.AddUInt64(V8_2PART_UINT64_C(0x1, 00000000));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10FFFFFFF", buffer);
+
+  AssignHexString(&bignum, "10000000000000000000000000000000000000000000");
+  bignum.AddUInt64(V8_2PART_UINT64_C(0xFFFF, 00000000));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000000000000000000000000000FFFF00000000", buffer);
+
+  AssignHexString(&bignum, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+  bignum.AddUInt64(V8_2PART_UINT64_C(0x1, 00000000));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1000000000000000000000000000000000000FFFFFFFF", buffer);
+
+  bignum.AssignUInt16(0x1);
+  bignum.ShiftLeft(100);
+  bignum.AddUInt64(V8_2PART_UINT64_C(0x1, 00000000));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000000000000100000000", buffer);
+
+  bignum.AssignUInt16(0x1);
+  bignum.ShiftLeft(100);
+  bignum.AddUInt64(V8_2PART_UINT64_C(0xFFFF, 00000000));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000000000FFFF00000000", buffer);
+}
+
+
+TEST(AddBignum) {
+  char buffer[kBufferSize];
+  Bignum bignum;
+  Bignum other;
+
+  AssignHexString(&other, "1");
+  AssignHexString(&bignum, "0");
+  bignum.AddBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1", buffer);
+
+  AssignHexString(&bignum, "1");
+  bignum.AddBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("2", buffer);
+
+  AssignHexString(&bignum, "FFFFFFF");
+  bignum.AddBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000", buffer);
+
+  AssignHexString(&bignum, "FFFFFFFFFFFFFF");
+  bignum.AddBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("100000000000000", buffer);
+
+  AssignHexString(&bignum, "10000000000000000000000000000000000000000000");
+  bignum.AddBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000000000000000000000000000000000000001", buffer);
+
+  AssignHexString(&other, "1000000000000");
+
+  AssignHexString(&bignum, "1");
+  bignum.AddBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1000000000001", buffer);
+
+  AssignHexString(&bignum, "FFFFFFF");
+  bignum.AddBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("100000FFFFFFF", buffer);
+
+  AssignHexString(&bignum, "10000000000000000000000000000000000000000000");
+  bignum.AddBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000000000000000000000000001000000000000", buffer);
+
+  AssignHexString(&bignum, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+  bignum.AddBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1000000000000000000000000000000FFFFFFFFFFFF", buffer);
+
+  bignum.AssignUInt16(0x1);
+  bignum.ShiftLeft(100);
+  bignum.AddBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000000001000000000000", buffer);
+
+  other.ShiftLeft(64);
+  // other == "10000000000000000000000000000"
+
+  bignum.AssignUInt16(0x1);
+  bignum.AddBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000000000000000000000001", buffer);
+
+  AssignHexString(&bignum, "FFFFFFF");
+  bignum.AddBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1000000000000000000000FFFFFFF", buffer);
+
+  AssignHexString(&bignum, "10000000000000000000000000000000000000000000");
+  bignum.AddBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000000000010000000000000000000000000000", buffer);
+
+  AssignHexString(&bignum, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+  bignum.AddBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("100000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFF", buffer);
+
+  bignum.AssignUInt16(0x1);
+  bignum.ShiftLeft(100);
+  bignum.AddBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10010000000000000000000000000", buffer);
+}
+
+
+TEST(SubtractBignum) {
+  char buffer[kBufferSize];
+  Bignum bignum;
+  Bignum other;
+
+  AssignHexString(&bignum, "1");
+  AssignHexString(&other, "0");
+  bignum.SubtractBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1", buffer);
+
+  AssignHexString(&bignum, "2");
+  AssignHexString(&other, "0");
+  bignum.SubtractBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("2", buffer);
+
+  AssignHexString(&bignum, "10000000");
+  AssignHexString(&other, "1");
+  bignum.SubtractBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFFFFF", buffer);
+
+  AssignHexString(&bignum, "100000000000000");
+  AssignHexString(&other, "1");
+  bignum.SubtractBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFFFFFFFFFFFF", buffer);
+
+  AssignHexString(&bignum, "10000000000000000000000000000000000000000001");
+  AssignHexString(&other, "1");
+  bignum.SubtractBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000000000000000000000000000000000000000", buffer);
+
+  AssignHexString(&bignum, "1000000000001");
+  AssignHexString(&other, "1000000000000");
+  bignum.SubtractBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1", buffer);
+
+  AssignHexString(&bignum, "100000FFFFFFF");
+  AssignHexString(&other, "1000000000000");
+  bignum.SubtractBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFFFFF", buffer);
+
+  AssignHexString(&bignum, "10000000000000000000000000000001000000000000");
+  AssignHexString(&other, "1000000000000");
+  bignum.SubtractBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000000000000000000000000000000000000000", buffer);
+
+  AssignHexString(&bignum, "1000000000000000000000000000000FFFFFFFFFFFF");
+  AssignHexString(&other, "1000000000000");
+  bignum.SubtractBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", buffer);
+
+  bignum.AssignUInt16(0x1);
+  bignum.ShiftLeft(100);
+  // "10 0000 0000 0000 0000 0000 0000"
+  AssignHexString(&other, "1000000000000");
+  bignum.SubtractBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFFFFFFFFFFF000000000000", buffer);
+
+  AssignHexString(&other, "1000000000000");
+  other.ShiftLeft(48);
+  // other == "1000000000000000000000000"
+
+  bignum.AssignUInt16(0x1);
+  bignum.ShiftLeft(100);
+  // bignum == "10000000000000000000000000"
+  bignum.SubtractBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("F000000000000000000000000", buffer);
+
+  other.AssignUInt16(0x1);
+  other.ShiftLeft(35);
+  // other == "800000000"
+  AssignHexString(&bignum, "FFFFFFF");
+  bignum.ShiftLeft(60);
+  // bignum = FFFFFFF000000000000000
+  bignum.SubtractBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFFFFEFFFFFF800000000", buffer);
+
+  AssignHexString(&bignum, "10000000000000000000000000000000000000000000");
+  bignum.SubtractBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF800000000", buffer);
+
+  AssignHexString(&bignum, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+  bignum.SubtractBignum(other);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFF", buffer);
+}
+
+
+TEST(MultiplyUInt32) {
+  char buffer[kBufferSize];
+  Bignum bignum;
+
+  AssignHexString(&bignum, "0");
+  bignum.MultiplyByUInt32(0x25);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("0", buffer);
+
+  AssignHexString(&bignum, "2");
+  bignum.MultiplyByUInt32(0x5);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("A", buffer);
+
+  AssignHexString(&bignum, "10000000");
+  bignum.MultiplyByUInt32(0x9);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("90000000", buffer);
+
+  AssignHexString(&bignum, "100000000000000");
+  bignum.MultiplyByUInt32(0xFFFF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFF00000000000000", buffer);
+
+  AssignHexString(&bignum, "100000000000000");
+  bignum.MultiplyByUInt32(0xFFFFFFFF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFFFFFF00000000000000", buffer);
+
+  AssignHexString(&bignum, "1234567ABCD");
+  bignum.MultiplyByUInt32(0xFFF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("12333335552433", buffer);
+
+  AssignHexString(&bignum, "1234567ABCD");
+  bignum.MultiplyByUInt32(0xFFFFFFF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("12345679998A985433", buffer);
+
+  AssignHexString(&bignum, "FFFFFFFFFFFFFFFF");
+  bignum.MultiplyByUInt32(0x2);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1FFFFFFFFFFFFFFFE", buffer);
+
+  AssignHexString(&bignum, "FFFFFFFFFFFFFFFF");
+  bignum.MultiplyByUInt32(0x4);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("3FFFFFFFFFFFFFFFC", buffer);
+
+  AssignHexString(&bignum, "FFFFFFFFFFFFFFFF");
+  bignum.MultiplyByUInt32(0xF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("EFFFFFFFFFFFFFFF1", buffer);
+
+  AssignHexString(&bignum, "FFFFFFFFFFFFFFFF");
+  bignum.MultiplyByUInt32(0xFFFFFF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFFFEFFFFFFFFFF000001", buffer);
+
+  bignum.AssignUInt16(0x1);
+  bignum.ShiftLeft(100);
+  // "10 0000 0000 0000 0000 0000 0000"
+  bignum.MultiplyByUInt32(2);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("20000000000000000000000000", buffer);
+
+  bignum.AssignUInt16(0x1);
+  bignum.ShiftLeft(100);
+  // "10 0000 0000 0000 0000 0000 0000"
+  bignum.MultiplyByUInt32(0xF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("F0000000000000000000000000", buffer);
+
+  bignum.AssignUInt16(0xFFFF);
+  bignum.ShiftLeft(100);
+  // "FFFF0 0000 0000 0000 0000 0000 0000"
+  bignum.MultiplyByUInt32(0xFFFF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFE00010000000000000000000000000", buffer);
+
+  bignum.AssignUInt16(0xFFFF);
+  bignum.ShiftLeft(100);
+  // "FFFF0 0000 0000 0000 0000 0000 0000"
+  bignum.MultiplyByUInt32(0xFFFFFFFF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFEFFFF00010000000000000000000000000", buffer);
+
+  bignum.AssignUInt16(0xFFFF);
+  bignum.ShiftLeft(100);
+  // "FFFF0 0000 0000 0000 0000 0000 0000"
+  bignum.MultiplyByUInt32(0xFFFFFFFF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFEFFFF00010000000000000000000000000", buffer);
+
+  AssignDecimalString(&bignum, "15611230384529777");
+  bignum.MultiplyByUInt32(10000000);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("210EDD6D4CDD2580EE80", buffer);
+}
+
+
+TEST(MultiplyUInt64) {
+  char buffer[kBufferSize];
+  Bignum bignum;
+
+  AssignHexString(&bignum, "0");
+  bignum.MultiplyByUInt64(0x25);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("0", buffer);
+
+  AssignHexString(&bignum, "2");
+  bignum.MultiplyByUInt64(0x5);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("A", buffer);
+
+  AssignHexString(&bignum, "10000000");
+  bignum.MultiplyByUInt64(0x9);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("90000000", buffer);
+
+  AssignHexString(&bignum, "100000000000000");
+  bignum.MultiplyByUInt64(0xFFFF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFF00000000000000", buffer);
+
+  AssignHexString(&bignum, "100000000000000");
+  bignum.MultiplyByUInt64(V8_2PART_UINT64_C(0xFFFFFFFF, FFFFFFFF));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFFFFFFFFFFFFFF00000000000000", buffer);
+
+  AssignHexString(&bignum, "1234567ABCD");
+  bignum.MultiplyByUInt64(0xFFF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("12333335552433", buffer);
+
+  AssignHexString(&bignum, "1234567ABCD");
+  bignum.MultiplyByUInt64(V8_2PART_UINT64_C(0xFF, FFFFFFFF));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1234567ABCBDCBA985433", buffer);
+
+  AssignHexString(&bignum, "FFFFFFFFFFFFFFFF");
+  bignum.MultiplyByUInt64(0x2);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1FFFFFFFFFFFFFFFE", buffer);
+
+  AssignHexString(&bignum, "FFFFFFFFFFFFFFFF");
+  bignum.MultiplyByUInt64(0x4);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("3FFFFFFFFFFFFFFFC", buffer);
+
+  AssignHexString(&bignum, "FFFFFFFFFFFFFFFF");
+  bignum.MultiplyByUInt64(0xF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("EFFFFFFFFFFFFFFF1", buffer);
+
+  AssignHexString(&bignum, "FFFFFFFFFFFFFFFF");
+  bignum.MultiplyByUInt64(V8_2PART_UINT64_C(0xFFFFFFFF, FFFFFFFF));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFFFFFFFFFFFFFE0000000000000001", buffer);
+
+  bignum.AssignUInt16(0x1);
+  bignum.ShiftLeft(100);
+  // "10 0000 0000 0000 0000 0000 0000"
+  bignum.MultiplyByUInt64(2);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("20000000000000000000000000", buffer);
+
+  bignum.AssignUInt16(0x1);
+  bignum.ShiftLeft(100);
+  // "10 0000 0000 0000 0000 0000 0000"
+  bignum.MultiplyByUInt64(0xF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("F0000000000000000000000000", buffer);
+
+  bignum.AssignUInt16(0xFFFF);
+  bignum.ShiftLeft(100);
+  // "FFFF0 0000 0000 0000 0000 0000 0000"
+  bignum.MultiplyByUInt64(0xFFFF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFE00010000000000000000000000000", buffer);
+
+  bignum.AssignUInt16(0xFFFF);
+  bignum.ShiftLeft(100);
+  // "FFFF0 0000 0000 0000 0000 0000 0000"
+  bignum.MultiplyByUInt64(0xFFFFFFFF);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFEFFFF00010000000000000000000000000", buffer);
+
+  bignum.AssignUInt16(0xFFFF);
+  bignum.ShiftLeft(100);
+  // "FFFF0 0000 0000 0000 0000 0000 0000"
+  bignum.MultiplyByUInt64(V8_2PART_UINT64_C(0xFFFFFFFF, FFFFFFFF));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFEFFFFFFFFFFFF00010000000000000000000000000", buffer);
+
+  AssignDecimalString(&bignum, "15611230384529777");
+  bignum.MultiplyByUInt64(V8_2PART_UINT64_C(0x8ac72304, 89e80000));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1E10EE4B11D15A7F3DE7F3C7680000", buffer);
+}
+
+
+TEST(MultiplyPowerOfTen) {
+  char buffer[kBufferSize];
+  Bignum bignum;
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(1);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("3034", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(2);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1E208", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(3);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("12D450", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(4);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("BC4B20", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(5);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("75AEF40", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(6);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("498D5880", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(7);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("2DF857500", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(8);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1CBB369200", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(9);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("11F5021B400", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(10);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("B3921510800", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(11);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("703B4D2A5000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(12);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("4625103A72000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(13);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("2BD72A24874000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(14);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1B667A56D488000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(15);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("11200C7644D50000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(16);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("AB407C9EB0520000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(17);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("6B084DE32E3340000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(18);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("42E530ADFCE0080000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(19);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("29CF3E6CBE0C0500000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(20);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1A218703F6C783200000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(21);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1054F4627A3CB1F400000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(22);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("A3518BD8C65EF38800000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(23);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("6612F7677BFB5835000000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(24);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("3FCBDAA0AD7D17212000000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(25);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("27DF68A46C6E2E74B4000000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(26);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("18EBA166C3C4DD08F08000000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(27);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("F9344E03A5B0A259650000000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(28);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("9BC0B0C2478E6577DF20000000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(29);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("61586E796CB8FF6AEB740000000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(30);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("3CD7450BE3F39FA2D32880000000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(31);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("26068B276E7843C5C3F9500000000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(50);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("149D1B4CFED03B23AB5F4E1196EF45C08000000000000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(100);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("5827249F27165024FBC47DFCA9359BF316332D1B91ACEECF471FBAB06D9B2"
+           "0000000000000000000000000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(200);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("64C1F5C06C3816AFBF8DAFD5A3D756365BB0FD020E6F084E759C1F7C99E4F"
+           "55B9ACC667CEC477EB958C2AEEB3C6C19BA35A1AD30B35C51EB72040920000"
+           "0000000000000000000000000000000000000000000000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(500);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("96741A625EB5D7C91039FEB5C5ACD6D9831EDA5B083D800E6019442C8C8223"
+           "3EAFB3501FE2058062221E15121334928880827DEE1EC337A8B26489F3A40A"
+           "CB440A2423734472D10BFCE886F41B3AF9F9503013D86D088929CA86EEB4D8"
+           "B9C831D0BD53327B994A0326227CFD0ECBF2EB48B02387AAE2D4CCCDF1F1A1"
+           "B8CC4F1FA2C56AD40D0E4DAA9C28CDBF0A549098EA13200000000000000000"
+           "00000000000000000000000000000000000000000000000000000000000000"
+           "0000000000000000000000000000000000000000000000", buffer);
+
+  AssignDecimalString(&bignum, "1234");
+  bignum.MultiplyByPowerOfTen(1000);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1258040F99B1CD1CC9819C676D413EA50E4A6A8F114BB0C65418C62D399B81"
+           "6361466CA8E095193E1EE97173553597C96673AF67FAFE27A66E7EF2E5EF2E"
+           "E3F5F5070CC17FE83BA53D40A66A666A02F9E00B0E11328D2224B8694C7372"
+           "F3D536A0AD1985911BD361496F268E8B23112500EAF9B88A9BC67B2AB04D38"
+           "7FEFACD00F5AF4F764F9ABC3ABCDE54612DE38CD90CB6647CA389EA0E86B16"
+           "BF7A1F34086E05ADBE00BD1673BE00FAC4B34AF1091E8AD50BA675E0381440"
+           "EA8E9D93E75D816BAB37C9844B1441C38FC65CF30ABB71B36433AF26DD97BD"
+           "ABBA96C03B4919B8F3515B92826B85462833380DC193D79F69D20DD6038C99"
+           "6114EF6C446F0BA28CC772ACBA58B81C04F8FFDE7B18C4E5A3ABC51E637FDF"
+           "6E37FDFF04C940919390F4FF92000000000000000000000000000000000000"
+           "00000000000000000000000000000000000000000000000000000000000000"
+           "00000000000000000000000000000000000000000000000000000000000000"
+           "00000000000000000000000000000000000000000000000000000000000000"
+           "0000000000000000000000000000", buffer);
+
+  Bignum bignum2;
+  AssignHexString(&bignum2, "3DA774C07FB5DF54284D09C675A492165B830D5DAAEB2A7501"
+                            "DA17CF9DFA1CA2282269F92A25A97314296B717E3DCBB9FE17"
+                            "41A842FE2913F540F40796F2381155763502C58B15AF7A7F88"
+                            "6F744C9164FF409A28F7FA0C41F89ED79C1BE9F322C8578B97"
+                            "841F1CBAA17D901BE1230E3C00E1C643AF32638B5674E01FEA"
+                            "96FC90864E621B856A9E1CE56E6EB545B9C2F8F0CC10DDA88D"
+                            "CC6D282605F8DB67044F2DFD3695E7BA63877AE16701536AE6"
+                            "567C794D0BFE338DFBB42D92D4215AF3BB22BF0A8B283FDDC2"
+                            "C667A10958EA6D2");
+  CHECK(bignum2.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("3DA774C07FB5DF54284D09C675A492165B830D5DAAEB2A7501"
+           "DA17CF9DFA1CA2282269F92A25A97314296B717E3DCBB9FE17"
+           "41A842FE2913F540F40796F2381155763502C58B15AF7A7F88"
+           "6F744C9164FF409A28F7FA0C41F89ED79C1BE9F322C8578B97"
+           "841F1CBAA17D901BE1230E3C00E1C643AF32638B5674E01FEA"
+           "96FC90864E621B856A9E1CE56E6EB545B9C2F8F0CC10DDA88D"
+           "CC6D282605F8DB67044F2DFD3695E7BA63877AE16701536AE6"
+           "567C794D0BFE338DFBB42D92D4215AF3BB22BF0A8B283FDDC2"
+           "C667A10958EA6D2", buffer);
+
+  bignum.AssignBignum(bignum2);
+  bignum.MultiplyByPowerOfTen(1);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("2688A8F84FD1AB949930261C0986DB4DF931E85A8AD2FA8921284EE1C2BC51"
+           "E55915823BBA5789E7EC99E326EEE69F543ECE890929DED9AC79489884BE57"
+           "630AD569E121BB76ED8DAC8FB545A8AFDADF1F8860599AFC47A93B6346C191"
+           "7237F5BD36B73EB29371F4A4EE7A116CB5E8E5808D1BEA4D7F7E3716090C13"
+           "F29E5DDA53F0FD513362A2D20F6505314B9419DB967F8A8A89589FC43917C3"
+           "BB892062B17CBE421DB0D47E34ACCCE060D422CFF60DCBD0277EE038BD509C"
+           "7BC494D8D854F5B76696F927EA99BC00C4A5D7928434", buffer);
+
+  bignum.AssignBignum(bignum2);
+  bignum.MultiplyByPowerOfTen(2);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1815699B31E30B3CDFBE17D185F44910BBBF313896C3DC95B4B9314D19B5B32"
+           "F57AD71655476B630F3E02DF855502394A74115A5BA2B480BCBCD5F52F6F69D"
+           "E6C5622CB5152A54788BD9D14B896DE8CB73B53C3800DDACC9C51E0C38FAE76"
+           "2F9964232872F9C2738E7150C4AE3F1B18F70583172706FAEE26DC5A78C77A2"
+           "FAA874769E52C01DA5C3499F233ECF3C90293E0FB69695D763DAA3AEDA5535B"
+           "43DAEEDF6E9528E84CEE0EC000C3C8495C1F9C89F6218AF4C23765261CD5ADD"
+           "0787351992A01E5BB8F2A015807AE7A6BB92A08", buffer);
+
+  bignum.AssignBignum(bignum2);
+  bignum.MultiplyByPowerOfTen(5);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("5E13A4863ADEE3E5C9FE8D0A73423D695D62D8450CED15A8C9F368952C6DC3"
+           "F0EE7D82F3D1EFB7AF38A3B3920D410AFCAD563C8F5F39116E141A3C5C14B3"
+           "58CD73077EA35AAD59F6E24AD98F10D5555ABBFBF33AC361EAF429FD5FBE94"
+           "17DA9EF2F2956011F9F93646AA38048A681D984ED88127073443247CCC167C"
+           "B354A32206EF5A733E73CF82D795A1AD598493211A6D613C39515E0E0F6304"
+           "DCD9C810F3518C7F6A7CB6C81E99E02FCC65E8FDB7B7AE97306CC16A8631CE"
+           "0A2AEF6568276BE4C176964A73C153FDE018E34CB4C2F40", buffer);
+
+  bignum.AssignBignum(bignum2);
+  bignum.MultiplyByPowerOfTen(10);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("8F8CB8EB51945A7E815809F6121EF2F4E61EF3405CD9432CAD2709749EEAFD"
+           "1B81E843F14A3667A7BDCCC9E0BB795F63CDFDB62844AC7438976C885A0116"
+           "29607DA54F9C023CC366570B7637ED0F855D931752038A614922D0923E382C"
+           "B8E5F6C975672DB76E0DE471937BB9EDB11E28874F1C122D5E1EF38CECE9D0"
+           "0723056BCBD4F964192B76830634B1D322B7EB0062F3267E84F5C824343A77"
+           "4B7DCEE6DD464F01EBDC8C671BB18BB4EF4300A42474A6C77243F2A12B03BF"
+           "0443C38A1C0D2701EDB393135AE0DEC94211F9D4EB51F990800", buffer);
+
+  bignum.AssignBignum(bignum2);
+  bignum.MultiplyByPowerOfTen(50);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("107A8BE345E24407372FC1DE442CBA696BC23C4FFD5B4BDFD9E5C39559815"
+           "86628CF8472D2D589F2FC2BAD6E0816EC72CBF85CCA663D8A1EC6C51076D8"
+           "2D247E6C26811B7EC4D4300FB1F91028DCB7B2C4E7A60C151161AA7E65E79"
+           "B40917B12B2B5FBE7745984D4E8EFA31F9AE6062427B068B144A9CB155873"
+           "E7C0C9F0115E5AC72DC5A73C4796DB970BF9205AB8C77A6996EB1B417F9D1"
+           "6232431E6313C392203601B9C22CC10DDA88DCC6D282605F8DB67044F2DFD"
+           "3695E7BA63877AE16701536AE6567C794D0BFE338DFBB42D924CF964BD2C0"
+           "F586E03A2FCD35A408000000000000", buffer);
+
+  bignum.AssignBignum(bignum2);
+  bignum.MultiplyByPowerOfTen(100);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("46784A90ACD0ED3E7759CC585FB32D36EB6034A6F78D92604E3BAA5ED3D8B"
+           "6E60E854439BE448897FB4B7EA5A3D873AA0FCB3CFFD80D0530880E45F511"
+           "722A50CE7E058B5A6F5464DB7500E34984EE3202A9441F44FA1554C0CEA96"
+           "B438A36F25E7C9D56D71AE2CD313EC37534DA299AC0854FC48591A7CF3171"
+           "31265AA4AE62DE32344CE7BEEEF894AE686A2DAAFE5D6D9A10971FFD9C064"
+           "5079B209E1048F58B5192D41D84336AC4C8C489EEF00939CFC9D55C122036"
+           "01B9C22CC10DDA88DCC6D282605F8DB67044F2DFD3695E7BA3F67B96D3A32"
+           "E11FB5561B68744C4035B0800DC166D49D98E3FD1D5BB2000000000000000"
+           "0000000000", buffer);
+
+  bignum.AssignBignum(bignum2);
+  bignum.MultiplyByPowerOfTen(200);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("508BD351221DF139D72D88CDC0416845A53EE2D0E6B98352509A9AC312F8C"
+           "6CB1A144889416201E0B6CE66EA3EBE259B5FD79ECFC1FD77963CE516CC7E"
+           "2FE73D4B5B710C19F6BCB092C7A2FD76286543B8DBD2C596DFF2C896720BA"
+           "DFF7BC9C366ACEA3A880AEC287C5E6207DF2739B5326FC19D773BD830B109"
+           "ED36C7086544BF8FDB9D4B73719C2B5BC2F571A5937EC46876CD428281F6B"
+           "F287E1E07F25C1B1D46BC37324FF657A8B2E0071DB83B86123CA34004F406"
+           "001082D7945E90C6E8C9A9FEC2B44BE0DDA46E9F52B152E4D1336D2FCFBC9"
+           "96E30CA0082256737365158FE36482AA7EB9DAF2AB128F10E7551A3CD5BE6"
+           "0A922F3A7D5EED38B634A7EC95BCF7021BA6820A292000000000000000000"
+           "00000000000000000000000000000000", buffer);
+
+  bignum.AssignBignum(bignum2);
+  bignum.MultiplyByPowerOfTen(500);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("7845F900E475B5086885BAAAE67C8E85185ACFE4633727F82A4B06B5582AC"
+           "BE933C53357DA0C98C20C5AC900C4D76A97247DF52B79F48F9E35840FB715"
+           "D392CE303E22622B0CF82D9471B398457DD3196F639CEE8BBD2C146873841"
+           "F0699E6C41F04FC7A54B48CEB995BEB6F50FE81DE9D87A8D7F849CC523553"
+           "7B7BBBC1C7CAAFF6E9650BE03B308C6D31012AEF9580F70D3EE2083ADE126"
+           "8940FA7D6308E239775DFD2F8C97FF7EBD525DAFA6512216F7047A62A93DC"
+           "38A0165BDC67E250DCC96A0181DE935A70B38704DC71819F02FC5261FF7E1"
+           "E5F11907678B0A3E519FF4C10A867B0C26CE02BE6960BA8621A87303C101C"
+           "3F88798BB9F7739655946F8B5744E6B1EAF10B0C5621330F0079209033C69"
+           "20DE2E2C8D324F0624463735D482BF291926C22A910F5B80FA25170B6B57D"
+           "8D5928C7BCA3FE87461275F69BD5A1B83181DAAF43E05FC3C72C4E93111B6"
+           "6205EBF49B28FEDFB7E7526CBDA658A332000000000000000000000000000"
+           "0000000000000000000000000000000000000000000000000000000000000"
+           "0000000000000000000000000000000000000", buffer);
+}
+
+
+TEST(DivideModuloIntBignum) {
+  char buffer[kBufferSize];
+  Bignum bignum;
+  Bignum other;
+  Bignum third;
+
+  bignum.AssignUInt16(10);
+  other.AssignUInt16(2);
+  CHECK_EQ(5, bignum.DivideModuloIntBignum(other));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("0", buffer);
+
+  bignum.AssignUInt16(10);
+  bignum.ShiftLeft(500);
+  other.AssignUInt16(2);
+  other.ShiftLeft(500);
+  CHECK_EQ(5, bignum.DivideModuloIntBignum(other));
+  CHECK_EQ("0", buffer);
+
+  bignum.AssignUInt16(11);
+  other.AssignUInt16(2);
+  CHECK_EQ(5, bignum.DivideModuloIntBignum(other));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1", buffer);
+
+  bignum.AssignUInt16(10);
+  bignum.ShiftLeft(500);
+  other.AssignUInt16(1);
+  bignum.AddBignum(other);
+  other.AssignUInt16(2);
+  other.ShiftLeft(500);
+  CHECK_EQ(5, bignum.DivideModuloIntBignum(other));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1", buffer);
+
+  bignum.AssignUInt16(10);
+  bignum.ShiftLeft(500);
+  other.AssignBignum(bignum);
+  bignum.MultiplyByUInt32(0x1234);
+  third.AssignUInt16(0xFFF);
+  bignum.AddBignum(third);
+  CHECK_EQ(0x1234, bignum.DivideModuloIntBignum(other));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFF", buffer);
+
+  bignum.AssignUInt16(10);
+  AssignHexString(&other, "1234567890");
+  CHECK_EQ(0, bignum.DivideModuloIntBignum(other));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("A", buffer);
+
+  AssignHexString(&bignum, "12345678");
+  AssignHexString(&other, "3789012");
+  CHECK_EQ(5, bignum.DivideModuloIntBignum(other));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("D9861E", buffer);
+
+  AssignHexString(&bignum, "70000001");
+  AssignHexString(&other, "1FFFFFFF");
+  CHECK_EQ(3, bignum.DivideModuloIntBignum(other));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000004", buffer);
+
+  AssignHexString(&bignum, "28000000");
+  AssignHexString(&other, "12A05F20");
+  CHECK_EQ(2, bignum.DivideModuloIntBignum(other));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("2BF41C0", buffer);
+
+  bignum.AssignUInt16(10);
+  bignum.ShiftLeft(500);
+  other.AssignBignum(bignum);
+  bignum.MultiplyByUInt32(0x1234);
+  third.AssignUInt16(0xFFF);
+  other.SubtractBignum(third);
+  CHECK_EQ(0x1234, bignum.DivideModuloIntBignum(other));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1232DCC", buffer);
+  CHECK_EQ(0, bignum.DivideModuloIntBignum(other));
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1232DCC", buffer);
+}
+
+
+TEST(Compare) {
+  Bignum bignum1;
+  Bignum bignum2;
+  bignum1.AssignUInt16(1);
+  bignum2.AssignUInt16(1);
+  CHECK_EQ(0, Bignum::Compare(bignum1, bignum2));
+  CHECK(Bignum::Equal(bignum1, bignum2));
+  CHECK(Bignum::LessEqual(bignum1, bignum2));
+  CHECK(!Bignum::Less(bignum1, bignum2));
+
+  bignum1.AssignUInt16(0);
+  bignum2.AssignUInt16(1);
+  CHECK_EQ(-1, Bignum::Compare(bignum1, bignum2));
+  CHECK_EQ(+1, Bignum::Compare(bignum2, bignum1));
+  CHECK(!Bignum::Equal(bignum1, bignum2));
+  CHECK(!Bignum::Equal(bignum2, bignum1));
+  CHECK(Bignum::LessEqual(bignum1, bignum2));
+  CHECK(!Bignum::LessEqual(bignum2, bignum1));
+  CHECK(Bignum::Less(bignum1, bignum2));
+  CHECK(!Bignum::Less(bignum2, bignum1));
+
+  AssignHexString(&bignum1, "1234567890ABCDEF12345");
+  AssignHexString(&bignum2, "1234567890ABCDEF12345");
+  CHECK_EQ(0, Bignum::Compare(bignum1, bignum2));
+
+  AssignHexString(&bignum1, "1234567890ABCDEF12345");
+  AssignHexString(&bignum2, "1234567890ABCDEF12346");
+  CHECK_EQ(-1, Bignum::Compare(bignum1, bignum2));
+  CHECK_EQ(+1, Bignum::Compare(bignum2, bignum1));
+
+  AssignHexString(&bignum1, "1234567890ABCDEF12345");
+  bignum1.ShiftLeft(500);
+  AssignHexString(&bignum2, "1234567890ABCDEF12345");
+  bignum2.ShiftLeft(500);
+  CHECK_EQ(0, Bignum::Compare(bignum1, bignum2));
+
+  AssignHexString(&bignum1, "1234567890ABCDEF12345");
+  bignum1.ShiftLeft(500);
+  AssignHexString(&bignum2, "1234567890ABCDEF12346");
+  bignum2.ShiftLeft(500);
+  CHECK_EQ(-1, Bignum::Compare(bignum1, bignum2));
+  CHECK_EQ(+1, Bignum::Compare(bignum2, bignum1));
+
+  bignum1.AssignUInt16(1);
+  bignum1.ShiftLeft(64);
+  AssignHexString(&bignum2, "10000000000000000");
+  CHECK_EQ(0, Bignum::Compare(bignum1, bignum2));
+  CHECK_EQ(0, Bignum::Compare(bignum2, bignum1));
+
+  bignum1.AssignUInt16(1);
+  bignum1.ShiftLeft(64);
+  AssignHexString(&bignum2, "10000000000000001");
+  CHECK_EQ(-1, Bignum::Compare(bignum1, bignum2));
+  CHECK_EQ(+1, Bignum::Compare(bignum2, bignum1));
+
+  bignum1.AssignUInt16(1);
+  bignum1.ShiftLeft(96);
+  AssignHexString(&bignum2, "10000000000000001");
+  bignum2.ShiftLeft(32);
+  CHECK_EQ(-1, Bignum::Compare(bignum1, bignum2));
+  CHECK_EQ(+1, Bignum::Compare(bignum2, bignum1));
+
+  AssignHexString(&bignum1, "FFFFFFFFFFFFFFFF");
+  bignum2.AssignUInt16(1);
+  bignum2.ShiftLeft(64);
+  CHECK_EQ(-1, Bignum::Compare(bignum1, bignum2));
+  CHECK_EQ(+1, Bignum::Compare(bignum2, bignum1));
+
+  AssignHexString(&bignum1, "FFFFFFFFFFFFFFFF");
+  bignum1.ShiftLeft(32);
+  bignum2.AssignUInt16(1);
+  bignum2.ShiftLeft(96);
+  CHECK_EQ(-1, Bignum::Compare(bignum1, bignum2));
+  CHECK_EQ(+1, Bignum::Compare(bignum2, bignum1));
+
+  AssignHexString(&bignum1, "FFFFFFFFFFFFFFFF");
+  bignum1.ShiftLeft(32);
+  bignum2.AssignUInt16(1);
+  bignum2.ShiftLeft(95);
+  CHECK_EQ(+1, Bignum::Compare(bignum1, bignum2));
+  CHECK_EQ(-1, Bignum::Compare(bignum2, bignum1));
+
+  AssignHexString(&bignum1, "FFFFFFFFFFFFFFFF");
+  bignum1.ShiftLeft(32);
+  bignum2.AssignUInt16(1);
+  bignum2.ShiftLeft(100);
+  CHECK_EQ(-1, Bignum::Compare(bignum1, bignum2));
+  CHECK_EQ(+1, Bignum::Compare(bignum2, bignum1));
+
+  AssignHexString(&bignum1, "100000000000000");
+  bignum2.AssignUInt16(1);
+  bignum2.ShiftLeft(14*4);
+  CHECK_EQ(0, Bignum::Compare(bignum1, bignum2));
+  CHECK_EQ(0, Bignum::Compare(bignum2, bignum1));
+
+  AssignHexString(&bignum1, "100000000000001");
+  bignum2.AssignUInt16(1);
+  bignum2.ShiftLeft(14*4);
+  CHECK_EQ(+1, Bignum::Compare(bignum1, bignum2));
+  CHECK_EQ(-1, Bignum::Compare(bignum2, bignum1));
+
+  AssignHexString(&bignum1, "200000000000000");
+  bignum2.AssignUInt16(3);
+  bignum2.ShiftLeft(14*4);
+  CHECK_EQ(-1, Bignum::Compare(bignum1, bignum2));
+  CHECK_EQ(+1, Bignum::Compare(bignum2, bignum1));
+}
+
+
+TEST(PlusCompare) {
+  Bignum a;
+  Bignum b;
+  Bignum c;
+  a.AssignUInt16(1);
+  b.AssignUInt16(0);
+  c.AssignUInt16(1);
+  CHECK_EQ(0, Bignum::PlusCompare(a, b, c));
+  CHECK(Bignum::PlusEqual(a, b, c));
+  CHECK(Bignum::PlusLessEqual(a, b, c));
+  CHECK(!Bignum::PlusLess(a, b, c));
+
+  a.AssignUInt16(0);
+  b.AssignUInt16(0);
+  c.AssignUInt16(1);
+  CHECK_EQ(-1, Bignum::PlusCompare(a, b, c));
+  CHECK_EQ(+1, Bignum::PlusCompare(c, b, a));
+  CHECK(!Bignum::PlusEqual(a, b, c));
+  CHECK(!Bignum::PlusEqual(c, b, a));
+  CHECK(Bignum::PlusLessEqual(a, b, c));
+  CHECK(!Bignum::PlusLessEqual(c, b, a));
+  CHECK(Bignum::PlusLess(a, b, c));
+  CHECK(!Bignum::PlusLess(c, b, a));
+
+  AssignHexString(&a, "1234567890ABCDEF12345");
+  b.AssignUInt16(1);
+  AssignHexString(&c, "1234567890ABCDEF12345");
+  CHECK_EQ(+1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890ABCDEF12344");
+  b.AssignUInt16(1);
+  AssignHexString(&c, "1234567890ABCDEF12345");
+  CHECK_EQ(0, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4);
+  AssignHexString(&b, "ABCDEF12345");
+  AssignHexString(&c, "1234567890ABCDEF12345");
+  CHECK_EQ(0, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4);
+  AssignHexString(&b, "ABCDEF12344");
+  AssignHexString(&c, "1234567890ABCDEF12345");
+  CHECK_EQ(-1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4);
+  AssignHexString(&b, "ABCDEF12346");
+  AssignHexString(&c, "1234567890ABCDEF12345");
+  CHECK_EQ(1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567891");
+  a.ShiftLeft(11*4);
+  AssignHexString(&b, "ABCDEF12345");
+  AssignHexString(&c, "1234567890ABCDEF12345");
+  CHECK_EQ(1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567889");
+  a.ShiftLeft(11*4);
+  AssignHexString(&b, "ABCDEF12345");
+  AssignHexString(&c, "1234567890ABCDEF12345");
+  CHECK_EQ(-1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12345");
+  b.ShiftLeft(32);
+  AssignHexString(&c, "1234567890ABCDEF12345");
+  c.ShiftLeft(32);
+  CHECK_EQ(0, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12344");
+  b.ShiftLeft(32);
+  AssignHexString(&c, "1234567890ABCDEF12345");
+  c.ShiftLeft(32);
+  CHECK_EQ(-1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12346");
+  b.ShiftLeft(32);
+  AssignHexString(&c, "1234567890ABCDEF12345");
+  c.ShiftLeft(32);
+  CHECK_EQ(1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567891");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12345");
+  b.ShiftLeft(32);
+  AssignHexString(&c, "1234567890ABCDEF12345");
+  c.ShiftLeft(32);
+  CHECK_EQ(1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567889");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12345");
+  b.ShiftLeft(32);
+  AssignHexString(&c, "1234567890ABCDEF12345");
+  c.ShiftLeft(32);
+  CHECK_EQ(-1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12345");
+  b.ShiftLeft(32);
+  AssignHexString(&c, "1234567890ABCDEF1234500000000");
+  CHECK_EQ(0, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12344");
+  b.ShiftLeft(32);
+  AssignHexString(&c, "1234567890ABCDEF1234500000000");
+  CHECK_EQ(-1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12346");
+  b.ShiftLeft(32);
+  AssignHexString(&c, "1234567890ABCDEF1234500000000");
+  CHECK_EQ(1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567891");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12345");
+  b.ShiftLeft(32);
+  AssignHexString(&c, "1234567890ABCDEF1234500000000");
+  CHECK_EQ(1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567889");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12345");
+  b.ShiftLeft(32);
+  AssignHexString(&c, "1234567890ABCDEF1234500000000");
+  CHECK_EQ(-1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12345");
+  AssignHexString(&c, "123456789000000000ABCDEF12345");
+  CHECK_EQ(0, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12346");
+  AssignHexString(&c, "123456789000000000ABCDEF12345");
+  CHECK_EQ(1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12344");
+  AssignHexString(&c, "123456789000000000ABCDEF12345");
+  CHECK_EQ(-1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12345");
+  b.ShiftLeft(16);
+  AssignHexString(&c, "12345678900000ABCDEF123450000");
+  CHECK_EQ(0, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12344");
+  b.ShiftLeft(16);
+  AssignHexString(&c, "12345678900000ABCDEF123450000");
+  CHECK_EQ(-1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12345");
+  b.ShiftLeft(16);
+  AssignHexString(&c, "12345678900000ABCDEF123450001");
+  CHECK_EQ(-1, Bignum::PlusCompare(a, b, c));
+
+  AssignHexString(&a, "1234567890");
+  a.ShiftLeft(11*4 + 32);
+  AssignHexString(&b, "ABCDEF12346");
+  b.ShiftLeft(16);
+  AssignHexString(&c, "12345678900000ABCDEF123450000");
+  CHECK_EQ(+1, Bignum::PlusCompare(a, b, c));
+}
+
+
+TEST(Square) {
+  Bignum bignum;
+  char buffer[kBufferSize];
+
+  bignum.AssignUInt16(1);
+  bignum.Square();
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1", buffer);
+
+  bignum.AssignUInt16(2);
+  bignum.Square();
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("4", buffer);
+
+  bignum.AssignUInt16(10);
+  bignum.Square();
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("64", buffer);
+
+  AssignHexString(&bignum, "FFFFFFF");
+  bignum.Square();
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFFFFE0000001", buffer);
+
+  AssignHexString(&bignum, "FFFFFFFFFFFFFF");
+  bignum.Square();
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FFFFFFFFFFFFFE00000000000001", buffer);
+}
+
+
+TEST(AssignPowerUInt16) {
+  Bignum bignum;
+  char buffer[kBufferSize];
+
+  bignum.AssignPowerUInt16(1, 0);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1", buffer);
+
+  bignum.AssignPowerUInt16(1, 1);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1", buffer);
+
+  bignum.AssignPowerUInt16(1, 2);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1", buffer);
+
+  bignum.AssignPowerUInt16(2, 0);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1", buffer);
+
+  bignum.AssignPowerUInt16(2, 1);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("2", buffer);
+
+  bignum.AssignPowerUInt16(2, 2);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("4", buffer);
+
+  bignum.AssignPowerUInt16(16, 1);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10", buffer);
+
+  bignum.AssignPowerUInt16(16, 2);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("100", buffer);
+
+  bignum.AssignPowerUInt16(16, 5);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("100000", buffer);
+
+  bignum.AssignPowerUInt16(16, 8);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("100000000", buffer);
+
+  bignum.AssignPowerUInt16(16, 16);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000000000000", buffer);
+
+  bignum.AssignPowerUInt16(16, 30);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1000000000000000000000000000000", buffer);
+
+  bignum.AssignPowerUInt16(10, 0);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1", buffer);
+
+  bignum.AssignPowerUInt16(10, 1);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("A", buffer);
+
+  bignum.AssignPowerUInt16(10, 2);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("64", buffer);
+
+  bignum.AssignPowerUInt16(10, 5);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("186A0", buffer);
+
+  bignum.AssignPowerUInt16(10, 8);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("5F5E100", buffer);
+
+  bignum.AssignPowerUInt16(10, 16);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("2386F26FC10000", buffer);
+
+  bignum.AssignPowerUInt16(10, 30);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("C9F2C9CD04674EDEA40000000", buffer);
+
+  bignum.AssignPowerUInt16(10, 31);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("7E37BE2022C0914B2680000000", buffer);
+
+  bignum.AssignPowerUInt16(2, 0);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1", buffer);
+
+  bignum.AssignPowerUInt16(2, 100);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("10000000000000000000000000", buffer);
+
+  bignum.AssignPowerUInt16(17, 0);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1", buffer);
+
+  bignum.AssignPowerUInt16(17, 99);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("1942BB9853FAD924A3D4DD92B89B940E0207BEF05DB9C26BC1B757"
+           "80BE0C5A2C2990E02A681224F34ED68558CE4C6E33760931",
+           buffer);
+
+  bignum.AssignPowerUInt16(0xFFFF, 99);
+  CHECK(bignum.ToHexString(buffer, kBufferSize));
+  CHECK_EQ("FF9D12F09B886C54E77E7439C7D2DED2D34F669654C0C2B6B8C288250"
+           "5A2211D0E3DC9A61831349EAE674B11D56E3049D7BD79DAAD6C9FA2BA"
+           "528E3A794299F2EE9146A324DAFE3E88967A0358233B543E233E575B9"
+           "DD4E3AA7942146426C328FF55BFD5C45E0901B1629260AF9AE2F310C5"
+           "50959FAF305C30116D537D80CF6EBDBC15C5694062AF1AC3D956D0A41"
+           "B7E1B79FF11E21D83387A1CE1F5882B31E4B5D8DE415BDBE6854466DF"
+           "343362267A7E8833119D31D02E18DB5B0E8F6A64B0ED0D0062FFFF",
+           buffer);
+}
index d59e2f5ad1162b8b3f28869c93f2e7328d36f385..748e3e8d91e3f4533d651e20965d688f61cabe59 100644 (file)
@@ -902,6 +902,7 @@ static void DebugEventBreak(v8::DebugEvent event,
 // Debug event handler which re-issues a debug break until a limit has been
 // reached.
 int max_break_point_hit_count = 0;
+bool terminate_after_max_break_point_hit = false;
 static void DebugEventBreakMax(v8::DebugEvent event,
                                v8::Handle<v8::Object> exec_state,
                                v8::Handle<v8::Object> event_data,
@@ -909,12 +910,17 @@ static void DebugEventBreakMax(v8::DebugEvent event,
   // When hitting a debug event listener there must be a break set.
   CHECK_NE(v8::internal::Debug::break_id(), 0);
 
-  if (event == v8::Break && break_point_hit_count < max_break_point_hit_count) {
-    // Count the number of breaks.
-    break_point_hit_count++;
+  if (event == v8::Break) {
+    if (break_point_hit_count < max_break_point_hit_count) {
+      // Count the number of breaks.
+      break_point_hit_count++;
 
-    // Set the break flag again to come back here as soon as possible.
-    v8::Debug::DebugBreak();
+      // Set the break flag again to come back here as soon as possible.
+      v8::Debug::DebugBreak();
+    } else if (terminate_after_max_break_point_hit) {
+      // Terminate execution after the last break if requested.
+      v8::V8::TerminateExecution();
+    }
   }
 }
 
@@ -6892,4 +6898,33 @@ TEST(DebugEventBreakData) {
   CheckDebuggerUnloaded();
 }
 
+
+// Test that setting the terminate execution flag during debug break processing.
+TEST(DebugBreakLoop) {
+  v8::HandleScope scope;
+  DebugLocalContext env;
+
+  // Receive 100 breaks and terminate.
+  max_break_point_hit_count = 100;
+  terminate_after_max_break_point_hit = true;
+
+  // Register a debug event listener which sets the break flag and counts.
+  v8::Debug::SetDebugEventListener(DebugEventBreakMax);
+
+  // Function with infinite loop.
+  CompileRun("function f() { while (true) { } }");
+
+  // Set the debug break to enter the debugger as soon as possible.
+  v8::Debug::DebugBreak();
+
+  // Call function with infinite loop.
+  CompileRun("f();");
+  CHECK_EQ(100, break_point_hit_count);
+
+  // Get rid of the debug event listener.
+  v8::Debug::SetDebugEventListener(NULL);
+  CheckDebuggerUnloaded();
+}
+
+
 #endif  // ENABLE_DEBUGGER_SUPPORT
index 61f5ffc7273310b93eeb34cb6c6d8af325423e49..c375831f271ebd39fe4f27411e5b5ee1dc78d8de 100644 (file)
@@ -87,9 +87,9 @@ bool DisassembleAndCompare(byte* pc, const char* compare_string) {
 #define COMPARE(asm_, compare_string) \
   { \
     int pc_offset = assm.pc_offset(); \
-    byte *pc = &buffer[pc_offset]; \
+    byte *progcounter = &buffer[pc_offset]; \
     assm.asm_; \
-    if (!DisassembleAndCompare(pc, compare_string)) failure = true; \
+    if (!DisassembleAndCompare(progcounter, compare_string)) failure = true; \
   }
 
 
@@ -499,6 +499,19 @@ TEST(Vfp) {
             "ed811b01       vstr d1, [r1 + 4*1]");
     COMPARE(vstr(d15, r10, 1020),
             "ed8afbff       vstr d15, [r10 + 4*255]");
+
+    COMPARE(vmsr(r5),
+            "eee15a10       vmsr FPSCR, r5");
+    COMPARE(vmsr(r10, pl),
+            "5ee1aa10       vmsrpl FPSCR, r10");
+    COMPARE(vmsr(pc),
+            "eee1fa10       vmsr FPSCR, APSR");
+    COMPARE(vmrs(r5),
+            "eef15a10       vmrs r5, FPSCR");
+    COMPARE(vmrs(r10, ge),
+            "aef1aa10       vmrsge r10, FPSCR");
+    COMPARE(vmrs(pc),
+            "eef1fa10       vmrs APSR, FPSCR");
   }
 
   VERIFY_RUN();
index a7a604ea43367789a330817ea23d428f4477cfd0..3594a4fe32aaedaf53e1eb7ac08157f221d5a928 100644 (file)
@@ -202,3 +202,19 @@ TEST(NormalizedBoundaries) {
   CHECK(diy_fp.f() - boundary_minus.f() == boundary_plus.f() - diy_fp.f());
   CHECK((1 << 10) == diy_fp.f() - boundary_minus.f());  // NOLINT
 }
+
+
+TEST(NextDouble) {
+  CHECK_EQ(4e-324, Double(0.0).NextDouble());
+  CHECK_EQ(0.0, Double(-0.0).NextDouble());
+  CHECK_EQ(-0.0, Double(-4e-324).NextDouble());
+  Double d0(-4e-324);
+  Double d1(d0.NextDouble());
+  Double d2(d1.NextDouble());
+  CHECK_EQ(-0.0, d1.value());
+  CHECK_EQ(0.0, d2.value());
+  CHECK_EQ(4e-324, d2.NextDouble());
+  CHECK_EQ(-1.7976931348623157e308, Double(-V8_INFINITY).NextDouble());
+  CHECK_EQ(V8_INFINITY,
+           Double(V8_2PART_UINT64_C(0x7fefffff, ffffffff)).NextDouble());
+}
diff --git a/deps/v8/test/cctest/test-dtoa.cc b/deps/v8/test/cctest/test-dtoa.cc
new file mode 100644 (file)
index 0000000..ff0b660
--- /dev/null
@@ -0,0 +1,331 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "dtoa.h"
+
+#include "cctest.h"
+#include "double.h"
+#include "gay-fixed.h"
+#include "gay-precision.h"
+#include "gay-shortest.h"
+#include "platform.h"
+
+
+using namespace v8::internal;
+
+
+// Removes trailing '0' digits.
+static void TrimRepresentation(Vector<char> representation) {
+  int len = strlen(representation.start());
+  int i;
+  for (i = len - 1; i >= 0; --i) {
+    if (representation[i] != '0') break;
+  }
+  representation[i + 1] = '\0';
+}
+
+
+static const int kBufferSize = 100;
+
+
+TEST(DtoaVariousDoubles) {
+  char buffer_container[kBufferSize];
+  Vector<char> buffer(buffer_container, kBufferSize);
+  int length;
+  int point;
+  int sign;
+
+  DoubleToAscii(0.0, DTOA_SHORTEST, 0, buffer, &sign, &length, &point);
+  CHECK_EQ("0", buffer.start());
+  CHECK_EQ(1, point);
+
+  DoubleToAscii(0.0, DTOA_FIXED, 2, buffer, &sign, &length, &point);
+  CHECK_EQ(1, length);
+  CHECK_EQ("0", buffer.start());
+  CHECK_EQ(1, point);
+
+  DoubleToAscii(0.0, DTOA_PRECISION, 3, buffer, &sign, &length, &point);
+  CHECK_EQ(1, length);
+  CHECK_EQ("0", buffer.start());
+  CHECK_EQ(1, point);
+
+  DoubleToAscii(1.0, DTOA_SHORTEST, 0, buffer, &sign, &length, &point);
+  CHECK_EQ("1", buffer.start());
+  CHECK_EQ(1, point);
+
+  DoubleToAscii(1.0, DTOA_FIXED, 3, buffer, &sign, &length, &point);
+  CHECK_GE(3, length - point);
+  TrimRepresentation(buffer);
+  CHECK_EQ("1", buffer.start());
+  CHECK_EQ(1, point);
+
+  DoubleToAscii(1.0, DTOA_PRECISION, 3, buffer, &sign, &length, &point);
+  CHECK_GE(3, length);
+  TrimRepresentation(buffer);
+  CHECK_EQ("1", buffer.start());
+  CHECK_EQ(1, point);
+
+  DoubleToAscii(1.5, DTOA_SHORTEST, 0, buffer, &sign, &length, &point);
+  CHECK_EQ("15", buffer.start());
+  CHECK_EQ(1, point);
+
+  DoubleToAscii(1.5, DTOA_FIXED, 10, buffer, &sign, &length, &point);
+  CHECK_GE(10, length - point);
+  TrimRepresentation(buffer);
+  CHECK_EQ("15", buffer.start());
+  CHECK_EQ(1, point);
+
+  DoubleToAscii(1.5, DTOA_PRECISION, 10, buffer, &sign, &length, &point);
+  CHECK_GE(10, length);
+  TrimRepresentation(buffer);
+  CHECK_EQ("15", buffer.start());
+  CHECK_EQ(1, point);
+
+  double min_double = 5e-324;
+  DoubleToAscii(min_double, DTOA_SHORTEST, 0, buffer, &sign, &length, &point);
+  CHECK_EQ("5", buffer.start());
+  CHECK_EQ(-323, point);
+
+  DoubleToAscii(min_double, DTOA_FIXED, 5, buffer, &sign, &length, &point);
+  CHECK_GE(5, length - point);
+  TrimRepresentation(buffer);
+  CHECK_EQ("", buffer.start());
+  CHECK_GE(-5, point);
+
+  DoubleToAscii(min_double, DTOA_PRECISION, 5, buffer, &sign, &length, &point);
+  CHECK_GE(5, length);
+  TrimRepresentation(buffer);
+  CHECK_EQ("49407", buffer.start());
+  CHECK_EQ(-323, point);
+
+  double max_double = 1.7976931348623157e308;
+  DoubleToAscii(max_double, DTOA_SHORTEST, 0, buffer, &sign, &length, &point);
+  CHECK_EQ("17976931348623157", buffer.start());
+  CHECK_EQ(309, point);
+
+  DoubleToAscii(max_double, DTOA_PRECISION, 7, buffer, &sign, &length, &point);
+  CHECK_GE(7, length);
+  TrimRepresentation(buffer);
+  CHECK_EQ("1797693", buffer.start());
+  CHECK_EQ(309, point);
+
+  DoubleToAscii(4294967272.0, DTOA_SHORTEST, 0, buffer, &sign, &length, &point);
+  CHECK_EQ("4294967272", buffer.start());
+  CHECK_EQ(10, point);
+
+  DoubleToAscii(4294967272.0, DTOA_FIXED, 5, buffer, &sign, &length, &point);
+  CHECK_GE(5, length - point);
+  TrimRepresentation(buffer);
+  CHECK_EQ("4294967272", buffer.start());
+  CHECK_EQ(10, point);
+
+
+  DoubleToAscii(4294967272.0, DTOA_PRECISION, 14,
+                buffer, &sign, &length, &point);
+  CHECK_GE(14, length);
+  TrimRepresentation(buffer);
+  CHECK_EQ("4294967272", buffer.start());
+  CHECK_EQ(10, point);
+
+  DoubleToAscii(4.1855804968213567e298, DTOA_SHORTEST, 0,
+                buffer, &sign, &length, &point);
+  CHECK_EQ("4185580496821357", buffer.start());
+  CHECK_EQ(299, point);
+
+  DoubleToAscii(4.1855804968213567e298, DTOA_PRECISION, 20,
+                buffer, &sign, &length, &point);
+  CHECK_GE(20, length);
+  TrimRepresentation(buffer);
+  CHECK_EQ("41855804968213567225", buffer.start());
+  CHECK_EQ(299, point);
+
+  DoubleToAscii(5.5626846462680035e-309, DTOA_SHORTEST, 0,
+                buffer, &sign, &length, &point);
+  CHECK_EQ("5562684646268003", buffer.start());
+  CHECK_EQ(-308, point);
+
+  DoubleToAscii(5.5626846462680035e-309, DTOA_PRECISION, 1,
+                buffer, &sign, &length, &point);
+  CHECK_GE(1, length);
+  TrimRepresentation(buffer);
+  CHECK_EQ("6", buffer.start());
+  CHECK_EQ(-308, point);
+
+  DoubleToAscii(-2147483648.0, DTOA_SHORTEST, 0,
+                buffer, &sign, &length, &point);
+  CHECK_EQ(1, sign);
+  CHECK_EQ("2147483648", buffer.start());
+  CHECK_EQ(10, point);
+
+
+  DoubleToAscii(-2147483648.0, DTOA_FIXED, 2, buffer, &sign, &length, &point);
+  CHECK_GE(2, length - point);
+  TrimRepresentation(buffer);
+  CHECK_EQ(1, sign);
+  CHECK_EQ("2147483648", buffer.start());
+  CHECK_EQ(10, point);
+
+  DoubleToAscii(-2147483648.0, DTOA_PRECISION, 5,
+                buffer, &sign, &length, &point);
+  CHECK_GE(5, length);
+  TrimRepresentation(buffer);
+  CHECK_EQ(1, sign);
+  CHECK_EQ("21475", buffer.start());
+  CHECK_EQ(10, point);
+
+  DoubleToAscii(-3.5844466002796428e+298, DTOA_SHORTEST, 0,
+                buffer, &sign, &length, &point);
+  CHECK_EQ(1, sign);
+  CHECK_EQ("35844466002796428", buffer.start());
+  CHECK_EQ(299, point);
+
+  DoubleToAscii(-3.5844466002796428e+298, DTOA_PRECISION, 10,
+                buffer, &sign, &length, &point);
+  CHECK_EQ(1, sign);
+  CHECK_GE(10, length);
+  TrimRepresentation(buffer);
+  CHECK_EQ("35844466", buffer.start());
+  CHECK_EQ(299, point);
+
+  uint64_t smallest_normal64 = V8_2PART_UINT64_C(0x00100000, 00000000);
+  double v = Double(smallest_normal64).value();
+  DoubleToAscii(v, DTOA_SHORTEST, 0, buffer, &sign, &length, &point);
+  CHECK_EQ("22250738585072014", buffer.start());
+  CHECK_EQ(-307, point);
+
+  DoubleToAscii(v, DTOA_PRECISION, 20, buffer, &sign, &length, &point);
+  CHECK_GE(20, length);
+  TrimRepresentation(buffer);
+  CHECK_EQ("22250738585072013831", buffer.start());
+  CHECK_EQ(-307, point);
+
+  uint64_t largest_denormal64 = V8_2PART_UINT64_C(0x000FFFFF, FFFFFFFF);
+  v = Double(largest_denormal64).value();
+  DoubleToAscii(v, DTOA_SHORTEST, 0, buffer, &sign, &length, &point);
+  CHECK_EQ("2225073858507201", buffer.start());
+  CHECK_EQ(-307, point);
+
+  DoubleToAscii(v, DTOA_PRECISION, 20, buffer, &sign, &length, &point);
+  CHECK_GE(20, length);
+  TrimRepresentation(buffer);
+  CHECK_EQ("2225073858507200889", buffer.start());
+  CHECK_EQ(-307, point);
+
+  DoubleToAscii(4128420500802942e-24, DTOA_SHORTEST, 0,
+                buffer, &sign, &length, &point);
+  CHECK_EQ(0, sign);
+  CHECK_EQ("4128420500802942", buffer.start());
+  CHECK_EQ(-8, point);
+
+  v = -3.9292015898194142585311918e-10;
+  DoubleToAscii(v, DTOA_SHORTEST, 0, buffer, &sign, &length, &point);
+  CHECK_EQ("39292015898194143", buffer.start());
+
+  v = 4194304.0;
+  DoubleToAscii(v, DTOA_FIXED, 5, buffer, &sign, &length, &point);
+  CHECK_GE(5, length - point);
+  TrimRepresentation(buffer);
+  CHECK_EQ("4194304", buffer.start());
+
+  v = 3.3161339052167390562200598e-237;
+  DoubleToAscii(v, DTOA_PRECISION, 19, buffer, &sign, &length, &point);
+  CHECK_GE(19, length);
+  TrimRepresentation(buffer);
+  CHECK_EQ("3316133905216739056", buffer.start());
+  CHECK_EQ(-236, point);
+}
+
+
+TEST(DtoaGayShortest) {
+  char buffer_container[kBufferSize];
+  Vector<char> buffer(buffer_container, kBufferSize);
+  int sign;
+  int length;
+  int point;
+
+  Vector<const PrecomputedShortest> precomputed =
+      PrecomputedShortestRepresentations();
+  for (int i = 0; i < precomputed.length(); ++i) {
+    const PrecomputedShortest current_test = precomputed[i];
+    double v = current_test.v;
+    DoubleToAscii(v, DTOA_SHORTEST, 0, buffer, &sign, &length, &point);
+    CHECK_EQ(0, sign);  // All precomputed numbers are positive.
+    CHECK_EQ(current_test.decimal_point, point);
+    CHECK_EQ(current_test.representation, buffer.start());
+  }
+}
+
+
+TEST(DtoaGayFixed) {
+  char buffer_container[kBufferSize];
+  Vector<char> buffer(buffer_container, kBufferSize);
+  int sign;
+  int length;
+  int point;
+
+  Vector<const PrecomputedFixed> precomputed =
+      PrecomputedFixedRepresentations();
+  for (int i = 0; i < precomputed.length(); ++i) {
+    const PrecomputedFixed current_test = precomputed[i];
+    double v = current_test.v;
+    int number_digits = current_test.number_digits;
+    DoubleToAscii(v, DTOA_FIXED, number_digits, buffer, &sign, &length, &point);
+    CHECK_EQ(0, sign);  // All precomputed numbers are positive.
+    CHECK_EQ(current_test.decimal_point, point);
+    CHECK_GE(number_digits, length - point);
+    TrimRepresentation(buffer);
+    CHECK_EQ(current_test.representation, buffer.start());
+  }
+}
+
+
+TEST(DtoaGayPrecision) {
+  char buffer_container[kBufferSize];
+  Vector<char> buffer(buffer_container, kBufferSize);
+  int sign;
+  int length;
+  int point;
+
+  Vector<const PrecomputedPrecision> precomputed =
+      PrecomputedPrecisionRepresentations();
+  for (int i = 0; i < precomputed.length(); ++i) {
+    const PrecomputedPrecision current_test = precomputed[i];
+    double v = current_test.v;
+    int number_digits = current_test.number_digits;
+    DoubleToAscii(v, DTOA_PRECISION, number_digits,
+                  buffer, &sign, &length, &point);
+    CHECK_EQ(0, sign);  // All precomputed numbers are positive.
+    CHECK_EQ(current_test.decimal_point, point);
+    CHECK_GE(number_digits, length);
+    TrimRepresentation(buffer);
+    CHECK_EQ(current_test.representation, buffer.start());
+  }
+}
index b86a3361605b5ee79abadb8dff0796a36faef8c1..b165190b0a98ac953b7993271194c0636eb4917f 100644 (file)
@@ -388,14 +388,10 @@ namespace {
 class NamedEntriesDetector {
  public:
   NamedEntriesDetector()
-      : has_A1(false), has_B1(false), has_C1(false),
-        has_A2(false), has_B2(false), has_C2(false) {
+      : has_A2(false), has_B2(false), has_C2(false) {
   }
 
   void Apply(i::HeapEntry** entry_ptr) {
-    if (IsReachableNodeWithName(*entry_ptr, "A1")) has_A1 = true;
-    if (IsReachableNodeWithName(*entry_ptr, "B1")) has_B1 = true;
-    if (IsReachableNodeWithName(*entry_ptr, "C1")) has_C1 = true;
     if (IsReachableNodeWithName(*entry_ptr, "A2")) has_A2 = true;
     if (IsReachableNodeWithName(*entry_ptr, "B2")) has_B2 = true;
     if (IsReachableNodeWithName(*entry_ptr, "C2")) has_C2 = true;
@@ -405,9 +401,6 @@ class NamedEntriesDetector {
     return strcmp(name, entry->name()) == 0 && entry->painted_reachable();
   }
 
-  bool has_A1;
-  bool has_B1;
-  bool has_C1;
   bool has_A2;
   bool has_B2;
   bool has_C2;
@@ -464,21 +457,7 @@ static bool HasString(const v8::HeapGraphNode* node, const char* contents) {
 
 TEST(HeapSnapshot) {
   v8::HandleScope scope;
-  v8::Handle<v8::String> token1 = v8::String::New("token1");
-  LocalContext env1;
-  env1->SetSecurityToken(token1);
-
-  CompileRun(
-      "function A1() {}\n"
-      "function B1(x) { this.x = x; }\n"
-      "function C1(x) { this.x1 = x; this.x2 = x; }\n"
-      "var a1 = new A1();\n"
-      "var b1_1 = new B1(a1), b1_2 = new B1(a1);\n"
-      "var c1 = new C1(a1);");
-
-  v8::Handle<v8::String> token2 = v8::String::New("token2");
   LocalContext env2;
-  env2->SetSecurityToken(token2);
 
   CompileRun(
       "function A2() {}\n"
@@ -498,14 +477,7 @@ TEST(HeapSnapshot) {
   const_cast<i::HeapEntry*>(
       reinterpret_cast<const i::HeapEntry*>(global_env2))->PaintAllReachable();
 
-  // Verify, that JS global object of env2 doesn't have '..1'
-  // properties, but has '..2' properties.
-  CHECK_EQ(NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "a1"));
-  CHECK_EQ(
-      NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "b1_1"));
-  CHECK_EQ(
-      NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "b1_2"));
-  CHECK_EQ(NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "c1"));
+  // Verify, that JS global object of env2 has '..2' properties.
   const v8::HeapGraphNode* a2_node =
       GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "a2");
   CHECK_NE(NULL, a2_node);
@@ -518,9 +490,6 @@ TEST(HeapSnapshot) {
   // Verify that anything related to '[ABC]1' is not reachable.
   NamedEntriesDetector det;
   i_snapshot_env2->IterateEntries(&det);
-  CHECK(!det.has_A1);
-  CHECK(!det.has_B1);
-  CHECK(!det.has_C1);
   CHECK(det.has_A2);
   CHECK(det.has_B2);
   CHECK(det.has_C2);
index 94d05555ec556276834a381ad68786266f433e77..fbe66ecd74627eade4ea57fe233b3f50ff21e33d 100644 (file)
@@ -1095,3 +1095,32 @@ TEST(TestInternalWeakListsTraverseWithGC) {
     ctx[i]->Exit();
   }
 }
+
+
+TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
+  InitializeVM();
+  intptr_t size_of_objects_1 = Heap::SizeOfObjects();
+  HeapIterator iterator(HeapIterator::kPreciseFiltering);
+  intptr_t size_of_objects_2 = 0;
+  for (HeapObject* obj = iterator.next();
+       obj != NULL;
+       obj = iterator.next()) {
+    size_of_objects_2 += obj->Size();
+  }
+  // Delta must be within 1% of the larger result.
+  if (size_of_objects_1 > size_of_objects_2) {
+    intptr_t delta = size_of_objects_1 - size_of_objects_2;
+    PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
+           "Iterator: %" V8_PTR_PREFIX "d, "
+           "delta: %" V8_PTR_PREFIX "d\n",
+           size_of_objects_1, size_of_objects_2, delta);
+    CHECK_GT(size_of_objects_1 / 100, delta);
+  } else {
+    intptr_t delta = size_of_objects_2 - size_of_objects_1;
+    PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
+           "Iterator: %" V8_PTR_PREFIX "d, "
+           "delta: %" V8_PTR_PREFIX "d\n",
+           size_of_objects_1, size_of_objects_2, delta);
+    CHECK_GT(size_of_objects_2 / 100, delta);
+  }
+}
index ea5afecc1e3b957721281edea3e5370f7d995947..994256712f0f301bd7572d14a3fdf4ad133ef525 100644 (file)
@@ -75,7 +75,7 @@ TEST(Promotion) {
   // from new space.
   FLAG_gc_global = true;
   FLAG_always_compact = true;
-  Heap::ConfigureHeap(2*256*KB, 4*MB);
+  Heap::ConfigureHeap(2*256*KB, 4*MB, 4*MB);
 
   InitializeVM();
 
@@ -101,7 +101,7 @@ TEST(Promotion) {
 
 
 TEST(NoPromotion) {
-  Heap::ConfigureHeap(2*256*KB, 4*MB);
+  Heap::ConfigureHeap(2*256*KB, 4*MB, 4*MB);
 
   // Test the situation that some objects in new space are promoted to
   // the old space
index 02503f225ca3b5d5004717f309cd2a35c7427357..d661af6c588f746bb1179a43a37e67818f69b0fa 100755 (executable)
@@ -26,6 +26,8 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
 
 #include "v8.h"
 
@@ -34,7 +36,8 @@
 #include "parser.h"
 #include "utils.h"
 #include "execution.h"
-
+#include "scanner.h"
+#include "preparser.h"
 #include "cctest.h"
 
 namespace i = ::v8::internal;
@@ -239,3 +242,89 @@ TEST(Preparsing) {
   i::Vector<const char*> args = pre_impl->BuildArgs();
   CHECK_GT(strlen(message), 0);
 }
+
+
+TEST(StandAlonePreParser) {
+  int marker;
+  i::StackGuard::SetStackLimit(
+      reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
+
+  const char* programs[] = {
+      "{label: 42}",
+      "var x = 42;",
+      "function foo(x, y) { return x + y; }",
+      "native function foo(); return %ArgleBargle(glop);",
+      "var x = new new Function('this.x = 42');",
+      NULL
+  };
+
+  for (int i = 0; programs[i]; i++) {
+    const char* program = programs[i];
+    unibrow::Utf8InputBuffer<256> stream(program, strlen(program));
+    i::CompleteParserRecorder log;
+    i::Scanner scanner;
+    scanner.Initialize(i::Handle<i::String>::null(), &stream, i::JAVASCRIPT);
+    v8::preparser::PreParser<i::Scanner, i::CompleteParserRecorder> preparser;
+    bool result = preparser.PreParseProgram(&scanner, &log, true);
+    CHECK(result);
+    i::ScriptDataImpl data(log.ExtractData());
+    CHECK(!data.has_error());
+  }
+}
+
+
+TEST(RegressChromium62639) {
+  int marker;
+  i::StackGuard::SetStackLimit(
+      reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
+
+  const char* program = "var x = 'something';\n"
+                        "escape: function() {}";
+  // Fails parsing expecting an identifier after "function".
+  // Before fix, didn't check *ok after Expect(Token::Identifier, ok),
+  // and then used the invalid currently scanned literal. This always
+  // failed in debug mode, and sometimes crashed in release mode.
+
+  unibrow::Utf8InputBuffer<256> stream(program, strlen(program));
+  i::ScriptDataImpl* data =
+      i::ParserApi::PreParse(i::Handle<i::String>::null(), &stream, NULL);
+  CHECK(data->HasError());
+  delete data;
+}
+
+
+TEST(Regress928) {
+  // Preparsing didn't consider the catch clause of a try statement
+  // as with-content, which made it assume that a function inside
+  // the block could be lazily compiled, and an extra, unexpected,
+  // entry was added to the data.
+  int marker;
+  i::StackGuard::SetStackLimit(
+      reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
+
+  const char* program =
+      "try { } catch (e) { var foo = function () { /* first */ } }"
+      "var bar = function () { /* second */ }";
+
+  unibrow::Utf8InputBuffer<256> stream(program, strlen(program));
+  i::ScriptDataImpl* data =
+      i::ParserApi::PartialPreParse(i::Handle<i::String>::null(),
+                                    &stream, NULL);
+  CHECK(!data->HasError());
+
+  data->Initialize();
+
+  int first_function = strstr(program, "function") - program;
+  int first_lbrace = first_function + strlen("function () ");
+  CHECK_EQ('{', program[first_lbrace]);
+  i::FunctionEntry entry1 = data->GetFunctionEntry(first_lbrace);
+  CHECK(!entry1.is_valid());
+
+  int second_function = strstr(program + first_lbrace, "function") - program;
+  int second_lbrace = second_function + strlen("function () ");
+  CHECK_EQ('{', program[second_lbrace]);
+  i::FunctionEntry entry2 = data->GetFunctionEntry(second_lbrace);
+  CHECK(entry2.is_valid());
+  CHECK_EQ('}', program[entry2.end_pos() - 1]);
+  delete data;
+}
index 06f1bfaca2994162308df25dbc280374a596e0ba..b399a4ef182fc6ff8f04912dbe5dcb4b32ed80c9 100644 (file)
@@ -91,7 +91,7 @@ TEST(Page) {
 
 TEST(MemoryAllocator) {
   CHECK(Heap::ConfigureHeapDefault());
-  CHECK(MemoryAllocator::Setup(Heap::MaxReserved()));
+  CHECK(MemoryAllocator::Setup(Heap::MaxReserved(), Heap::MaxExecutableSize()));
 
   OldSpace faked_space(Heap::MaxReserved(), OLD_POINTER_SPACE, NOT_EXECUTABLE);
   int total_pages = 0;
@@ -147,7 +147,7 @@ TEST(MemoryAllocator) {
 
 TEST(NewSpace) {
   CHECK(Heap::ConfigureHeapDefault());
-  CHECK(MemoryAllocator::Setup(Heap::MaxReserved()));
+  CHECK(MemoryAllocator::Setup(Heap::MaxReserved(), Heap::MaxExecutableSize()));
 
   NewSpace new_space;
 
@@ -172,7 +172,7 @@ TEST(NewSpace) {
 
 TEST(OldSpace) {
   CHECK(Heap::ConfigureHeapDefault());
-  CHECK(MemoryAllocator::Setup(Heap::MaxReserved()));
+  CHECK(MemoryAllocator::Setup(Heap::MaxReserved(), Heap::MaxExecutableSize()));
 
   OldSpace* s = new OldSpace(Heap::MaxOldGenerationSize(),
                              OLD_POINTER_SPACE,
index 56b26ea1eb90f8526431bcfb8cd4ef473dd52695..f5547dbc0326bb6a6a9f4318df067a764e9719ab 100644 (file)
@@ -4,7 +4,10 @@
 
 #include "v8.h"
 
+#include "bignum.h"
 #include "cctest.h"
+#include "diy-fp.h"
+#include "double.h"
 #include "strtod.h"
 
 using namespace v8::internal;
@@ -202,11 +205,14 @@ TEST(Strtod) {
   CHECK_EQ(1.7976931348623158E+308, StrtodChar("17976931348623158", 292));
   CHECK_EQ(V8_INFINITY, StrtodChar("17976931348623159", 292));
 
-  // The following number is the result of 89255.0/1e-22. Both floating-point
+  // The following number is the result of 89255.0/1e22. Both floating-point
   // numbers can be accurately represented with doubles. However on Linux,x86
   // the floating-point stack is set to 80bits and the double-rounding
   // introduces an error.
   CHECK_EQ(89255e-22, StrtodChar("89255", -22));
+
+  // Some random values.
+  CHECK_EQ(358416272e-33, StrtodChar("358416272", -33));
   CHECK_EQ(104110013277974872254e-225,
            StrtodChar("104110013277974872254", -225));
 
@@ -252,4 +258,177 @@ TEST(Strtod) {
            StrtodChar("1234567890123456789052345", 114));
   CHECK_EQ(1234567890123456789052345e115,
            StrtodChar("1234567890123456789052345", 115));
+
+  CHECK_EQ(5.445618932859895e-255,
+           StrtodChar("5445618932859895362967233318697132813618813095743952975"
+                      "4392982234069699615600475529427176366709107287468930197"
+                      "8628345413991790019316974825934906752493984055268219809"
+                      "5012176093045431437495773903922425632551857520884625114"
+                      "6241265881735209066709685420744388526014389929047617597"
+                      "0302268848374508109029268898695825171158085457567481507"
+                      "4162979705098246243690189880319928315307816832576838178"
+                      "2563074014542859888710209237525873301724479666744537857"
+                      "9026553346649664045621387124193095870305991178772256504"
+                      "4368663670643970181259143319016472430928902201239474588"
+                      "1392338901353291306607057623202353588698746085415097902"
+                      "6640064319118728664842287477491068264828851624402189317"
+                      "2769161449825765517353755844373640588822904791244190695"
+                      "2998382932630754670573838138825217065450843010498555058"
+                      "88186560731", -1035));
+
+  // Boundary cases. Boundaries themselves should round to even.
+  //
+  // 0x1FFFFFFFFFFFF * 2^3 = 72057594037927928
+  //                   next: 72057594037927936
+  //               boundary: 72057594037927932  should round up.
+  CHECK_EQ(72057594037927928.0, StrtodChar("72057594037927928", 0));
+  CHECK_EQ(72057594037927936.0, StrtodChar("72057594037927936", 0));
+  CHECK_EQ(72057594037927936.0, StrtodChar("72057594037927932", 0));
+  CHECK_EQ(72057594037927928.0, StrtodChar("7205759403792793199999", -5));
+  CHECK_EQ(72057594037927936.0, StrtodChar("7205759403792793200001", -5));
+
+  // 0x1FFFFFFFFFFFF * 2^10 = 9223372036854774784
+  //                    next: 9223372036854775808
+  //                boundary: 9223372036854775296 should round up.
+  CHECK_EQ(9223372036854774784.0, StrtodChar("9223372036854774784", 0));
+  CHECK_EQ(9223372036854775808.0, StrtodChar("9223372036854775808", 0));
+  CHECK_EQ(9223372036854775808.0, StrtodChar("9223372036854775296", 0));
+  CHECK_EQ(9223372036854774784.0, StrtodChar("922337203685477529599999", -5));
+  CHECK_EQ(9223372036854775808.0, StrtodChar("922337203685477529600001", -5));
+
+  // 0x1FFFFFFFFFFFF * 2^50 = 10141204801825834086073718800384
+  //                    next: 10141204801825835211973625643008
+  //                boundary: 10141204801825834649023672221696 should round up.
+  CHECK_EQ(10141204801825834086073718800384.0,
+           StrtodChar("10141204801825834086073718800384", 0));
+  CHECK_EQ(10141204801825835211973625643008.0,
+           StrtodChar("10141204801825835211973625643008", 0));
+  CHECK_EQ(10141204801825835211973625643008.0,
+           StrtodChar("10141204801825834649023672221696", 0));
+  CHECK_EQ(10141204801825834086073718800384.0,
+           StrtodChar("1014120480182583464902367222169599999", -5));
+  CHECK_EQ(10141204801825835211973625643008.0,
+           StrtodChar("1014120480182583464902367222169600001", -5));
+
+  // 0x1FFFFFFFFFFFF * 2^99 = 5708990770823838890407843763683279797179383808
+  //                    next: 5708990770823839524233143877797980545530986496
+  //                boundary: 5708990770823839207320493820740630171355185152
+  // The boundary should round up.
+  CHECK_EQ(5708990770823838890407843763683279797179383808.0,
+           StrtodChar("5708990770823838890407843763683279797179383808", 0));
+  CHECK_EQ(5708990770823839524233143877797980545530986496.0,
+           StrtodChar("5708990770823839524233143877797980545530986496", 0));
+  CHECK_EQ(5708990770823839524233143877797980545530986496.0,
+           StrtodChar("5708990770823839207320493820740630171355185152", 0));
+  CHECK_EQ(5708990770823838890407843763683279797179383808.0,
+           StrtodChar("5708990770823839207320493820740630171355185151999", -3));
+  CHECK_EQ(5708990770823839524233143877797980545530986496.0,
+           StrtodChar("5708990770823839207320493820740630171355185152001", -3));
+}
+
+
+static int CompareBignumToDiyFp(const Bignum& bignum_digits,
+                                int bignum_exponent,
+                                DiyFp diy_fp) {
+  Bignum bignum;
+  bignum.AssignBignum(bignum_digits);
+  Bignum other;
+  other.AssignUInt64(diy_fp.f());
+  if (bignum_exponent >= 0) {
+    bignum.MultiplyByPowerOfTen(bignum_exponent);
+  } else {
+    other.MultiplyByPowerOfTen(-bignum_exponent);
+  }
+  if (diy_fp.e() >= 0) {
+    other.ShiftLeft(diy_fp.e());
+  } else {
+    bignum.ShiftLeft(-diy_fp.e());
+  }
+  return Bignum::Compare(bignum, other);
+}
+
+
+static bool CheckDouble(Vector<const char> buffer,
+                        int exponent,
+                        double to_check) {
+  DiyFp lower_boundary;
+  DiyFp upper_boundary;
+  Bignum input_digits;
+  input_digits.AssignDecimalString(buffer);
+  if (to_check == 0.0) {
+    const double kMinDouble = 4e-324;
+    // Check that the buffer*10^exponent < (0 + kMinDouble)/2.
+    Double d(kMinDouble);
+    d.NormalizedBoundaries(&lower_boundary, &upper_boundary);
+    return CompareBignumToDiyFp(input_digits, exponent, lower_boundary) <= 0;
+  }
+  if (to_check == V8_INFINITY) {
+    const double kMaxDouble = 1.7976931348623157e308;
+    // Check that the buffer*10^exponent >= boundary between kMaxDouble and inf.
+    Double d(kMaxDouble);
+    d.NormalizedBoundaries(&lower_boundary, &upper_boundary);
+    return CompareBignumToDiyFp(input_digits, exponent, upper_boundary) >= 0;
+  }
+  Double d(to_check);
+  d.NormalizedBoundaries(&lower_boundary, &upper_boundary);
+  if ((d.Significand() & 1) == 0) {
+    return CompareBignumToDiyFp(input_digits, exponent, lower_boundary) >= 0 &&
+        CompareBignumToDiyFp(input_digits, exponent, upper_boundary) <= 0;
+  } else {
+    return CompareBignumToDiyFp(input_digits, exponent, lower_boundary) > 0 &&
+        CompareBignumToDiyFp(input_digits, exponent, upper_boundary) < 0;
+  }
+}
+
+
+// Copied from v8.cc and adapted to make the function deterministic.
+static uint32_t DeterministicRandom() {
+  // Random number generator using George Marsaglia's MWC algorithm.
+  static uint32_t hi = 0;
+  static uint32_t lo = 0;
+
+  // Initialization values don't have any special meaning. (They are the result
+  // of two calls to random().)
+  if (hi == 0) hi = 0xbfe166e7;
+  if (lo == 0) lo = 0x64d1c3c9;
+
+  // Mix the bits.
+  hi = 36969 * (hi & 0xFFFF) + (hi >> 16);
+  lo = 18273 * (lo & 0xFFFF) + (lo >> 16);
+  return (hi << 16) + (lo & 0xFFFF);
+}
+
+
+static const int kBufferSize = 1024;
+static const int kShortStrtodRandomCount = 2;
+static const int kLargeStrtodRandomCount = 2;
+
+TEST(RandomStrtod) {
+  char buffer[kBufferSize];
+  for (int length = 1; length < 15; length++) {
+    for (int i = 0; i < kShortStrtodRandomCount; ++i) {
+      int pos = 0;
+      for (int j = 0; j < length; ++j) {
+        buffer[pos++] = random() % 10 + '0';
+      }
+      int exponent = DeterministicRandom() % (25*2 + 1) - 25 - length;
+      buffer[pos] = '\0';
+      Vector<const char> vector(buffer, pos);
+      double strtod_result = Strtod(vector, exponent);
+      CHECK(CheckDouble(vector, exponent, strtod_result));
+    }
+  }
+  for (int length = 15; length < 800; length += 2) {
+    for (int i = 0; i < kLargeStrtodRandomCount; ++i) {
+      int pos = 0;
+      for (int j = 0; j < length; ++j) {
+        buffer[pos++] = random() % 10 + '0';
+      }
+      int exponent = DeterministicRandom() % (308*2 + 1) - 308 - length;
+      buffer[pos] = '\0';
+      Vector<const char> vector(buffer, pos);
+      double strtod_result = Strtod(vector, exponent);
+      CHECK(CheckDouble(vector, exponent, strtod_result));
+    }
+  }
 }
diff --git a/deps/v8/test/mjsunit/regress/regress-918.js b/deps/v8/test/mjsunit/regress/regress-918.js
new file mode 100644 (file)
index 0000000..4b6ddba
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Parser should not accept parentheses around labels.
+// See http://code.google.com/p/v8/issues/detail?id=918
+
+// The label was parsed as an expression and then tested for being a 
+// single identifier. This threw away the parentheses.
+assertThrows("(label):42;");
diff --git a/deps/v8/test/mjsunit/regress/regress-927.js b/deps/v8/test/mjsunit/regress/regress-927.js
new file mode 100644 (file)
index 0000000..c671f7d
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function a1() {
+    var a2 = -1756315459;
+    return ((((a2 & a2) ^ 1) * a2) << -10);
+}
+
+assertEquals(a1(), -2147483648);
diff --git a/deps/v8/test/mjsunit/regress/regress-931.js b/deps/v8/test/mjsunit/regress/regress-931.js
new file mode 100644 (file)
index 0000000..d2fb8cc
--- /dev/null
@@ -0,0 +1,48 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// See http://code.google.com/p/v8/issues/detail?id=931.
+
+var sequence = '';
+
+var o = { f: function (x, y) { return x + y; },
+          2: function (x, y) { return x - y} };
+
+function first() { sequence += "1"; return o; }
+function second() { sequence += "2"; return "f"; }
+function third() { sequence += "3"; return 3; }
+function fourth() { sequence += "4"; return 4; }
+
+var result = (first()[second()](third(), fourth()))
+assertEquals(7, result);
+assertEquals("1234", sequence);
+
+function second_prime() { sequence += "2'"; return 2; }
+
+var result = (first()[second_prime()](third(), fourth()))
+assertEquals(-1, result);
+assertEquals("123412'34", sequence);
diff --git a/deps/v8/test/mjsunit/regress/regress-conditional-position.js b/deps/v8/test/mjsunit/regress/regress-conditional-position.js
new file mode 100644 (file)
index 0000000..cd8f7bd
--- /dev/null
@@ -0,0 +1,95 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --always-full-compiler
+
+var functionToCatch;
+var lineNumber;
+
+function catchLineNumber () {
+  var x = {};
+
+  Error.prepareStackTrace = function (error, stackTrace) {
+    stackTrace.some(function (frame) {
+      if (frame.getFunction() == functionToCatch) {
+        lineNumber = frame.getLineNumber();
+        return true;
+      }
+      return false;
+    });
+    return lineNumber;
+  };
+
+  Error.captureStackTrace(x);
+  return x.stack;
+}
+
+function log() {
+  catchLineNumber();
+}
+
+function foo() {}
+
+function test1() {
+  log(foo() == foo()
+      ? 'a'
+      : 'b');
+}
+
+function test2() {
+  var o = { foo: function () {}}
+  log(o.foo() == o.foo()
+      ? 'a'
+      : 'b');
+}
+
+function test3() {
+  var o = { log: log, foo: function() { } };
+  o.log(o.foo() == o.foo()
+      ? 'a'
+      : 'b');
+
+}
+
+function test(f, expectedLineNumber) {
+  functionToCatch = f;
+  f();
+
+  assertEquals(expectedLineNumber, lineNumber);
+}
+
+test(test1, 58);
+test(test2, 65);
+test(test3, 72);
+
+eval(test1.toString() + "//@ sourceUrl=foo");
+eval(test2.toString() + "//@ sourceUrl=foo");
+eval(test3.toString() + "//@ sourceUrl=foo");
+
+test(test1, 2);
+test(test2, 3);
+test(test3, 3);
index 59d3ad3ee387215e6aaf2c089fecab50b167b58b..c741f6a3e59d639ba4403860927e762890da66d5 100644 (file)
 
 expected = ["A", undefined, "B", "bold", "/", "B", "and", undefined, "CODE", "coded", "/", "CODE", ""];
 result = "A<B>bold</B>and<CODE>coded</CODE>".split(/<(\/)?([^<>]+)>/);
-assertArrayEquals(expected, result, 1);
+assertArrayEquals(expected, result);
 
-expected = ["a", "b"];
-result = "ab".split(/a*?/);
-assertArrayEquals(expected, result, 2);
 
-expected = ["", "b"];
-result = "ab".split(/a*/);
-assertArrayEquals(expected, result, 3);
+assertArrayEquals(["a", "b"], "ab".split(/a*?/));
 
-expected = ["a"];
-result = "ab".split(/a*?/, 1);
-assertArrayEquals(expected, result, 4);
+assertArrayEquals(["", "b"], "ab".split(/a*/));
 
-expected = [""];
-result = "ab".split(/a*/, 1);
-assertArrayEquals(expected, result, 5);
+assertArrayEquals(["a"], "ab".split(/a*?/, 1));
 
-expected = ["as","fas","fas","f"];
-result = "asdfasdfasdf".split("d");
-assertArrayEquals(expected, result, 6);
+assertArrayEquals([""], "ab".split(/a*/, 1));
 
-expected = ["as","fas","fas","f"];
-result = "asdfasdfasdf".split("d", -1);
-assertArrayEquals(expected, result, 7);
+assertArrayEquals(["as","fas","fas","f"], "asdfasdfasdf".split("d"));
 
-expected = ["as", "fas"];
-result = "asdfasdfasdf".split("d", 2);
-assertArrayEquals(expected, result, 8);
+assertArrayEquals(["as","fas","fas","f"], "asdfasdfasdf".split("d", -1));
 
-expected = [];
-result = "asdfasdfasdf".split("d", 0);
-assertArrayEquals(expected, result, 9);
+assertArrayEquals(["as", "fas"], "asdfasdfasdf".split("d", 2));
 
-expected = ["as","fas","fas",""];
-result = "asdfasdfasd".split("d");
-assertArrayEquals(expected, result, 10);
+assertArrayEquals([], "asdfasdfasdf".split("d", 0));
 
-expected = [];
-result = "".split("");
-assertArrayEquals(expected, result, 11);
+assertArrayEquals(["as","fas","fas",""], "asdfasdfasd".split("d"));
 
-expected = [""]
-result = "".split("a");
-assertArrayEquals(expected, result, 12);
+assertArrayEquals([], "".split(""));
 
-expected = ["a","b"]
-result = "axxb".split(/x*/);
-assertArrayEquals(expected, result, 13);
+assertArrayEquals([""], "".split("a"));
 
-expected = ["a","b"]
-result = "axxb".split(/x+/);
-assertArrayEquals(expected, result, 14);
+assertArrayEquals(["a","b"], "axxb".split(/x*/));
 
-expected = ["a","","b"]
-result = "axxb".split(/x/);
-assertArrayEquals(expected, result, 15);
+assertArrayEquals(["a","b"], "axxb".split(/x+/));
+
+assertArrayEquals(["a","","b"], "axxb".split(/x/));
 
 // This was http://b/issue?id=1151354
-expected = ["div", "#id", ".class"]
-result = "div#id.class".split(/(?=[#.])/);
-assertArrayEquals(expected, result, 16);
+assertArrayEquals(["div", "#id", ".class"], "div#id.class".split(/(?=[#.])/));
+
 
-expected = ["div", "#i", "d", ".class"]
-result = "div#id.class".split(/(?=[d#.])/);
-assertArrayEquals(expected, result, 17);
+assertArrayEquals(["div", "#i", "d", ".class"], "div#id.class".split(/(?=[d#.])/));
+
+assertArrayEquals(["a", "b", "c"], "abc".split(/(?=.)/));
 
-expected = ["a", "b", "c"]
-result = "abc".split(/(?=.)/);
-assertArrayEquals(expected, result, 18);
 
 /* "ab".split(/((?=.))/)
  * 
@@ -108,19 +77,23 @@ assertArrayEquals(expected, result, 18);
  * 
  * Opera seems to have this right.  The others make no sense.
  */
-expected = ["a", "", "b"]
-result = "ab".split(/((?=.))/);
-assertArrayEquals(expected, result, 19);
+assertArrayEquals(["a", "", "b"], "ab".split(/((?=.))/));
 
 /* "ab".split(/(?=)/)
  *
  * KJS:   a,b
  * SM:    ab
  * IE:    a,b
- * Opera: a,b
+ * Opera: a,bb
  * V8:    a,b
  */
-expected = ["a", "b"]
-result = "ab".split(/(?=)/);
-assertArrayEquals(expected, result, 20);
+assertArrayEquals(["a", "b"], "ab".split(/(?=)/));
+
 
+// For issue http://code.google.com/p/v8/issues/detail?id=924
+// Splitting the empty string is a special case.
+assertEquals([""], ''.split());
+assertEquals([""], ''.split(/./));
+assertEquals([], ''.split(/.?/));
+assertEquals([], ''.split(/.??/));
+assertEquals([], ''.split(/()()/));
index 17d556f1cf788432de54ec9c10ce845292af7df7..30b15a97373630bef4122d05c0ffcbebecf253a8 100644 (file)
         '../../src/ast.cc',
         '../../src/ast-inl.h',
         '../../src/ast.h',
+        '../../src/bignum.cc',
+        '../../src/bignum.h',
+        '../../src/bignum-dtoa.cc',
+        '../../src/bignum-dtoa.h',
         '../../src/bootstrapper.cc',
         '../../src/bootstrapper.h',
         '../../src/builtins.cc',
         '../../src/rewriter.h',
         '../../src/runtime.cc',
         '../../src/runtime.h',
+        '../../src/scanner-base.cc',
+        '../../src/scanner-base.h',
         '../../src/scanner.cc',
         '../../src/scanner.h',
         '../../src/scopeinfo.cc',
         '../../src/zone-inl.h',
         '../../src/zone.cc',
         '../../src/zone.h',
+       '../../src/extensions/externalize-string-extension.cc',
+       '../../src/extensions/externalize-string-extension.h',
+       '../../src/extensions/gc-extension.cc',
+       '../../src/extensions/gc-extension.h',
       ],
       'conditions': [
         ['v8_target_arch=="arm"', {
index e69c9a85ac8e3ee033779c2f2847b3061abbf226..ebf8bd89396faf6ffe08aef46919b588e3d02216 100755 (executable)
@@ -195,7 +195,7 @@ class CppLintProcessor(SourceFileProcessor):
               or (name in CppLintProcessor.IGNORE_LINT))
 
   def GetPathsToSearch(self):
-    return ['src', 'public', 'samples', join('test', 'cctest')]
+    return ['src', 'include', 'samples', join('test', 'cctest')]
 
   def ProcessFiles(self, files, path):
     good_files_cache = FileContentsCache('.cpplint-cache')
index 62d450152f8998fdfd5e7d8b2b187da682b295ba..615889c9167c0b368c0f845645d88196aa7839e2 100644 (file)
                                        />
                                </FileConfiguration>
                        </File>
+               <File
+                               RelativePath="..\..\src\bignum.cc"
+                               >
+                       </File>
+               <File
+                               RelativePath="..\..\src\bignum.h"
+                               >
+                       </File>
+               <File
+                               RelativePath="..\..\src\bignum-dtoa.cc"
+                               >
+                       </File>
+               <File
+                               RelativePath="..\..\src\bignum-dtoa.h"
+                               >
+                       </File>
                <File
                                RelativePath="..\..\src\dtoa.cc"
                                >
                                RelativePath="..\..\src\ast.h"
                                >
                        </File>
+                       <File
+                               RelativePath="..\..\src\bignum.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\bignum.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\bignum-dtoa.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\bignum-dtoa.h"
+                               >
+                       </File>
                        <File
                                RelativePath="..\..\src\bootstrapper.cc"
                                >
                                RelativePath="..\..\src\runtime.h"
                                >
                        </File>
+                       <File
+                               RelativePath="..\..\src\scanner-base.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\scanner-base.h"
+                               >
+                       </File>
                        <File
                                RelativePath="..\..\src\scanner.cc"
                                >
                                RelativePath="..\..\src\zone.h"
                                >
                        </File>
+                       <File
+                               RelativePath="..\..\src\extensions\externalize-string-extension.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\extensions\externalize-string-extension.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\extensions\gc-extension.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\extensions\gc-extension.h"
+                               >
+                       </File>
                        <Filter
                                Name="third party"
                                >