Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/deps
diff options
context:
space:
mode:
authorRyan Dahl <ry@tinyclouds.org>2010-11-19 21:49:09 +0300
committerRyan Dahl <ry@tinyclouds.org>2010-11-19 21:49:09 +0300
commitcbdcc1d5f321cfff3d4d3f416e48733089de7e00 (patch)
tree5d44f3a1fdb3d48326566126eca8e31729f6db90 /deps
parentf11291a220136164294e3cac5f09efd6c2b21be6 (diff)
Upgrade V8 to 2.5.7
Diffstat (limited to 'deps')
-rw-r--r--deps/v8/AUTHORS1
-rw-r--r--deps/v8/ChangeLog47
-rwxr-xr-xdeps/v8/include/v8-debug.h4
-rw-r--r--deps/v8/include/v8.h64
-rw-r--r--deps/v8/include/v8stdint.h53
-rwxr-xr-xdeps/v8/src/SConscript5
-rw-r--r--deps/v8/src/accessors.cc6
-rw-r--r--deps/v8/src/allocation.cc18
-rw-r--r--deps/v8/src/allocation.h4
-rw-r--r--deps/v8/src/api.cc20
-rw-r--r--deps/v8/src/arm/assembler-arm.cc114
-rw-r--r--deps/v8/src/arm/assembler-arm.h46
-rw-r--r--deps/v8/src/arm/codegen-arm.cc114
-rw-r--r--deps/v8/src/arm/codegen-arm.h14
-rw-r--r--deps/v8/src/arm/constants-arm.h7
-rw-r--r--deps/v8/src/arm/disasm-arm.cc23
-rw-r--r--deps/v8/src/arm/full-codegen-arm.cc165
-rw-r--r--deps/v8/src/arm/ic-arm.cc4
-rw-r--r--deps/v8/src/arm/macro-assembler-arm.cc26
-rw-r--r--deps/v8/src/arm/macro-assembler-arm.h10
-rw-r--r--deps/v8/src/arm/simulator-arm.cc108
-rw-r--r--deps/v8/src/arm/simulator-arm.h3
-rw-r--r--deps/v8/src/arm/stub-cache-arm.cc139
-rw-r--r--deps/v8/src/arm/virtual-frame-arm.cc7
-rw-r--r--deps/v8/src/assembler.cc49
-rw-r--r--deps/v8/src/assembler.h61
-rw-r--r--deps/v8/src/bignum-dtoa.cc655
-rw-r--r--deps/v8/src/bignum-dtoa.h81
-rw-r--r--deps/v8/src/bignum.cc767
-rw-r--r--deps/v8/src/bignum.h140
-rw-r--r--deps/v8/src/bootstrapper.cc4
-rw-r--r--deps/v8/src/checks.cc9
-rw-r--r--deps/v8/src/checks.h19
-rw-r--r--deps/v8/src/code-stubs.cc34
-rw-r--r--deps/v8/src/code-stubs.h32
-rw-r--r--deps/v8/src/codegen.cc62
-rw-r--r--deps/v8/src/codegen.h2
-rwxr-xr-xdeps/v8/src/compiler.cc1
-rw-r--r--deps/v8/src/conversions.cc97
-rw-r--r--deps/v8/src/dateparser.h17
-rw-r--r--deps/v8/src/debug-debugger.js32
-rw-r--r--deps/v8/src/debug.cc1
-rw-r--r--deps/v8/src/double.h32
-rw-r--r--deps/v8/src/dtoa.cc41
-rw-r--r--deps/v8/src/dtoa.h14
-rw-r--r--deps/v8/src/execution.cc131
-rw-r--r--deps/v8/src/execution.h26
-rw-r--r--deps/v8/src/extensions/externalize-string-extension.cc141
-rw-r--r--deps/v8/src/extensions/externalize-string-extension.h50
-rw-r--r--deps/v8/src/extensions/gc-extension.cc54
-rw-r--r--deps/v8/src/extensions/gc-extension.h49
-rw-r--r--deps/v8/src/flag-definitions.h1
-rw-r--r--deps/v8/src/full-codegen.cc17
-rw-r--r--deps/v8/src/full-codegen.h7
-rw-r--r--deps/v8/src/global-handles.cc6
-rw-r--r--deps/v8/src/global-handles.h3
-rw-r--r--deps/v8/src/globals.h432
-rw-r--r--deps/v8/src/handles.cc4
-rw-r--r--deps/v8/src/heap-inl.h7
-rw-r--r--deps/v8/src/heap-profiler.cc8
-rw-r--r--deps/v8/src/heap.cc200
-rw-r--r--deps/v8/src/heap.h55
-rw-r--r--deps/v8/src/ia32/assembler-ia32.cc54
-rw-r--r--deps/v8/src/ia32/assembler-ia32.h17
-rw-r--r--deps/v8/src/ia32/code-stubs-ia32.cc9
-rw-r--r--deps/v8/src/ia32/codegen-ia32.cc123
-rw-r--r--deps/v8/src/ia32/codegen-ia32.h17
-rw-r--r--deps/v8/src/ia32/full-codegen-ia32.cc146
-rw-r--r--deps/v8/src/ia32/ic-ia32.cc1
-rw-r--r--deps/v8/src/ia32/macro-assembler-ia32.cc90
-rw-r--r--deps/v8/src/ia32/macro-assembler-ia32.h46
-rw-r--r--deps/v8/src/ia32/stub-cache-ia32.cc243
-rw-r--r--deps/v8/src/ia32/virtual-frame-ia32.cc5
-rw-r--r--deps/v8/src/jump-target-heavy.cc5
-rw-r--r--deps/v8/src/jump-target-light.cc5
-rw-r--r--deps/v8/src/list.h8
-rw-r--r--deps/v8/src/mark-compact.cc16
-rw-r--r--deps/v8/src/mark-compact.h3
-rw-r--r--deps/v8/src/objects-debug.cc2
-rw-r--r--deps/v8/src/objects-inl.h42
-rw-r--r--deps/v8/src/objects.cc8
-rw-r--r--deps/v8/src/objects.h4
-rw-r--r--deps/v8/src/parser.cc1146
-rw-r--r--deps/v8/src/parser.h240
-rw-r--r--deps/v8/src/platform-linux.cc71
-rw-r--r--deps/v8/src/platform-win32.cc5
-rw-r--r--deps/v8/src/preparser.h1419
-rw-r--r--deps/v8/src/prescanner.h1098
-rw-r--r--deps/v8/src/profile-generator.cc30
-rw-r--r--deps/v8/src/profile-generator.h2
-rw-r--r--deps/v8/src/regexp.js168
-rw-r--r--deps/v8/src/runtime.cc66
-rw-r--r--deps/v8/src/runtime.h5
-rw-r--r--deps/v8/src/scanner-base.cc195
-rw-r--r--deps/v8/src/scanner-base.h206
-rwxr-xr-xdeps/v8/src/scanner.cc323
-rw-r--r--deps/v8/src/scanner.h231
-rw-r--r--deps/v8/src/serialize.cc4
-rw-r--r--deps/v8/src/spaces.cc66
-rw-r--r--deps/v8/src/spaces.h32
-rw-r--r--deps/v8/src/string.js82
-rw-r--r--deps/v8/src/strtod.cc129
-rw-r--r--deps/v8/src/stub-cache.cc28
-rw-r--r--deps/v8/src/stub-cache.h4
-rw-r--r--deps/v8/src/token.h2
-rw-r--r--deps/v8/src/utils.cc36
-rw-r--r--deps/v8/src/utils.h317
-rw-r--r--deps/v8/src/v8.cc38
-rw-r--r--deps/v8/src/v8.h9
-rw-r--r--deps/v8/src/v8globals.h464
-rw-r--r--deps/v8/src/v8utils.h301
-rw-r--r--deps/v8/src/version.cc2
-rw-r--r--deps/v8/src/virtual-frame.h13
-rw-r--r--deps/v8/src/x64/assembler-x64.cc54
-rw-r--r--deps/v8/src/x64/assembler-x64.h15
-rw-r--r--deps/v8/src/x64/code-stubs-x64.cc33
-rw-r--r--deps/v8/src/x64/codegen-x64.cc111
-rw-r--r--deps/v8/src/x64/codegen-x64.h14
-rw-r--r--deps/v8/src/x64/full-codegen-x64.cc196
-rw-r--r--deps/v8/src/x64/ic-x64.cc1
-rw-r--r--deps/v8/src/x64/macro-assembler-x64.cc127
-rw-r--r--deps/v8/src/x64/macro-assembler-x64.h75
-rw-r--r--deps/v8/src/x64/stub-cache-x64.cc257
-rw-r--r--deps/v8/src/x64/virtual-frame-x64.cc5
-rw-r--r--deps/v8/test/cctest/SConscript3
-rw-r--r--deps/v8/test/cctest/test-api.cc3
-rw-r--r--deps/v8/test/cctest/test-assembler-arm.cc68
-rw-r--r--deps/v8/test/cctest/test-bignum-dtoa.cc315
-rw-r--r--deps/v8/test/cctest/test-bignum.cc1502
-rw-r--r--deps/v8/test/cctest/test-debug.cc45
-rw-r--r--deps/v8/test/cctest/test-disasm-arm.cc17
-rw-r--r--deps/v8/test/cctest/test-double.cc16
-rw-r--r--deps/v8/test/cctest/test-dtoa.cc331
-rw-r--r--deps/v8/test/cctest/test-heap-profiler.cc35
-rw-r--r--deps/v8/test/cctest/test-heap.cc29
-rw-r--r--deps/v8/test/cctest/test-mark-compact.cc4
-rwxr-xr-xdeps/v8/test/cctest/test-parsing.cc91
-rw-r--r--deps/v8/test/cctest/test-spaces.cc6
-rw-r--r--deps/v8/test/cctest/test-strtod.cc181
-rw-r--r--deps/v8/test/mjsunit/regress/regress-918.js33
-rw-r--r--deps/v8/test/mjsunit/regress/regress-927.js33
-rw-r--r--deps/v8/test/mjsunit/regress/regress-931.js48
-rw-r--r--deps/v8/test/mjsunit/regress/regress-conditional-position.js95
-rw-r--r--deps/v8/test/mjsunit/string-split.js91
-rw-r--r--deps/v8/tools/gyp/v8.gyp10
-rwxr-xr-xdeps/v8/tools/presubmit.py2
-rw-r--r--deps/v8/tools/visual_studio/v8_base.vcproj56
147 files changed, 11695 insertions, 4126 deletions
diff --git a/deps/v8/AUTHORS b/deps/v8/AUTHORS
index 3749cebcd17..68f9b63babb 100644
--- a/deps/v8/AUTHORS
+++ b/deps/v8/AUTHORS
@@ -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>
diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog
index 69aff33d185..c618f202f9b 100644
--- a/deps/v8/ChangeLog
+++ b/deps/v8/ChangeLog
@@ -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
diff --git a/deps/v8/include/v8-debug.h b/deps/v8/include/v8-debug.h
index 4314727adc4..f17b848550d 100755
--- a/deps/v8/include/v8-debug.h
+++ b/deps/v8/include/v8-debug.h
@@ -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
diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h
index c7e4552b4d4..9baa17db1d5 100644
--- a/deps/v8/include/v8.h
+++ b/deps/v8/include/v8.h
@@ -38,23 +38,9 @@
#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
index 00000000000..50b4f29a64f
--- /dev/null
+++ b/deps/v8/include/v8stdint.h
@@ -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_
diff --git a/deps/v8/src/SConscript b/deps/v8/src/SConscript
index ef5485d8542..316387fa231 100755
--- a/deps/v8/src/SConscript
+++ b/deps/v8/src/SConscript
@@ -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
diff --git a/deps/v8/src/accessors.cc b/deps/v8/src/accessors.cc
index 7c21659ebc4..08ef41b9f7e 100644
--- a/deps/v8/src/accessors.cc
+++ b/deps/v8/src/accessors.cc
@@ -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;
}
diff --git a/deps/v8/src/allocation.cc b/deps/v8/src/allocation.cc
index 678f4fd7d2f..d74c37cd799 100644
--- a/deps/v8/src/allocation.cc
+++ b/deps/v8/src/allocation.cc
@@ -27,16 +27,21 @@
#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_;
diff --git a/deps/v8/src/allocation.h b/deps/v8/src/allocation.h
index 70a3a038899..6f4bd2fb545 100644
--- a/deps/v8/src/allocation.h
+++ b/deps/v8/src/allocation.h
@@ -31,6 +31,10 @@
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!
diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc
index 617922dd5a7..59124491698 100644
--- a/deps/v8/src/api.cc
+++ b/deps/v8/src/api.cc
@@ -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());
}
diff --git a/deps/v8/src/arm/assembler-arm.cc b/deps/v8/src/arm/assembler-arm.cc
index ebbd9b1138a..4cb421c577e 100644
--- a/deps/v8/src/arm/assembler-arm.cc
+++ b/deps/v8/src/arm/assembler-arm.cc
@@ -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");
diff --git a/deps/v8/src/arm/assembler-arm.h b/deps/v8/src/arm/assembler-arm.h
index 5b647a7537e..606ff86340e 100644
--- a/deps/v8/src/arm/assembler-arm.h
+++ b/deps/v8/src/arm/assembler-arm.h
@@ -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_
diff --git a/deps/v8/src/arm/codegen-arm.cc b/deps/v8/src/arm/codegen-arm.cc
index 70ff244649c..dd0520feed4 100644
--- a/deps/v8/src/arm/codegen-arm.cc
+++ b/deps/v8/src/arm/codegen-arm.cc
@@ -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);
diff --git a/deps/v8/src/arm/codegen-arm.h b/deps/v8/src/arm/codegen-arm.h
index e6fd6071e1d..2e8f46668c1 100644
--- a/deps/v8/src/arm/codegen-arm.h
+++ b/deps/v8/src/arm/codegen-arm.h
@@ -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);
diff --git a/deps/v8/src/arm/constants-arm.h b/deps/v8/src/arm/constants-arm.h
index 123c5e79720..36f6283c967 100644
--- a/deps/v8/src/arm/constants-arm.h
+++ b/deps/v8/src/arm/constants-arm.h
@@ -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;
diff --git a/deps/v8/src/arm/disasm-arm.cc b/deps/v8/src/arm/disasm-arm.cc
index 4e7580f8684..297a2db5b2e 100644
--- a/deps/v8/src/arm/disasm-arm.cc
+++ b/deps/v8/src/arm/disasm-arm.cc
@@ -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");
+ }
+ }
}
}
}
diff --git a/deps/v8/src/arm/full-codegen-arm.cc b/deps/v8/src/arm/full-codegen-arm.cc
index 9935e038f5c..c50f84ad5e6 100644
--- a/deps/v8/src/arm/full-codegen-arm.cc
+++ b/deps/v8/src/arm/full-codegen-arm.cc
@@ -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
diff --git a/deps/v8/src/arm/ic-arm.cc b/deps/v8/src/arm/ic-arm.cc
index a09afdf754e..4c1f9835f4d 100644
--- a/deps/v8/src/arm/ic-arm.cc
+++ b/deps/v8/src/arm/ic-arm.cc
@@ -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);
diff --git a/deps/v8/src/arm/macro-assembler-arm.cc b/deps/v8/src/arm/macro-assembler-arm.cc
index 7f6090bc50f..d2c22af53df 100644
--- a/deps/v8/src/arm/macro-assembler-arm.cc
+++ b/deps/v8/src/arm/macro-assembler-arm.cc
@@ -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);
}
diff --git a/deps/v8/src/arm/macro-assembler-arm.h b/deps/v8/src/arm/macro-assembler-arm.h
index 48a80599669..8d89d6984ce 100644
--- a/deps/v8/src/arm/macro-assembler-arm.h
+++ b/deps/v8/src/arm/macro-assembler-arm.h
@@ -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)
diff --git a/deps/v8/src/arm/simulator-arm.cc b/deps/v8/src/arm/simulator-arm.cc
index cb91520f3a5..3ec5f449d8a 100644
--- a/deps/v8/src/arm/simulator-arm.cc
+++ b/deps/v8/src/arm/simulator-arm.cc
@@ -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);
diff --git a/deps/v8/src/arm/simulator-arm.h b/deps/v8/src/arm/simulator-arm.h
index 3e023489eef..c37b3f7156d 100644
--- a/deps/v8/src/arm/simulator-arm.h
+++ b/deps/v8/src/arm/simulator-arm.h
@@ -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_;
diff --git a/deps/v8/src/arm/stub-cache-arm.cc b/deps/v8/src/arm/stub-cache-arm.cc
index 5e29c2e4850..a0ef80a0fde 100644
--- a/deps/v8/src/arm/stub-cache-arm.cc
+++ b/deps/v8/src/arm/stub-cache-arm.cc
@@ -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);
}
diff --git a/deps/v8/src/arm/virtual-frame-arm.cc b/deps/v8/src/arm/virtual-frame-arm.cc
index da76edf3919..45f48767c4d 100644
--- a/deps/v8/src/arm/virtual-frame-arm.cc
+++ b/deps/v8/src/arm/virtual-frame-arm.cc
@@ -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);
}
diff --git a/deps/v8/src/assembler.cc b/deps/v8/src/assembler.cc
index ce90dceacbc..7493673e819 100644
--- a/deps/v8/src/assembler.cc
+++ b/deps/v8/src/assembler.cc
@@ -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
diff --git a/deps/v8/src/assembler.h b/deps/v8/src/assembler.h
index 66811777fad..09159fed08e 100644
--- a/deps/v8/src/assembler.h
+++ b/deps/v8/src/assembler.h
@@ -585,6 +585,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
static inline bool is_intn(int x, int n) {
diff --git a/deps/v8/src/bignum-dtoa.cc b/deps/v8/src/bignum-dtoa.cc
new file mode 100644
index 00000000000..088dd79f550
--- /dev/null
+++ b/deps/v8/src/bignum-dtoa.cc
@@ -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
index 00000000000..ea1acbbfc80
--- /dev/null
+++ b/deps/v8/src/bignum-dtoa.h
@@ -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
index 00000000000..dd1537a25a0
--- /dev/null
+++ b/deps/v8/src/bignum.cc
@@ -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
index 00000000000..1d2bff61a5e
--- /dev/null
+++ b/deps/v8/src/bignum.h
@@ -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_
diff --git a/deps/v8/src/bootstrapper.cc b/deps/v8/src/bootstrapper.cc
index 0e49966bbdd..f60a975dc10 100644
--- a/deps/v8/src/bootstrapper.cc
+++ b/deps/v8/src/bootstrapper.cc
@@ -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();
}
diff --git a/deps/v8/src/checks.cc b/deps/v8/src/checks.cc
index b5df316d0f7..1ab8802ec3f 100644
--- a/deps/v8/src/checks.cc
+++ b/deps/v8/src/checks.cc
@@ -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
diff --git a/deps/v8/src/checks.h b/deps/v8/src/checks.h
index 5ea59920ac1..6b493225ad0 100644
--- a/deps/v8/src/checks.h
+++ b/deps/v8/src/checks.h
@@ -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)
diff --git a/deps/v8/src/code-stubs.cc b/deps/v8/src/code-stubs.cc
index 787ec2a7a1e..8b9198fb99e 100644
--- a/deps/v8/src/code-stubs.cc
+++ b/deps/v8/src/code-stubs.cc
@@ -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));
}
}
diff --git a/deps/v8/src/code-stubs.h b/deps/v8/src/code-stubs.h
index c0a8d3063c8..b156647d5d3 100644
--- a/deps/v8/src/code-stubs.h
+++ b/deps/v8/src/code-stubs.h
@@ -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() { }
diff --git a/deps/v8/src/codegen.cc b/deps/v8/src/codegen.cc
index bda697abafd..fb8c5cd4a31 100644
--- a/deps/v8/src/codegen.cc
+++ b/deps/v8/src/codegen.cc
@@ -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
diff --git a/deps/v8/src/codegen.h b/deps/v8/src/codegen.h
index 8f923dd34b2..66300d6caf4 100644
--- a/deps/v8/src/codegen.h
+++ b/deps/v8/src/codegen.h
@@ -58,8 +58,6 @@
// Generate
// ComputeLazyCompile
// BuildFunctionInfo
-// ComputeCallInitialize
-// ComputeCallInitializeInLoop
// ProcessDeclarations
// DeclareGlobals
// CheckForInlineRuntimeCall
diff --git a/deps/v8/src/compiler.cc b/deps/v8/src/compiler.cc
index 6f02960dda7..29bbbc7034e 100755
--- a/deps/v8/src/compiler.cc
+++ b/deps/v8/src/compiler.cc
@@ -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);
}
diff --git a/deps/v8/src/conversions.cc b/deps/v8/src/conversions.cc
index 790e807aef4..c0dbf73ad02 100644
--- a/deps/v8/src/conversions.cc
+++ b/deps/v8/src/conversions.cc
@@ -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;
}
diff --git a/deps/v8/src/dateparser.h b/deps/v8/src/dateparser.h
index cae9b08d5b1..28053f46d12 100644
--- a/deps/v8/src/dateparser.h
+++ b/deps/v8/src/dateparser.h
@@ -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() {
diff --git a/deps/v8/src/debug-debugger.js b/deps/v8/src/debug-debugger.js
index 0eab8d1b831..d091991a119 100644
--- a/deps/v8/src/debug-debugger.js
+++ b/deps/v8/src/debug-debugger.js
@@ -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
diff --git a/deps/v8/src/debug.cc b/deps/v8/src/debug.cc
index 24f04098610..f3bf954da9b 100644
--- a/deps/v8/src/debug.cc
+++ b/deps/v8/src/debug.cc
@@ -1839,6 +1839,7 @@ bool Debug::IsDebugGlobal(GlobalObject* global) {
void Debug::ClearMirrorCache() {
+ PostponeInterruptsScope postpone;
HandleScope scope;
ASSERT(Top::context() == *Debug::debug_context());
diff --git a/deps/v8/src/double.h b/deps/v8/src/double.h
index e805173e07e..65eded99893 100644
--- a/deps/v8/src/double.h
+++ b/deps/v8/src/double.h
@@ -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));
diff --git a/deps/v8/src/dtoa.cc b/deps/v8/src/dtoa.cc
index f4141eb6198..b857a5dc599 100644
--- a/deps/v8/src/dtoa.cc
+++ b/deps/v8/src/dtoa.cc
@@ -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"
@@ -37,7 +38,19 @@
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
diff --git a/deps/v8/src/dtoa.h b/deps/v8/src/dtoa.h
index be0d5456b23..b3e79afa482 100644
--- a/deps/v8/src/dtoa.h
+++ b/deps/v8/src/dtoa.h
@@ -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
diff --git a/deps/v8/src/execution.cc b/deps/v8/src/execution.cc
index 885bf63cf1b..691d56954a9 100644
--- a/deps/v8/src/execution.cc
+++ b/deps/v8/src/execution.cc
@@ -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
diff --git a/deps/v8/src/execution.h b/deps/v8/src/execution.h
index 5547803be79..a2ddc41a15f 100644
--- a/deps/v8/src/execution.h
+++ b/deps/v8/src/execution.h
@@ -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
index 00000000000..8b4bdbd88e4
--- /dev/null
+++ b/deps/v8/src/extensions/externalize-string-extension.cc
@@ -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
index 00000000000..b97b4962cf0
--- /dev/null
+++ b/deps/v8/src/extensions/externalize-string-extension.h
@@ -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
index 00000000000..b8f081c54dd
--- /dev/null
+++ b/deps/v8/src/extensions/gc-extension.cc
@@ -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
index 00000000000..06ea4ed21a6
--- /dev/null
+++ b/deps/v8/src/extensions/gc-extension.h
@@ -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_
diff --git a/deps/v8/src/flag-definitions.h b/deps/v8/src/flag-definitions.h
index 54501ec95d9..46feea77ac2 100644
--- a/deps/v8/src/flag-definitions.h
+++ b/deps/v8/src/flag-definitions.h
@@ -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,
diff --git a/deps/v8/src/full-codegen.cc b/deps/v8/src/full-codegen.cc
index 97987c27a80..85924725245 100644
--- a/deps/v8/src/full-codegen.cc
+++ b/deps/v8/src/full-codegen.cc
@@ -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 __
diff --git a/deps/v8/src/full-codegen.h b/deps/v8/src/full-codegen.h
index 201507b2af3..6a1def6ee19 100644
--- a/deps/v8/src/full-codegen.h
+++ b/deps/v8/src/full-codegen.h
@@ -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)
diff --git a/deps/v8/src/global-handles.cc b/deps/v8/src/global-handles.cc
index 9ede9085283..5339840988d 100644
--- a/deps/v8/src/global-handles.cc
+++ b/deps/v8/src/global-handles.cc
@@ -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;
}
diff --git a/deps/v8/src/global-handles.h b/deps/v8/src/global-handles.h
index 659f86eca70..37b2b44522e 100644
--- a/deps/v8/src/global-handles.h
+++ b/deps/v8/src/global-handles.h
@@ -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);
diff --git a/deps/v8/src/globals.h b/deps/v8/src/globals.h
index c218f80dc11..88c3e780d94 100644
--- a/deps/v8/src/globals.h
+++ b/deps/v8/src/globals.h
@@ -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
diff --git a/deps/v8/src/handles.cc b/deps/v8/src/handles.cc
index 7a46bc3ea25..1364951b714 100644
--- a/deps/v8/src/handles.cc
+++ b/deps/v8/src/handles.cc
@@ -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());
}
diff --git a/deps/v8/src/heap-inl.h b/deps/v8/src/heap-inl.h
index 15feb9d5fb9..ba50c0f7358 100644
--- a/deps/v8/src/heap-inl.h
+++ b/deps/v8/src/heap-inl.h
@@ -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; \
diff --git a/deps/v8/src/heap-profiler.cc b/deps/v8/src/heap-profiler.cc
index e47d66f9848..d3cc4ab9106 100644
--- a/deps/v8/src/heap-profiler.cc
+++ b/deps/v8/src/heap-profiler.cc
@@ -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);
diff --git a/deps/v8/src/heap.cc b/deps/v8/src/heap.cc
index b037efd8045..26859d7c07f 100644
--- a/deps/v8/src/heap.cc
+++ b/deps/v8/src/heap.cc
@@ -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;
diff --git a/deps/v8/src/heap.h b/deps/v8/src/heap.h
index 8ff2f5f3413..93caf3bd4e4 100644
--- a/deps/v8/src/heap.h
+++ b/deps/v8/src/heap.h
@@ -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.
diff --git a/deps/v8/src/ia32/assembler-ia32.cc b/deps/v8/src/ia32/assembler-ia32.cc
index 019f478adc5..125f503bec3 100644
--- a/deps/v8/src/ia32/assembler-ia32.cc
+++ b/deps/v8/src/ia32/assembler-ia32.cc
@@ -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");
diff --git a/deps/v8/src/ia32/assembler-ia32.h b/deps/v8/src/ia32/assembler-ia32.h
index 5286788fa72..79637a19010 100644
--- a/deps/v8/src/ia32/assembler-ia32.h
+++ b/deps/v8/src/ia32/assembler-ia32.h
@@ -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;
};
diff --git a/deps/v8/src/ia32/code-stubs-ia32.cc b/deps/v8/src/ia32/code-stubs-ia32.cc
index b2b73926b9a..6ac89bfbac0 100644
--- a/deps/v8/src/ia32/code-stubs-ia32.cc
+++ b/deps/v8/src/ia32/code-stubs-ia32.cc
@@ -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,
diff --git a/deps/v8/src/ia32/codegen-ia32.cc b/deps/v8/src/ia32/codegen-ia32.cc
index 6d23dd7df99..fb7a138d5cb 100644
--- a/deps/v8/src/ia32/codegen-ia32.cc
+++ b/deps/v8/src/ia32/codegen-ia32.cc
@@ -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;
diff --git a/deps/v8/src/ia32/codegen-ia32.h b/deps/v8/src/ia32/codegen-ia32.h
index 4594b19ddd2..a945e217ab7 100644
--- a/deps/v8/src/ia32/codegen-ia32.h
+++ b/deps/v8/src/ia32/codegen-ia32.h
@@ -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);
diff --git a/deps/v8/src/ia32/full-codegen-ia32.cc b/deps/v8/src/ia32/full-codegen-ia32.cc
index ee4e6458ae3..ad32dc85bed 100644
--- a/deps/v8/src/ia32/full-codegen-ia32.cc
+++ b/deps/v8/src/ia32/full-codegen-ia32.cc
@@ -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
diff --git a/deps/v8/src/ia32/ic-ia32.cc b/deps/v8/src/ia32/ic-ia32.cc
index b5f4deefeb9..a0bc086d871 100644
--- a/deps/v8/src/ia32/ic-ia32.cc
+++ b/deps/v8/src/ia32/ic-ia32.cc
@@ -33,7 +33,6 @@
#include "ic-inl.h"
#include "runtime.h"
#include "stub-cache.h"
-#include "utils.h"
namespace v8 {
namespace internal {
diff --git a/deps/v8/src/ia32/macro-assembler-ia32.cc b/deps/v8/src/ia32/macro-assembler-ia32.cc
index b72f4df0e7e..db26c104257 100644
--- a/deps/v8/src/ia32/macro-assembler-ia32.cc
+++ b/deps/v8/src/ia32/macro-assembler-ia32.cc
@@ -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,
diff --git a/deps/v8/src/ia32/macro-assembler-ia32.h b/deps/v8/src/ia32/macro-assembler-ia32.h
index 7b9b843939e..0a6e0ee35b6 100644
--- a/deps/v8/src/ia32/macro-assembler-ia32.h
+++ b/deps/v8/src/ia32/macro-assembler-ia32.h
@@ -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);
diff --git a/deps/v8/src/ia32/stub-cache-ia32.cc b/deps/v8/src/ia32/stub-cache-ia32.cc
index e3870883599..4184d4cde30 100644
--- a/deps/v8/src/ia32/stub-cache-ia32.cc
+++ b/deps/v8/src/ia32/stub-cache-ia32.cc
@@ -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));
diff --git a/deps/v8/src/ia32/virtual-frame-ia32.cc b/deps/v8/src/ia32/virtual-frame-ia32.cc
index a31f6e83600..11e1aaf2b38 100644
--- a/deps/v8/src/ia32/virtual-frame-ia32.cc
+++ b/deps/v8/src/ia32/virtual-frame-ia32.cc
@@ -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();
diff --git a/deps/v8/src/jump-target-heavy.cc b/deps/v8/src/jump-target-heavy.cc
index e0585e79429..c3c22f1ac63 100644
--- a/deps/v8/src/jump-target-heavy.cc
+++ b/deps/v8/src/jump-target-heavy.cc
@@ -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);
diff --git a/deps/v8/src/jump-target-light.cc b/deps/v8/src/jump-target-light.cc
index 19f7bfec0a6..36dc176bce7 100644
--- a/deps/v8/src/jump-target-light.cc
+++ b/deps/v8/src/jump-target-light.cc
@@ -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);
diff --git a/deps/v8/src/list.h b/deps/v8/src/list.h
index 5a08212b1e0..24f34945b54 100644
--- a/deps/v8/src/list.h
+++ b/deps/v8/src/list.h
@@ -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_
diff --git a/deps/v8/src/mark-compact.cc b/deps/v8/src/mark-compact.cc
index 484497f087f..40194e36125 100644
--- a/deps/v8/src/mark-compact.cc
+++ b/deps/v8/src/mark-compact.cc
@@ -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();
diff --git a/deps/v8/src/mark-compact.h b/deps/v8/src/mark-compact.h
index 7444c5bf3c2..1b7e60022e5 100644
--- a/deps/v8/src/mark-compact.h
+++ b/deps/v8/src/mark-compact.h
@@ -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;
diff --git a/deps/v8/src/objects-debug.cc b/deps/v8/src/objects-debug.cc
index c0e5610abaf..69219ee3647 100644
--- a/deps/v8/src/objects-debug.cc
+++ b/deps/v8/src/objects-debug.cc
@@ -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() {
diff --git a/deps/v8/src/objects-inl.h b/deps/v8/src/objects-inl.h
index 1852b549bf1..499cb91dde8 100644
--- a/deps/v8/src/objects-inl.h
+++ b/deps/v8/src/objects-inl.h
@@ -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
diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc
index c1cb922de55..8efb0daae6a 100644
--- a/deps/v8/src/objects.cc
+++ b/deps/v8/src/objects.cc
@@ -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++) {
diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h
index 6029ad545b4..b52bac27be9 100644
--- a/deps/v8/src/objects.h
+++ b/deps/v8/src/objects.h
@@ -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.
diff --git a/deps/v8/src/parser.cc b/deps/v8/src/parser.cc
index aad7a615a51..a9ba0e71691 100644
--- a/deps/v8/src/parser.cc
+++ b/deps/v8/src/parser.cc
@@ -36,9 +36,10 @@
#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
diff --git a/deps/v8/src/parser.h b/deps/v8/src/parser.h
index 19b382e8ded..64f621c9e2e 100644
--- a/deps/v8/src/parser.h
+++ b/deps/v8/src/parser.h
@@ -31,13 +31,13 @@
#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).
diff --git a/deps/v8/src/platform-linux.cc b/deps/v8/src/platform-linux.cc
index c0eb21395fe..89003ba83f9 100644
--- a/deps/v8/src/platform-linux.cc
+++ b/deps/v8/src/platform-linux.cc
@@ -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_;
}
diff --git a/deps/v8/src/platform-win32.cc b/deps/v8/src/platform-win32.cc
index caea16cb9be..a0ba5e865ca 100644
--- a/deps/v8/src/platform-win32.cc
+++ b/deps/v8/src/platform-win32.cc
@@ -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
index 00000000000..547e7667526
--- /dev/null
+++ b/deps/v8/src/preparser.h
@@ -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
index 00000000000..7fb8aa5b1da
--- /dev/null
+++ b/deps/v8/src/prescanner.h
@@ -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_
diff --git a/deps/v8/src/profile-generator.cc b/deps/v8/src/profile-generator.cc
index a4d9a828dd4..29f9ab4d353 100644
--- a/deps/v8/src/profile-generator.cc
+++ b/deps/v8/src/profile-generator.cc
@@ -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;
}
diff --git a/deps/v8/src/profile-generator.h b/deps/v8/src/profile-generator.h
index 6f63f6a122b..b691a056e85 100644
--- a/deps/v8/src/profile-generator.h
+++ b/deps/v8/src/profile-generator.h
@@ -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);
diff --git a/deps/v8/src/regexp.js b/deps/v8/src/regexp.js
index 51f4b094d37..d01d04f2e39 100644
--- a/deps/v8/src/regexp.js
+++ b/deps/v8/src/regexp.js
@@ -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);
};
diff --git a/deps/v8/src/runtime.cc b/deps/v8/src/runtime.cc
index fc1a0232295..5534db557ce 100644
--- a/deps/v8/src/runtime.cc
+++ b/deps/v8/src/runtime.cc
@@ -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);
diff --git a/deps/v8/src/runtime.h b/deps/v8/src/runtime.h
index 72a80379701..756099b413f 100644
--- a/deps/v8/src/runtime.h
+++ b/deps/v8/src/runtime.h
@@ -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
index 00000000000..6cde51787f5
--- /dev/null
+++ b/deps/v8/src/scanner-base.cc
@@ -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
index 00000000000..50f30305c4a
--- /dev/null
+++ b/deps/v8/src/scanner-base.h
@@ -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_
diff --git a/deps/v8/src/scanner.cc b/deps/v8/src/scanner.cc
index 79d63f1774d..6b2fcb4c5ec 100755
--- a/deps/v8/src/scanner.cc
+++ b/deps/v8/src/scanner.cc
@@ -30,27 +30,15 @@
#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();
diff --git a/deps/v8/src/scanner.h b/deps/v8/src/scanner.h
index dab3d672815..df5cd729491 100644
--- a/deps/v8/src/scanner.h
+++ b/deps/v8/src/scanner.h
@@ -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_
diff --git a/deps/v8/src/serialize.cc b/deps/v8/src/serialize.cc
index 763c12f4f57..15fed442b95 100644
--- a/deps/v8/src/serialize.cc
+++ b/deps/v8/src/serialize.cc
@@ -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, \
diff --git a/deps/v8/src/spaces.cc b/deps/v8/src/spaces.cc
index e3fb9233129..239c9cd6c9a 100644
--- a/deps/v8/src/spaces.cc
+++ b/deps/v8/src/spaces.cc
@@ -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);
}
diff --git a/deps/v8/src/spaces.h b/deps/v8/src/spaces.h
index 3ed2fe8b98a..60068c3d911 100644
--- a/deps/v8/src/spaces.h
+++ b/deps/v8/src/spaces.h
@@ -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.
diff --git a/deps/v8/src/string.js b/deps/v8/src/string.js
index d97f632b88d..d82ce05237e 100644
--- a/deps/v8/src/string.js
+++ b/deps/v8/src/string.js
@@ -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;
}
diff --git a/deps/v8/src/strtod.cc b/deps/v8/src/strtod.cc
index 0ed1b0d9147..cedbff91ea5 100644
--- a/deps/v8/src/strtod.cc
+++ b/deps/v8/src/strtod.cc
@@ -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
diff --git a/deps/v8/src/stub-cache.cc b/deps/v8/src/stub-cache.cc
index e794f0932db..b7c769c7a25 100644
--- a/deps/v8/src/stub-cache.cc
+++ b/deps/v8/src/stub-cache.cc
@@ -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) {
diff --git a/deps/v8/src/stub-cache.h b/deps/v8/src/stub-cache.h
index 9d947e404b1..4886c7eb29d 100644
--- a/deps/v8/src/stub-cache.h
+++ b/deps/v8/src/stub-cache.h
@@ -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,
diff --git a/deps/v8/src/token.h b/deps/v8/src/token.h
index ebc7fea1cd5..74d9539f498 100644
--- a/deps/v8/src/token.h
+++ b/deps/v8/src/token.h
@@ -28,6 +28,8 @@
#ifndef V8_TOKEN_H_
#define V8_TOKEN_H_
+#include "checks.h"
+
namespace v8 {
namespace internal {
diff --git a/deps/v8/src/utils.cc b/deps/v8/src/utils.cc
index 45a4cd60f8d..7096ba35ab2 100644
--- a/deps/v8/src/utils.cc
+++ b/deps/v8/src/utils.cc
@@ -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
diff --git a/deps/v8/src/utils.h b/deps/v8/src/utils.h
index 05217677885..6270f8efaf0 100644
--- a/deps/v8/src/utils.h
+++ b/deps/v8/src/utils.h
@@ -31,6 +31,10 @@
#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
diff --git a/deps/v8/src/v8.cc b/deps/v8/src/v8.cc
index 0623400abbd..c8d719b1447 100644
--- a/deps/v8/src/v8.cc
+++ b/deps/v8/src/v8.cc
@@ -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);
}
diff --git a/deps/v8/src/v8.h b/deps/v8/src/v8.h
index 9dbdf4c28a9..74e98f151de 100644
--- a/deps/v8/src/v8.h
+++ b/deps/v8/src/v8.h
@@ -53,10 +53,10 @@
// 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
index 00000000000..2815771a29e
--- /dev/null
+++ b/deps/v8/src/v8globals.h
@@ -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
index 00000000000..a907c9f5563
--- /dev/null
+++ b/deps/v8/src/v8utils.h
@@ -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_
diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc
index e27b9153fcc..ae3250fb872 100644
--- a/deps/v8/src/version.cc
+++ b/deps/v8/src/version.cc
@@ -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
diff --git a/deps/v8/src/virtual-frame.h b/deps/v8/src/virtual-frame.h
index 220823ed4b1..65d1009899a 100644
--- a/deps/v8/src/virtual-frame.h
+++ b/deps/v8/src/virtual-frame.h
@@ -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
@@ -43,4 +46,14 @@
#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_
diff --git a/deps/v8/src/x64/assembler-x64.cc b/deps/v8/src/x64/assembler-x64.cc
index bf5ee5bbb77..caed7c8aa9b 100644
--- a/deps/v8/src/x64/assembler-x64.cc
+++ b/deps/v8/src/x64/assembler-x64.cc
@@ -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;
diff --git a/deps/v8/src/x64/assembler-x64.h b/deps/v8/src/x64/assembler-x64.h
index bbc10106276..c7f763222e6 100644
--- a/deps/v8/src/x64/assembler-x64.h
+++ b/deps/v8/src/x64/assembler-x64.h
@@ -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;
};
diff --git a/deps/v8/src/x64/code-stubs-x64.cc b/deps/v8/src/x64/code-stubs-x64.cc
index c179769b8a5..04173e1afb3 100644
--- a/deps/v8/src/x64/code-stubs-x64.cc
+++ b/deps/v8/src/x64/code-stubs-x64.cc
@@ -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
diff --git a/deps/v8/src/x64/codegen-x64.cc b/deps/v8/src/x64/codegen-x64.cc
index 0faf775d51c..6e98a00900f 100644
--- a/deps/v8/src/x64/codegen-x64.cc
+++ b/deps/v8/src/x64/codegen-x64.cc
@@ -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);
diff --git a/deps/v8/src/x64/codegen-x64.h b/deps/v8/src/x64/codegen-x64.h
index 795732451c3..c3270add261 100644
--- a/deps/v8/src/x64/codegen-x64.h
+++ b/deps/v8/src/x64/codegen-x64.h
@@ -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);
diff --git a/deps/v8/src/x64/full-codegen-x64.cc b/deps/v8/src/x64/full-codegen-x64.cc
index 4e0f6d4b624..e4b24ff4cdb 100644
--- a/deps/v8/src/x64/full-codegen-x64.cc
+++ b/deps/v8/src/x64/full-codegen-x64.cc
@@ -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.
diff --git a/deps/v8/src/x64/ic-x64.cc b/deps/v8/src/x64/ic-x64.cc
index 1d95b7f663d..9ec781487be 100644
--- a/deps/v8/src/x64/ic-x64.cc
+++ b/deps/v8/src/x64/ic-x64.cc
@@ -33,7 +33,6 @@
#include "ic-inl.h"
#include "runtime.h"
#include "stub-cache.h"
-#include "utils.h"
namespace v8 {
namespace internal {
diff --git a/deps/v8/src/x64/macro-assembler-x64.cc b/deps/v8/src/x64/macro-assembler-x64.cc
index 293d8a5633f..834a6f6ef59 100644
--- a/deps/v8/src/x64/macro-assembler-x64.cc
+++ b/deps/v8/src/x64/macro-assembler-x64.cc
@@ -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);
diff --git a/deps/v8/src/x64/macro-assembler-x64.h b/deps/v8/src/x64/macro-assembler-x64.h
index 2f6e9561653..5b082fd627e 100644
--- a/deps/v8/src/x64/macro-assembler-x64.h
+++ b/deps/v8/src/x64/macro-assembler-x64.h
@@ -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
diff --git a/deps/v8/src/x64/stub-cache-x64.cc b/deps/v8/src/x64/stub-cache-x64.cc
index 24609bf642b..2e60dd53b46 100644
--- a/deps/v8/src/x64/stub-cache-x64.cc
+++ b/deps/v8/src/x64/stub-cache-x64.cc
@@ -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;
}
diff --git a/deps/v8/src/x64/virtual-frame-x64.cc b/deps/v8/src/x64/virtual-frame-x64.cc
index e88a993b25c..3f7b1db7e5c 100644
--- a/deps/v8/src/x64/virtual-frame-x64.cc
+++ b/deps/v8/src/x64/virtual-frame-x64.cc
@@ -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.
diff --git a/deps/v8/test/cctest/SConscript b/deps/v8/test/cctest/SConscript
index 006653c2e8e..ba3466deec1 100644
--- a/deps/v8/test/cctest/SConscript
+++ b/deps/v8/test/cctest/SConscript
@@ -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',
diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc
index 6eb15d8fbfa..b4f6914ed78 100644
--- a/deps/v8/test/cctest/test-api.cc
+++ b/deps/v8/test/cctest/test-api.cc
@@ -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();
}
diff --git a/deps/v8/test/cctest/test-assembler-arm.cc b/deps/v8/test/cctest/test-assembler-arm.cc
index 4f90b613a83..0f12f985a36 100644
--- a/deps/v8/test/cctest/test-assembler-arm.cc
+++ b/deps/v8/test/cctest/test-assembler-arm.cc
@@ -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
index 00000000000..51a90574d75
--- /dev/null
+++ b/deps/v8/test/cctest/test-bignum-dtoa.cc
@@ -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
index 00000000000..9aa5ef30d0a
--- /dev/null
+++ b/deps/v8/test/cctest/test-bignum.cc
@@ -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);
+}
diff --git a/deps/v8/test/cctest/test-debug.cc b/deps/v8/test/cctest/test-debug.cc
index d59e2f5ad11..748e3e8d91e 100644
--- a/deps/v8/test/cctest/test-debug.cc
+++ b/deps/v8/test/cctest/test-debug.cc
@@ -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
diff --git a/deps/v8/test/cctest/test-disasm-arm.cc b/deps/v8/test/cctest/test-disasm-arm.cc
index 61f5ffc7273..c375831f271 100644
--- a/deps/v8/test/cctest/test-disasm-arm.cc
+++ b/deps/v8/test/cctest/test-disasm-arm.cc
@@ -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();
diff --git a/deps/v8/test/cctest/test-double.cc b/deps/v8/test/cctest/test-double.cc
index a7a604ea433..3594a4fe32a 100644
--- a/deps/v8/test/cctest/test-double.cc
+++ b/deps/v8/test/cctest/test-double.cc
@@ -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
index 00000000000..ff0b660745d
--- /dev/null
+++ b/deps/v8/test/cctest/test-dtoa.cc
@@ -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());
+ }
+}
diff --git a/deps/v8/test/cctest/test-heap-profiler.cc b/deps/v8/test/cctest/test-heap-profiler.cc
index b86a3361605..b165190b0a9 100644
--- a/deps/v8/test/cctest/test-heap-profiler.cc
+++ b/deps/v8/test/cctest/test-heap-profiler.cc
@@ -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);
diff --git a/deps/v8/test/cctest/test-heap.cc b/deps/v8/test/cctest/test-heap.cc
index 94d05555ec5..fbe66ecd746 100644
--- a/deps/v8/test/cctest/test-heap.cc
+++ b/deps/v8/test/cctest/test-heap.cc
@@ -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);
+ }
+}
diff --git a/deps/v8/test/cctest/test-mark-compact.cc b/deps/v8/test/cctest/test-mark-compact.cc
index ea5afecc1e3..994256712f0 100644
--- a/deps/v8/test/cctest/test-mark-compact.cc
+++ b/deps/v8/test/cctest/test-mark-compact.cc
@@ -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
diff --git a/deps/v8/test/cctest/test-parsing.cc b/deps/v8/test/cctest/test-parsing.cc
index 02503f225ca..d661af6c588 100755
--- a/deps/v8/test/cctest/test-parsing.cc
+++ b/deps/v8/test/cctest/test-parsing.cc
@@ -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;
+}
diff --git a/deps/v8/test/cctest/test-spaces.cc b/deps/v8/test/cctest/test-spaces.cc
index 06f1bfaca29..b399a4ef182 100644
--- a/deps/v8/test/cctest/test-spaces.cc
+++ b/deps/v8/test/cctest/test-spaces.cc
@@ -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,
diff --git a/deps/v8/test/cctest/test-strtod.cc b/deps/v8/test/cctest/test-strtod.cc
index 56b26ea1eb9..f5547dbc032 100644
--- a/deps/v8/test/cctest/test-strtod.cc
+++ b/deps/v8/test/cctest/test-strtod.cc
@@ -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
index 00000000000..4b6ddbacf8a
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-918.js
@@ -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
index 00000000000..c671f7d480c
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-927.js
@@ -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
index 00000000000..d2fb8cc2b79
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-931.js
@@ -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
index 00000000000..cd8f7bd7457
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-conditional-position.js
@@ -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);
diff --git a/deps/v8/test/mjsunit/string-split.js b/deps/v8/test/mjsunit/string-split.js
index 59d3ad3ee38..c741f6a3e59 100644
--- a/deps/v8/test/mjsunit/string-split.js
+++ b/deps/v8/test/mjsunit/string-split.js
@@ -27,76 +27,45 @@
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(/()()/));
diff --git a/deps/v8/tools/gyp/v8.gyp b/deps/v8/tools/gyp/v8.gyp
index 17d556f1cf7..30b15a97373 100644
--- a/deps/v8/tools/gyp/v8.gyp
+++ b/deps/v8/tools/gyp/v8.gyp
@@ -280,6 +280,10 @@
'../../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',
@@ -426,6 +430,8 @@
'../../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',
@@ -480,6 +486,10 @@
'../../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"', {
diff --git a/deps/v8/tools/presubmit.py b/deps/v8/tools/presubmit.py
index e69c9a85ac8..ebf8bd89396 100755
--- a/deps/v8/tools/presubmit.py
+++ b/deps/v8/tools/presubmit.py
@@ -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')
diff --git a/deps/v8/tools/visual_studio/v8_base.vcproj b/deps/v8/tools/visual_studio/v8_base.vcproj
index 62d450152f8..615889c9167 100644
--- a/deps/v8/tools/visual_studio/v8_base.vcproj
+++ b/deps/v8/tools/visual_studio/v8_base.vcproj
@@ -145,6 +145,22 @@
</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"
>
</File>
@@ -241,6 +257,22 @@
>
</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"
>
</File>
@@ -882,6 +914,14 @@
>
</File>
<File
+ RelativePath="..\..\src\scanner-base.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\scanner-base.h"
+ >
+ </File>
+ <File
RelativePath="..\..\src\scanner.cc"
>
</File>
@@ -1101,6 +1141,22 @@
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"
>