diff options
author | Ryan Dahl <ry@tinyclouds.org> | 2010-11-17 06:13:52 +0300 |
---|---|---|
committer | Ryan Dahl <ry@tinyclouds.org> | 2010-11-17 06:14:14 +0300 |
commit | 03fa258df7d9e642c3ccac82d27c9c8167681cce (patch) | |
tree | 09dcbd2f391b2e81c0f50c9e2f37afd94fc1479f /deps | |
parent | cea3a95f9fe6faaa504542d4f03349739d08a0f3 (diff) |
Revert "Upgrade V8 to 2.5.6"
This reverts commit 564a48643bd3edc6da845e458277a54c8068d0e2.
Breaks cygwin
Diffstat (limited to 'deps')
99 files changed, 2691 insertions, 6813 deletions
diff --git a/deps/v8/AUTHORS b/deps/v8/AUTHORS index 68f9b63babb..3749cebcd17 100644 --- a/deps/v8/AUTHORS +++ b/deps/v8/AUTHORS @@ -9,7 +9,6 @@ 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 573ebb34977..69aff33d185 100644 --- a/deps/v8/ChangeLog +++ b/deps/v8/ChangeLog @@ -1,26 +1,3 @@ -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 f17b848550d..4314727adc4 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 f6c3c8b3019..c7e4552b4d4 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -38,9 +38,23 @@ #ifndef V8_H_ #define V8_H_ -#include "v8stdint.h" +#include <stdio.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 @@ -62,6 +76,8 @@ #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. @@ -111,6 +127,7 @@ class Arguments; class Object; class Heap; class Top; + } @@ -459,10 +476,10 @@ class V8EXPORT HandleScope { level = 0; } }; - + void Leave(); - + internal::Object** prev_next_; internal::Object** prev_limit_; @@ -1038,7 +1055,7 @@ class String : public Primitive { */ V8EXPORT bool IsExternalAscii() const; - class V8EXPORT ExternalStringResourceBase { // NOLINT + class V8EXPORT ExternalStringResourceBase { public: virtual ~ExternalStringResourceBase() {} @@ -2348,15 +2365,12 @@ 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_; }; @@ -2488,18 +2502,13 @@ 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; @@ -3251,8 +3260,8 @@ class V8EXPORT Locker { /** * An interface for exporting data from V8, using "push" model. */ -class V8EXPORT OutputStream { // NOLINT - public: +class V8EXPORT OutputStream { +public: enum OutputEncoding { kAscii = 0 // 7-bit ASCII. }; @@ -3282,8 +3291,6 @@ class V8EXPORT OutputStream { // NOLINT namespace internal { -const int kPointerSize = sizeof(void*); // NOLINT -const int kIntSize = sizeof(int); // NOLINT // Tag information for HeapObject. const int kHeapObjectTag = 1; @@ -3319,19 +3326,19 @@ template <> struct SmiConstants<8> { } }; -const int kSmiShiftSize = SmiConstants<kPointerSize>::kSmiShiftSize; -const int kSmiValueSize = SmiConstants<kPointerSize>::kSmiValueSize; +const int kSmiShiftSize = SmiConstants<sizeof(void*)>::kSmiShiftSize; +const int kSmiValueSize = SmiConstants<sizeof(void*)>::kSmiValueSize; template <size_t ptr_size> struct InternalConstants; // Internal constants for 32-bit systems. template <> struct InternalConstants<4> { - static const int kStringResourceOffset = 3 * kPointerSize; + static const int kStringResourceOffset = 3 * sizeof(void*); }; // Internal constants for 64-bit systems. template <> struct InternalConstants<8> { - static const int kStringResourceOffset = 3 * kPointerSize; + static const int kStringResourceOffset = 3 * sizeof(void*); }; /** @@ -3345,12 +3352,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 = kPointerSize + kIntSize; + static const int kMapInstanceTypeOffset = sizeof(void*) + sizeof(int); static const int kStringResourceOffset = - InternalConstants<kPointerSize>::kStringResourceOffset; + InternalConstants<sizeof(void*)>::kStringResourceOffset; - static const int kProxyProxyOffset = kPointerSize; - static const int kJSObjectHeaderSize = 3 * kPointerSize; + static const int kProxyProxyOffset = sizeof(void*); + static const int kJSObjectHeaderSize = 3 * sizeof(void*); static const int kFullStringRepresentationMask = 0x07; static const int kExternalTwoByteRepresentationTag = 0x02; @@ -3368,7 +3375,7 @@ class Internals { } static inline int SmiValue(internal::Object* value) { - return SmiConstants<kPointerSize>::SmiToInt(value); + return SmiConstants<sizeof(void*)>::SmiToInt(value); } static inline int GetInstanceType(internal::Object* obj) { @@ -3397,9 +3404,10 @@ class Internals { uint8_t* addr = reinterpret_cast<uint8_t*>(ptr) + offset - kHeapObjectTag; return *reinterpret_cast<T*>(addr); } + }; -} // namespace internal +} template <class T> @@ -3559,7 +3567,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 + (internal::kPointerSize * index); + int offset = I::kJSObjectHeaderSize + (sizeof(void*) * index); O* value = I::ReadField<O*>(obj, offset); O** result = HandleScope::CreateHandle(value); return Local<Value>(reinterpret_cast<Value*>(result)); @@ -3595,7 +3603,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 + (internal::kPointerSize * index); + int offset = I::kJSObjectHeaderSize + (sizeof(void*) * 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 deleted file mode 100644 index 50b4f29a64f..00000000000 --- a/deps/v8/include/v8stdint.h +++ /dev/null @@ -1,53 +0,0 @@ -// 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 ad647dfa006..ef5485d8542 100755 --- a/deps/v8/src/SConscript +++ b/deps/v8/src/SConscript @@ -40,7 +40,6 @@ SOURCES = { api.cc assembler.cc ast.cc - bignum.cc bootstrapper.cc builtins.cc cached-powers.cc @@ -96,7 +95,6 @@ SOURCES = { register-allocator.cc rewriter.cc runtime.cc - scanner-base.cc scanner.cc scopeinfo.cc scopes.cc diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index 9da3346d794..617922dd5a7 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -43,6 +43,7 @@ #include "serialize.h" #include "snapshot.h" #include "top.h" +#include "utils.h" #include "v8threads.h" #include "version.h" @@ -393,18 +394,14 @@ 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(); - 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 (young_space_size != 0 || old_gen_size != 0) { + bool result = i::Heap::ConfigureHeap(young_space_size / 2, old_gen_size); if (!result) return false; } if (constraints->stack_limit() != NULL) { @@ -3263,15 +3260,11 @@ bool v8::V8::Dispose() { } -HeapStatistics::HeapStatistics(): total_heap_size_(0), - total_heap_size_executable_(0), - used_heap_size_(0) { } +HeapStatistics::HeapStatistics(): total_heap_size_(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 4cb421c577e..ebbd9b1138a 100644 --- a/deps/v8/src/arm/assembler-arm.cc +++ b/deps/v8/src/arm/assembler-arm.cc @@ -317,8 +317,7 @@ static const Instr kLdrStrOffsetMask = 0x00000fff; static const int kMinimalBufferSize = 4*KB; static byte* spare_buffer_ = NULL; -Assembler::Assembler(void* buffer, int buffer_size) - : positions_recorder_(this) { +Assembler::Assembler(void* buffer, int buffer_size) { if (buffer == NULL) { // Do our own buffer management. if (buffer_size <= kMinimalBufferSize) { @@ -355,6 +354,10 @@ 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_; } @@ -749,15 +752,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. -bool Operand::must_use_constant_pool() const { - if (rmode_ == RelocInfo::EXTERNAL_REFERENCE) { +static bool MustUseConstantPool(RelocInfo::Mode rmode) { + 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; @@ -766,7 +769,7 @@ bool Operand::must_use_constant_pool() const { bool Operand::is_single_instruction() const { if (rm_.is_valid()) return true; - if (must_use_constant_pool()) return false; + if (MustUseConstantPool(rmode_)) return false; uint32_t dummy1, dummy2; return fits_shifter(imm32_, &dummy1, &dummy2, NULL); } @@ -782,7 +785,7 @@ void Assembler::addrmod1(Instr instr, // Immediate. uint32_t rotate_imm; uint32_t immed_8; - if (x.must_use_constant_pool() || + if (MustUseConstantPool(x.rmode_) || !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. @@ -791,7 +794,8 @@ 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 (x.must_use_constant_pool() || !CpuFeatures::IsSupported(ARMv7)) { + if (MustUseConstantPool(x.rmode_) || + !CpuFeatures::IsSupported(ARMv7)) { RecordRelocInfo(x.rmode_, x.imm32_); ldr(rd, MemOperand(pc, 0), cond); } else { @@ -802,7 +806,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 (!x.must_use_constant_pool() && + if (!MustUseConstantPool(x.rmode_) && (instr & kMovMvnMask) != kMovMvnPattern) { mov(ip, x, LeaveCC, cond); } else { @@ -995,7 +999,7 @@ void Assembler::bl(int branch_offset, Condition cond) { void Assembler::blx(int branch_offset) { // v5 and above - positions_recorder()->WriteRecordedPositions(); + WriteRecordedPositions(); ASSERT((branch_offset & 1) == 0); int h = ((branch_offset & 2) >> 1)*B24; int imm24 = branch_offset >> 2; @@ -1005,14 +1009,14 @@ void Assembler::blx(int branch_offset) { // v5 and above void Assembler::blx(Register target, Condition cond) { // v5 and above - positions_recorder()->WriteRecordedPositions(); + 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 - positions_recorder()->WriteRecordedPositions(); + 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()); } @@ -1110,7 +1114,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)) { - positions_recorder()->WriteRecordedPositions(); + 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) @@ -1335,7 +1339,7 @@ void Assembler::msr(SRegisterFieldMask fields, const Operand& src, // Immediate. uint32_t rotate_imm; uint32_t immed_8; - if (src.must_use_constant_pool() || + if (MustUseConstantPool(src.rmode_) || !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_); @@ -1355,7 +1359,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)) { - positions_recorder()->WriteRecordedPositions(); + WriteRecordedPositions(); } addrmod2(cond | B26 | L, dst, src); @@ -2144,7 +2148,6 @@ 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; @@ -2163,7 +2166,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 = mode; + op = 1; // round towards zero } else { ASSERT(IsIntegerVFPType(src_type)); opc2 = 0x0; @@ -2187,64 +2190,57 @@ 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(), mode, cond)); + emit(EncodeVCVT(F64, dst.code(), S32, src.code(), 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(), mode, cond)); + emit(EncodeVCVT(F32, dst.code(), S32, src.code(), 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(), mode, cond)); + emit(EncodeVCVT(F64, dst.code(), U32, src.code(), 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(), mode, cond)); + emit(EncodeVCVT(S32, dst.code(), F64, src.code(), 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(), mode, cond)); + emit(EncodeVCVT(U32, dst.code(), F64, src.code(), 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(), mode, cond)); + emit(EncodeVCVT(F64, dst.code(), F32, src.code(), 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(), mode, cond)); + emit(EncodeVCVT(F32, dst.code(), F64, src.code(), cond)); } @@ -2337,16 +2333,6 @@ 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) | @@ -2357,6 +2343,7 @@ void Assembler::vmrs(Register dst, Condition cond) { } + void Assembler::vsqrt(const DwVfpRegister dst, const DwVfpRegister src, const Condition cond) { @@ -2390,14 +2377,14 @@ void Assembler::BlockConstPoolFor(int instructions) { // Debugging. void Assembler::RecordJSReturn() { - positions_recorder()->WriteRecordedPositions(); + WriteRecordedPositions(); CheckBuffer(); RecordRelocInfo(RelocInfo::JS_RETURN); } void Assembler::RecordDebugBreakSlot() { - positions_recorder()->WriteRecordedPositions(); + WriteRecordedPositions(); CheckBuffer(); RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT); } @@ -2411,6 +2398,47 @@ 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 de3931c2cf9..5b647a7537e 100644 --- a/deps/v8/src/arm/assembler-arm.h +++ b/deps/v8/src/arm/assembler-arm.h @@ -448,7 +448,6 @@ 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()); @@ -1008,37 +1007,26 @@ 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, @@ -1067,8 +1055,6 @@ 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); @@ -1131,9 +1117,13 @@ class Assembler : public Malloced { // Use --debug_code to enable. void RecordComment(const char* msg); - int pc_offset() const { return pc_ - buffer_; } + void RecordPosition(int pos); + void RecordStatementPosition(int pos); + bool WriteRecordedPositions(); - PositionsRecorder* positions_recorder() { return &positions_recorder_; } + int pc_offset() const { return pc_ - buffer_; } + int current_position() const { return current_position_; } + int current_statement_position() const { return current_statement_position_; } bool can_peephole_optimize(int instructions) { if (!FLAG_peephole_optimization) return false; @@ -1269,6 +1259,12 @@ 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(); @@ -1294,21 +1290,8 @@ 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 d7fd9a49022..70ff244649c 100644 --- a/deps/v8/src/arm/codegen-arm.cc +++ b/deps/v8/src/arm/codegen-arm.cc @@ -5496,6 +5496,73 @@ 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) diff --git a/deps/v8/src/arm/codegen-arm.h b/deps/v8/src/arm/codegen-arm.h index 97e50b426be..e6fd6071e1d 100644 --- a/deps/v8/src/arm/codegen-arm.h +++ b/deps/v8/src/arm/codegen-arm.h @@ -518,6 +518,8 @@ 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 36f6283c967..123c5e79720 100644 --- a/deps/v8/src/arm/constants-arm.h +++ b/deps/v8/src/arm/constants-arm.h @@ -206,13 +206,6 @@ 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/full-codegen-arm.cc b/deps/v8/src/arm/full-codegen-arm.cc index bf27d0c7fee..9935e038f5c 100644 --- a/deps/v8/src/arm/full-codegen-arm.cc +++ b/deps/v8/src/arm/full-codegen-arm.cc @@ -1688,14 +1688,12 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr, // Code common for calls using the IC. ZoneList<Expression*>* args = expr->arguments(); int arg_count = args->length(); - { PreserveStatementPositionScope scope(masm()->positions_recorder()); - for (int i = 0; i < arg_count; i++) { - VisitForStackValue(args->at(i)); - } - __ mov(r2, Operand(name)); + for (int i = 0; i < arg_count; i++) { + VisitForStackValue(args->at(i)); } + __ mov(r2, Operand(name)); // Record source position for debugger. - SetSourcePosition(expr->position(), FORCED_POSITION); + SetSourcePosition(expr->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); @@ -1712,15 +1710,13 @@ void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, // Code common for calls using the IC. ZoneList<Expression*>* args = expr->arguments(); int arg_count = args->length(); - { PreserveStatementPositionScope scope(masm()->positions_recorder()); - for (int i = 0; i < arg_count; i++) { - VisitForStackValue(args->at(i)); - } - VisitForAccumulatorValue(key); - __ mov(r2, r0); + 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(), FORCED_POSITION); + SetSourcePosition(expr->position()); // Call the IC initialization code. InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; Handle<Code> ic = CodeGenerator::ComputeKeyedCallInitialize(arg_count, @@ -1736,13 +1732,11 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr) { // Code common for calls using the call stub. ZoneList<Expression*>* args = expr->arguments(); int arg_count = args->length(); - { PreserveStatementPositionScope scope(masm()->positions_recorder()); - for (int i = 0; i < arg_count; i++) { - VisitForStackValue(args->at(i)); - } + for (int i = 0; i < arg_count; i++) { + VisitForStackValue(args->at(i)); } // Record source position for debugger. - SetSourcePosition(expr->position(), FORCED_POSITION); + SetSourcePosition(expr->position()); InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); __ CallStub(&stub); @@ -1762,45 +1756,41 @@ 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)); + } - { 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 function - found below the arguments. + __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize)); + __ push(r1); - // Push copy of the function - found below the arguments. - __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize)); + // 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); + } - // 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); - } - - // 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 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)); - } + // 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(), FORCED_POSITION); + SetSourcePosition(expr->position()); InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); __ CallStub(&stub); @@ -1817,14 +1807,12 @@ void FullCodeGenerator::VisitCall(Call* expr) { // Call to a lookup slot (dynamically introduced variable). Label 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); - } + // 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) @@ -1858,23 +1846,17 @@ void FullCodeGenerator::VisitCall(Call* expr) { Literal* key = prop->key()->AsLiteral(); if (key != NULL && key->handle()->IsSymbol()) { // Call to a named property, use call IC. - { PreserveStatementPositionScope scope(masm()->positions_recorder()); - VisitForStackValue(prop->obj()); - } + 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. - { PreserveStatementPositionScope scope(masm()->positions_recorder()); - VisitForStackValue(prop->obj()); - } + VisitForStackValue(prop->obj()); if (prop->is_synthetic()) { - { PreserveStatementPositionScope scope(masm()->positions_recorder()); - VisitForAccumulatorValue(prop->key()); - } + VisitForAccumulatorValue(prop->key()); // Record source code position for IC call. - SetSourcePosition(prop->position(), FORCED_POSITION); + SetSourcePosition(prop->position()); __ pop(r1); // We do not need to keep the receiver. Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); @@ -1897,10 +1879,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { loop_depth() == 0) { lit->set_try_full_codegen(true); } - - { PreserveStatementPositionScope scope(masm()->positions_recorder()); - VisitForStackValue(fun); - } + VisitForStackValue(fun); // Load global receiver object. __ ldr(r1, CodeGenerator::GlobalObject()); __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset)); diff --git a/deps/v8/src/arm/ic-arm.cc b/deps/v8/src/arm/ic-arm.cc index 4c1f9835f4d..a09afdf754e 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, Assembler::RoundToZero, ne); + __ vcvt_s32_f64(s0, d0, ne); } else { - __ vcvt_u32_f64(s0, d0, Assembler::RoundToZero, ne); + __ vcvt_u32_f64(s0, d0, 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 d2c22af53df..7f6090bc50f 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. - positions_recorder()->WriteRecordedPositions(); + 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 (!src2.is_reg() && - !src2.must_use_constant_pool() && - src2.immediate() == 0) { - mov(dst, Operand(0, RelocInfo::NONE), LeaveCC, cond); - - } 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 { + if (!CpuFeatures::IsSupported(ARMv7) || src2.is_single_instruction()) { and_(dst, src1, src2, LeaveCC, cond); + return; + } + int32_t immediate = src2.immediate(); + if (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; } + and_(dst, src1, src2, LeaveCC, cond); } diff --git a/deps/v8/src/arm/simulator-arm.cc b/deps/v8/src/arm/simulator-arm.cc index 3ec5f449d8a..cb91520f3a5 100644 --- a/deps/v8/src/arm/simulator-arm.cc +++ b/deps/v8/src/arm/simulator-arm.cc @@ -705,7 +705,6 @@ 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; @@ -2502,45 +2501,10 @@ void Simulator::DecodeTypeVFP(Instr* instr) { (instr->VAField() == 0x7) && (instr->Bits(19, 16) == 0x1)) { // vmrs - uint32_t rt = instr->RtField(); - if (rt == 0xF) { + if (instr->RtField() == 0xF) Copy_FPSCR_to_APSR(); - } 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. } else { UNIMPLEMENTED(); // Not used by V8. } @@ -2641,71 +2605,29 @@ void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr) { if (to_integer) { bool unsigned_integer = (instr->Bit(16) == 0); - FPSCRRoundingModes mode; if (instr->Bit(7) != 1) { - // 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; + // Only rounding towards zero supported. + UNIMPLEMENTED(); // Not used by V8. } 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); - - inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != 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); - inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != 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); - } - 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); + 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); + set_s_register_from_sinteger(dst, sint); + } else { + float val = get_float_from_s_register(src); - set_s_register_from_sinteger(dst, sint); - } - break; + int sint = unsigned_integer ? static_cast<uint32_t>(val) : + static_cast<int32_t>(val); - default: - UNREACHABLE(); + set_s_register_from_sinteger(dst, sint); } - } 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 c37b3f7156d..3e023489eef 100644 --- a/deps/v8/src/arm/simulator-arm.h +++ b/deps/v8/src/arm/simulator-arm.h @@ -306,9 +306,6 @@ 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/assembler.cc b/deps/v8/src/assembler.cc index 7493673e819..ce90dceacbc 100644 --- a/deps/v8/src/assembler.cc +++ b/deps/v8/src/assembler.cc @@ -804,53 +804,4 @@ 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 09159fed08e..66811777fad 100644 --- a/deps/v8/src/assembler.h +++ b/deps/v8/src/assembler.h @@ -585,67 +585,6 @@ 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.cc b/deps/v8/src/bignum.cc deleted file mode 100644 index dd1537a25a0..00000000000 --- a/deps/v8/src/bignum.cc +++ /dev/null @@ -1,767 +0,0 @@ -// 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 deleted file mode 100644 index 1d2bff61a5e..00000000000 --- a/deps/v8/src/bignum.h +++ /dev/null @@ -1,140 +0,0 @@ -// 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/checks.cc b/deps/v8/src/checks.cc index 1ab8802ec3f..b5df316d0f7 100644 --- a/deps/v8/src/checks.cc +++ b/deps/v8/src/checks.cc @@ -98,12 +98,3 @@ 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 e0704774ba4..5ea59920ac1 100644 --- a/deps/v8/src/checks.h +++ b/deps/v8/src/checks.h @@ -30,7 +30,7 @@ #include <string.h> -#include "../include/v8stdint.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,12 +279,6 @@ 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 @@ -293,7 +287,7 @@ bool EnableSlowAsserts(); #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 (EnableSlowAsserts()) CHECK(condition) +#define SLOW_ASSERT(condition) if (FLAG_enable_slow_asserts) CHECK(condition) #else #define ASSERT_RESULT(expr) (expr) #define ASSERT(condition) ((void) 0) @@ -309,16 +303,11 @@ bool EnableSlowAsserts(); // 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) & HeapObjectTagMask()) == 0) + ASSERT((reinterpret_cast<intptr_t>(address) & kHeapObjectTagMask) == 0) -#define ASSERT_SIZE_TAG_ALIGNED(size) ASSERT((size & HeapObjectTagMask()) == 0) +#define ASSERT_SIZE_TAG_ALIGNED(size) ASSERT((size & kHeapObjectTagMask) == 0) #define ASSERT_NOT_NULL(p) ASSERT_NE(NULL, p) diff --git a/deps/v8/src/code-stubs.h b/deps/v8/src/code-stubs.h index ec643534159..c0a8d3063c8 100644 --- a/deps/v8/src/code-stubs.h +++ b/deps/v8/src/code-stubs.h @@ -542,7 +542,7 @@ class ApiGetterEntryStub : public CodeStub { ApiFunction* fun() { return fun_; } Major MajorKey() { return NoCache; } int MinorKey() { return 0; } - const char* GetName() { return "ApiGetterEntryStub"; } + const char* GetName() { return "ApiEntryStub"; } // The accessor info associated with the function. Handle<AccessorInfo> info_; // The function to be called. @@ -550,32 +550,6 @@ class ApiGetterEntryStub : public CodeStub { }; -class ApiCallEntryStub : public CodeStub { - public: - ApiCallEntryStub(Handle<CallHandlerInfo> 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 = 0; - static const int kArgc = 5; - private: - Handle<CallHandlerInfo> info() { return info_; } - ApiFunction* fun() { return fun_; } - Major MajorKey() { return NoCache; } - int MinorKey() { return 0; } - const char* GetName() { return "ApiCallEntryStub"; } - // The call handler info associated with the function. - Handle<CallHandlerInfo> 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 e954dd66c1a..bda697abafd 100644 --- a/deps/v8/src/codegen.cc +++ b/deps/v8/src/codegen.cc @@ -70,10 +70,9 @@ void CodeGenerator::ProcessDeferred() { DeferredCode* code = deferred_.RemoveLast(); ASSERT(masm_ == code->masm()); // Record position of deferred code stub. - masm_->positions_recorder()->RecordStatementPosition( - code->statement_position()); + masm_->RecordStatementPosition(code->statement_position()); if (code->position() != RelocInfo::kNoPosition) { - masm_->positions_recorder()->RecordPosition(code->position()); + masm_->RecordPosition(code->position()); } // Generate the code. Comment cmnt(masm_, code->comment()); @@ -403,10 +402,10 @@ bool CodeGenerator::RecordPositions(MacroAssembler* masm, int pos, bool right_here) { if (pos != RelocInfo::kNoPosition) { - masm->positions_recorder()->RecordStatementPosition(pos); - masm->positions_recorder()->RecordPosition(pos); + masm->RecordStatementPosition(pos); + masm->RecordPosition(pos); if (right_here) { - return masm->positions_recorder()->WriteRecordedPositions(); + return masm->WriteRecordedPositions(); } } return false; @@ -436,7 +435,7 @@ void CodeGenerator::CodeForDoWhileConditionPosition(DoWhileStatement* stmt) { void CodeGenerator::CodeForSourcePosition(int pos) { if (FLAG_debug_info && pos != RelocInfo::kNoPosition) { - masm()->positions_recorder()->RecordPosition(pos); + masm()->RecordPosition(pos); } } @@ -482,8 +481,8 @@ int CEntryStub::MinorKey() { } -// Implementation of CodeStub::GetCustomCache. -static bool GetCustomCacheHelper(Object* cache, Code** code_out) { +bool ApiGetterEntryStub::GetCustomCache(Code** code_out) { + Object* cache = info()->load_stub_cache(); if (cache->IsUndefined()) { return false; } else { @@ -493,24 +492,9 @@ static bool GetCustomCacheHelper(Object* cache, Code** code_out) { } -bool ApiGetterEntryStub::GetCustomCache(Code** code_out) { - return GetCustomCacheHelper(info()->load_stub_cache(), code_out); -} - - void ApiGetterEntryStub::SetCustomCache(Code* value) { info()->set_load_stub_cache(value); } -bool ApiCallEntryStub::GetCustomCache(Code** code_out) { - return GetCustomCacheHelper(info()->call_stub_cache(), code_out); -} - - -void ApiCallEntryStub::SetCustomCache(Code* value) { - info()->set_call_stub_cache(value); -} - - } } // namespace v8::internal diff --git a/deps/v8/src/compiler.cc b/deps/v8/src/compiler.cc index 29bbbc7034e..6f02960dda7 100755 --- a/deps/v8/src/compiler.cc +++ b/deps/v8/src/compiler.cc @@ -279,6 +279,7 @@ 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 4cc67448508..790e807aef4 100644 --- a/deps/v8/src/conversions.cc +++ b/deps/v8/src/conversions.cc @@ -816,7 +816,7 @@ const char* IntToCString(int n, Vector<char> buffer) { char* DoubleToFixedCString(double value, int f) { - const int kMaxDigitsBeforePoint = 21; + const int kMaxDigitsBeforePoint = 20; const double kFirstNonFixed = 1e21; const int kMaxDigitsAfterPoint = 20; ASSERT(f >= 0); @@ -840,9 +840,9 @@ char* DoubleToFixedCString(double value, int f) { // Find a sufficiently precise decimal representation of n. int decimal_point; int sign; - // Add space for the '\0' byte. + // Add space for the '.' and the '\0' byte. const int kDecimalRepCapacity = - kMaxDigitsBeforePoint + kMaxDigitsAfterPoint + 1; + kMaxDigitsBeforePoint + kMaxDigitsAfterPoint + 2; char decimal_rep[kDecimalRepCapacity]; int decimal_rep_length; bool status = DoubleToAscii(value, DTOA_FIXED, f, diff --git a/deps/v8/src/debug-debugger.js b/deps/v8/src/debug-debugger.js index d091991a119..0eab8d1b831 100644 --- a/deps/v8/src/debug-debugger.js +++ b/deps/v8/src/debug-debugger.js @@ -897,6 +897,10 @@ 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.'); @@ -1747,6 +1751,11 @@ 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) { @@ -2196,6 +2205,29 @@ 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 f3bf954da9b..24f04098610 100644 --- a/deps/v8/src/debug.cc +++ b/deps/v8/src/debug.cc @@ -1839,7 +1839,6 @@ 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 65eded99893..e805173e07e 100644 --- a/deps/v8/src/double.h +++ b/deps/v8/src/double.h @@ -54,20 +54,18 @@ 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()); } - // The value encoded by this Double must be strictly greater than 0. + // this->Significand() must not be 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; @@ -84,20 +82,6 @@ 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; @@ -136,30 +120,24 @@ 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/flag-definitions.h b/deps/v8/src/flag-definitions.h index 46feea77ac2..54501ec95d9 100644 --- a/deps/v8/src/flag-definitions.h +++ b/deps/v8/src/flag-definitions.h @@ -186,7 +186,6 @@ 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 c770e189b35..97987c27a80 100644 --- a/deps/v8/src/full-codegen.cc +++ b/deps/v8/src/full-codegen.cc @@ -563,10 +563,9 @@ void FullCodeGenerator::SetStatementPosition(int pos) { } -void FullCodeGenerator::SetSourcePosition( - int pos, PositionRecordingType recording_type) { +void FullCodeGenerator::SetSourcePosition(int pos) { if (FLAG_debug_info && pos != RelocInfo::kNoPosition) { - masm_->positions_recorder()->RecordPosition(pos, recording_type); + masm_->RecordPosition(pos); } } @@ -1226,6 +1225,13 @@ 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 a3270aa774e..201507b2af3 100644 --- a/deps/v8/src/full-codegen.h +++ b/deps/v8/src/full-codegen.h @@ -423,9 +423,7 @@ class FullCodeGenerator: public AstVisitor { void SetStatementPosition(Statement* stmt); void SetExpressionPosition(Expression* expr, int pos); void SetStatementPosition(int pos); - void SetSourcePosition( - int pos, - PositionRecordingType recording_type = NORMAL_POSITION); + void SetSourcePosition(int pos); // Non-local control flow support. void EnterFinallyBlock(); diff --git a/deps/v8/src/global-handles.cc b/deps/v8/src/global-handles.cc index 5339840988d..9ede9085283 100644 --- a/deps/v8/src/global-handles.cc +++ b/deps/v8/src/global-handles.cc @@ -372,14 +372,13 @@ void GlobalHandles::IdentifyWeakHandles(WeakSlotCallback f) { int post_gc_processing_count = 0; -bool GlobalHandles::PostGarbageCollectionProcessing() { +void 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()) { @@ -400,7 +399,6 @@ bool GlobalHandles::PostGarbageCollectionProcessing() { } node->set_next_free(first_deallocated()); set_first_deallocated(node); - next_gc_likely_to_collect_more = true; } else { p = (*p)->next_addr(); } @@ -409,8 +407,6 @@ bool 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 37b2b44522e..659f86eca70 100644 --- a/deps/v8/src/global-handles.h +++ b/deps/v8/src/global-handles.h @@ -96,8 +96,7 @@ class GlobalHandles : public AllStatic { static bool IsWeak(Object** location); // Process pending weak handles. - // Returns true if next major GC is likely to collect more garbage. - static bool PostGarbageCollectionProcessing(); + static void 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 a74b6c79303..c218f80dc11 100644 --- a/deps/v8/src/globals.h +++ b/deps/v8/src/globals.h @@ -193,9 +193,10 @@ const uint32_t kMaxUInt32 = 0xFFFFFFFFu; 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 -// kIntSize and kPointerSize are defined in include/v8.h. #if V8_HOST_ARCH_64_BIT const int kPointerSizeLog2 = 3; diff --git a/deps/v8/src/heap-inl.h b/deps/v8/src/heap-inl.h index ba50c0f7358..15feb9d5fb9 100644 --- a/deps/v8/src/heap-inl.h +++ b/deps/v8/src/heap-inl.h @@ -330,11 +330,6 @@ 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. @@ -418,7 +413,7 @@ void Heap::SetLastScriptId(Object* last_script_id) { } \ if (!__maybe_object__->IsRetryAfterGC()) RETURN_EMPTY; \ Counters::gc_last_resort_from_handles.Increment(); \ - Heap::CollectAllAvailableGarbage(); \ + Heap::CollectAllGarbage(false); \ { \ AlwaysAllocateScope __scope__; \ __maybe_object__ = FUNCTION_CALL; \ diff --git a/deps/v8/src/heap.cc b/deps/v8/src/heap.cc index 134f40e5070..b037efd8045 100644 --- a/deps/v8/src/heap.cc +++ b/deps/v8/src/heap.cc @@ -83,19 +83,16 @@ int Heap::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; 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; 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 // The snapshot semispace size will be the default semispace size if @@ -175,12 +172,6 @@ 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; @@ -438,31 +429,7 @@ void Heap::CollectAllGarbage(bool force_compaction) { } -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) { +void Heap::CollectGarbage(AllocationSpace space) { // The VM is in the GC state until exiting this function. VMState state(GC); @@ -475,14 +442,13 @@ bool Heap::CollectGarbage(AllocationSpace space, GarbageCollector collector) { 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); @@ -490,8 +456,7 @@ bool Heap::CollectGarbage(AllocationSpace space, GarbageCollector collector) { ? &Counters::gc_scavenger : &Counters::gc_compactor; rate->Start(); - next_gc_likely_to_collect_more = - PerformGarbageCollection(collector, &tracer); + PerformGarbageCollection(collector, &tracer); rate->Stop(); GarbageCollectionEpilogue(); @@ -502,8 +467,6 @@ bool Heap::CollectGarbage(AllocationSpace space, GarbageCollector collector) { if (FLAG_log_gc) HeapProfiler::WriteSample(); if (CpuProfiler::is_profiling()) CpuProfiler::ProcessMovedFunctions(); #endif - - return next_gc_likely_to_collect_more; } @@ -690,10 +653,8 @@ void Heap::UpdateSurvivalRateTrend(int start_new_space_size) { survival_rate_ = survival_rate; } -bool Heap::PerformGarbageCollection(GarbageCollector collector, +void Heap::PerformGarbageCollection(GarbageCollector collector, GCTracer* tracer) { - bool next_gc_likely_to_collect_more = false; - if (collector != SCAVENGER) { PROFILE(CodeMovingGCEvent()); } @@ -759,8 +720,7 @@ bool Heap::PerformGarbageCollection(GarbageCollector collector, if (collector == MARK_COMPACTOR) { DisableAssertNoAllocation allow_allocation; GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL); - next_gc_likely_to_collect_more = - GlobalHandles::PostGarbageCollectionProcessing(); + GlobalHandles::PostGarbageCollectionProcessing(); } // Update relocatables. @@ -787,8 +747,6 @@ bool Heap::PerformGarbageCollection(GarbageCollector collector, global_gc_epilogue_callback_(); } VerifySymbolTable(); - - return next_gc_likely_to_collect_more; } @@ -4322,9 +4280,7 @@ 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, - int max_executable_size) { +bool Heap::ConfigureHeap(int max_semispace_size, int max_old_gen_size) { if (HasBeenSetup()) return false; if (max_semispace_size > 0) max_semispace_size_ = max_semispace_size; @@ -4345,15 +4301,6 @@ bool Heap::ConfigureHeap(int max_semispace_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. @@ -4371,9 +4318,8 @@ bool Heap::ConfigureHeap(int max_semispace_size, bool Heap::ConfigureHeapDefault() { - return ConfigureHeap(FLAG_max_new_space_size / 2 * KB, - FLAG_max_old_space_size * MB, - FLAG_max_executable_size * MB); + return ConfigureHeap( + FLAG_max_new_space_size * (KB / 2), FLAG_max_old_space_size * MB); } @@ -4456,7 +4402,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(), MaxExecutableSize())) return false; + if (!MemoryAllocator::Setup(MaxReserved())) return false; void* chunk = MemoryAllocator::ReserveInitialChunk(4 * reserved_semispace_size_); if (chunk == NULL) return false; diff --git a/deps/v8/src/heap.h b/deps/v8/src/heap.h index c37ced39399..8ff2f5f3413 100644 --- a/deps/v8/src/heap.h +++ b/deps/v8/src/heap.h @@ -222,9 +222,7 @@ 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, - int max_executable_size); + static bool ConfigureHeap(int max_semispace_size, int max_old_gen_size); static bool ConfigureHeapDefault(); // Initializes the global object heap. If create_heap_objects is true, @@ -255,7 +253,6 @@ 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. @@ -264,9 +261,6 @@ 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. @@ -711,22 +705,13 @@ class Heap : public AllStatic { static void GarbageCollectionEpilogue(); // Performs garbage collection operation. - // 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); + // Returns whether required_space bytes are available after the collection. + static void 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_; } @@ -1102,7 +1087,6 @@ 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 @@ -1262,9 +1246,7 @@ class Heap : public AllStatic { static GarbageCollector SelectGarbageCollector(AllocationSpace space); // Performs garbage collection - // Returns whether there is a chance another major GC could - // collect more garbage. - static bool PerformGarbageCollection(GarbageCollector collector, + static void PerformGarbageCollection(GarbageCollector collector, GCTracer* tracer); // Allocate an uninitialized object in map space. The behavior is identical diff --git a/deps/v8/src/ia32/assembler-ia32.cc b/deps/v8/src/ia32/assembler-ia32.cc index 125f503bec3..019f478adc5 100644 --- a/deps/v8/src/ia32/assembler-ia32.cc +++ b/deps/v8/src/ia32/assembler-ia32.cc @@ -298,8 +298,7 @@ static void InitCoverageLog(); // Spare buffer. byte* Assembler::spare_buffer_ = NULL; -Assembler::Assembler(void* buffer, int buffer_size) - : positions_recorder_(this) { +Assembler::Assembler(void* buffer, int buffer_size) { if (buffer == NULL) { // Do our own buffer management. if (buffer_size <= kMinimalBufferSize) { @@ -340,6 +339,10 @@ 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 @@ -1578,7 +1581,7 @@ void Assembler::call(const Operand& adr) { void Assembler::call(Handle<Code> code, RelocInfo::Mode rmode) { - positions_recorder()->WriteRecordedPositions(); + WriteRecordedPositions(); EnsureSpace ensure_space(this); last_pc_ = pc_; ASSERT(RelocInfo::IsCodeTarget(rmode)); @@ -2461,14 +2464,14 @@ void Assembler::Print() { void Assembler::RecordJSReturn() { - positions_recorder()->WriteRecordedPositions(); + WriteRecordedPositions(); EnsureSpace ensure_space(this); RecordRelocInfo(RelocInfo::JS_RETURN); } void Assembler::RecordDebugBreakSlot() { - positions_recorder()->WriteRecordedPositions(); + WriteRecordedPositions(); EnsureSpace ensure_space(this); RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT); } @@ -2482,6 +2485,47 @@ 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 79637a19010..5286788fa72 100644 --- a/deps/v8/src/ia32/assembler-ia32.h +++ b/deps/v8/src/ia32/assembler-ia32.h @@ -521,6 +521,7 @@ 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); @@ -846,11 +847,17 @@ 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 @@ -862,8 +869,6 @@ 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; @@ -942,9 +947,11 @@ class Assembler : public Malloced { // push-pop elimination byte* last_pc_; - PositionsRecorder positions_recorder_; - - friend class PositionsRecorder; + // source position information + int current_statement_position_; + int current_position_; + int written_statement_position_; + int written_position_; }; diff --git a/deps/v8/src/ia32/code-stubs-ia32.cc b/deps/v8/src/ia32/code-stubs-ia32.cc index a7d658bdce5..b2b73926b9a 100644 --- a/deps/v8/src/ia32/code-stubs-ia32.cc +++ b/deps/v8/src/ia32/code-stubs-ia32.cc @@ -3067,26 +3067,6 @@ void ApiGetterEntryStub::Generate(MacroAssembler* masm) { } -void ApiCallEntryStub::Generate(MacroAssembler* masm) { - __ PrepareCallApiFunction(kStackSpace, kArgc); - STATIC_ASSERT(kArgc == 5); - - // Allocate the v8::Arguments structure in the arguments' space since - // it's not controlled by GC. - __ mov(ApiParameterOperand(1), eax); // v8::Arguments::implicit_args_. - __ mov(ApiParameterOperand(2), ebx); // v8::Arguments::values_. - __ mov(ApiParameterOperand(3), edx); // v8::Arguments::length_. - // v8::Arguments::is_construct_call_. - __ mov(ApiParameterOperand(4), Immediate(0)); - - // v8::InvocationCallback's argument. - __ lea(eax, ApiParameterOperand(1)); - __ mov(ApiParameterOperand(0), eax); - - __ 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 6f4ef87e85e..6d23dd7df99 100644 --- a/deps/v8/src/ia32/codegen-ia32.cc +++ b/deps/v8/src/ia32/codegen-ia32.cc @@ -3734,7 +3734,7 @@ void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { CodeForStatementPosition(node); Load(node->expression()); Result return_value = frame_->Pop(); - masm()->positions_recorder()->WriteRecordedPositions(); + masm()->WriteRecordedPositions(); if (function_return_is_shadowed_) { function_return_.Jump(&return_value); } else { @@ -7292,6 +7292,88 @@ 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) @@ -8578,11 +8660,9 @@ void CodeGenerator::Int32BinaryOperation(BinaryOperation* node) { } right.Unuse(); frame_->Push(&left); - if (!node->to_int32() || op == Token::MUL) { - // If ToInt32 is called on the result of ADD, SUB, we don't + if (!node->to_int32()) { + // If ToInt32 is called on the result of ADD, SUB, or MUL, 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 5a12e10ea5a..4594b19ddd2 100644 --- a/deps/v8/src/ia32/codegen-ia32.h +++ b/deps/v8/src/ia32/codegen-ia32.h @@ -697,6 +697,11 @@ 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 1ea719d7133..ee4e6458ae3 100644 --- a/deps/v8/src/ia32/full-codegen-ia32.cc +++ b/deps/v8/src/ia32/full-codegen-ia32.cc @@ -1996,14 +1996,12 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr, // Code common for calls using the IC. ZoneList<Expression*>* args = expr->arguments(); int arg_count = args->length(); - { PreserveStatementPositionScope scope(masm()->positions_recorder()); - for (int i = 0; i < arg_count; i++) { - VisitForStackValue(args->at(i)); - } - __ Set(ecx, Immediate(name)); + for (int i = 0; i < arg_count; i++) { + VisitForStackValue(args->at(i)); } + __ Set(ecx, Immediate(name)); // Record source position of the IC call. - SetSourcePosition(expr->position(), FORCED_POSITION); + SetSourcePosition(expr->position()); InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop); EmitCallIC(ic, mode); @@ -2019,15 +2017,13 @@ void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, // Code common for calls using the IC. ZoneList<Expression*>* args = expr->arguments(); int arg_count = args->length(); - { PreserveStatementPositionScope scope(masm()->positions_recorder()); - for (int i = 0; i < arg_count; i++) { - VisitForStackValue(args->at(i)); - } - VisitForAccumulatorValue(key); - __ mov(ecx, eax); + 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(), FORCED_POSITION); + SetSourcePosition(expr->position()); InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; Handle<Code> ic = CodeGenerator::ComputeKeyedCallInitialize( arg_count, in_loop); @@ -2042,13 +2038,11 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr) { // Code common for calls using the call stub. ZoneList<Expression*>* args = expr->arguments(); int arg_count = args->length(); - { PreserveStatementPositionScope scope(masm()->positions_recorder()); - for (int i = 0; i < arg_count; i++) { - VisitForStackValue(args->at(i)); - } + for (int i = 0; i < arg_count; i++) { + VisitForStackValue(args->at(i)); } // Record source position for debugger. - SetSourcePosition(expr->position(), FORCED_POSITION); + SetSourcePosition(expr->position()); InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); __ CallStub(&stub); @@ -2068,39 +2062,37 @@ 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(); - { PreserveStatementPositionScope pos_scope(masm()->positions_recorder()); - VisitForStackValue(fun); - // Reserved receiver slot. - __ push(Immediate(Factory::undefined_value())); + for (int i = 0; i < arg_count; i++) { + VisitForStackValue(args->at(i)); + } - // Push the arguments. - for (int i = 0; i < arg_count; i++) { - VisitForStackValue(args->at(i)); - } + // Push copy of the function - found below the arguments. + __ push(Operand(esp, (arg_count + 1) * kPointerSize)); - // Push copy of the function - found below the arguments. - __ push(Operand(esp, (arg_count + 1) * kPointerSize)); + // 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 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 the receiver of the enclosing function and do runtime call. + __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize)); + __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3); - // 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); - // 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(), FORCED_POSITION); + SetSourcePosition(expr->position()); InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); __ CallStub(&stub); @@ -2116,14 +2108,12 @@ void FullCodeGenerator::VisitCall(Call* expr) { // Call to a lookup slot (dynamically introduced variable). Label 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); - } + // 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) @@ -2162,15 +2152,11 @@ 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. - { PreserveStatementPositionScope scope(masm()->positions_recorder()); - VisitForStackValue(prop->obj()); - } + VisitForStackValue(prop->obj()); if (prop->is_synthetic()) { - { PreserveStatementPositionScope scope(masm()->positions_recorder()); - VisitForAccumulatorValue(prop->key()); - } + VisitForAccumulatorValue(prop->key()); // Record source code position for IC call. - SetSourcePosition(prop->position(), FORCED_POSITION); + SetSourcePosition(prop->position()); __ pop(edx); // We do not need to keep the receiver. Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); @@ -2195,9 +2181,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { loop_depth() == 0) { lit->set_try_full_codegen(true); } - { PreserveStatementPositionScope scope(masm()->positions_recorder()); - VisitForStackValue(fun); - } + VisitForStackValue(fun); // Load global receiver object. __ mov(ebx, CodeGenerator::GlobalObject()); __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); diff --git a/deps/v8/src/ia32/ic-ia32.cc b/deps/v8/src/ia32/ic-ia32.cc index a0bc086d871..b5f4deefeb9 100644 --- a/deps/v8/src/ia32/ic-ia32.cc +++ b/deps/v8/src/ia32/ic-ia32.cc @@ -33,6 +33,7 @@ #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.h b/deps/v8/src/ia32/macro-assembler-ia32.h index d65eebbc20c..7b9b843939e 100644 --- a/deps/v8/src/ia32/macro-assembler-ia32.h +++ b/deps/v8/src/ia32/macro-assembler-ia32.h @@ -488,7 +488,7 @@ class MacroAssembler: public Assembler { // stored in ApiParameterOperand(0), ApiParameterOperand(1) etc. void PrepareCallApiFunction(int stack_space, int argc); - // Calls an API function. Allocates HandleScope, extracts + // Tail call an API function (jump). Allocates HandleScope, extracts // returned value from handle and propagates exceptions. // Clobbers ebx, esi, edi and caller-save registers. void CallApiFunctionAndReturn(ApiFunction* function, int argc); diff --git a/deps/v8/src/ia32/stub-cache-ia32.cc b/deps/v8/src/ia32/stub-cache-ia32.cc index f59928fe2bb..e3870883599 100644 --- a/deps/v8/src/ia32/stub-cache-ia32.cc +++ b/deps/v8/src/ia32/stub-cache-ia32.cc @@ -413,10 +413,6 @@ 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. // @@ -427,9 +423,10 @@ static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) { // -- esp[4] : last argument in the internal frame of the caller // ----------------------------------- __ pop(scratch); - for (int i = 0; i < kFastApiCallArguments; i++) { - __ push(Immediate(Smi::FromInt(0))); - } + __ push(Immediate(Smi::FromInt(0))); + __ push(Immediate(Smi::FromInt(0))); + __ push(Immediate(Smi::FromInt(0))); + __ push(Immediate(Smi::FromInt(0))); __ push(scratch); } @@ -437,81 +434,75 @@ 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[kFastApiCallArguments * 4] : first fast api call extra argument. - // -- esp[kFastApiCallArguments * 4 + 4] : last argument in the internal - // frame. + // -- esp[16] : first fast api call extra argument + // -- esp[20] : last argument in the internal frame // ----------------------------------- __ pop(scratch); - __ add(Operand(esp), Immediate(kPointerSize * kFastApiCallArguments)); + __ add(Operand(esp), Immediate(kPointerSize * 4)); __ push(scratch); } // Generates call to FastHandleApiCall builtin. -static bool GenerateFastApiCall(MacroAssembler* masm, +static void GenerateFastApiCall(MacroAssembler* masm, const CallOptimization& optimization, - int argc, - Failure** failure) { + int argc) { // ----------- 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 function + // -- esp[8] : api call data + // -- esp[12] : api callback + // -- esp[16] : api function // (first fast api call extra argument) - // -- esp[12] : api call data - // -- esp[16] : last argument + // -- esp[20] : last argument // -- ... - // -- esp[(argc + 3) * 4] : first argument - // -- esp[(argc + 4) * 4] : receiver + // -- esp[(argc + 5) * 4] : first argument + // -- esp[(argc + 6) * 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, 2 * kPointerSize), edi); + __ 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))); + } Object* call_data = optimization.api_call_info()->data(); - Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info()); if (Heap::InNewSpace(call_data)) { - __ mov(ecx, api_call_info_handle); + if (!info_loaded) { + __ mov(ecx, Handle<CallHandlerInfo>(optimization.api_call_info())); + } __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset)); - __ mov(Operand(esp, 3 * kPointerSize), ebx); + __ mov(Operand(esp, 2 * kPointerSize), ebx); } else { - __ mov(Operand(esp, 3 * kPointerSize), + __ mov(Operand(esp, 2 * kPointerSize), Immediate(Handle<Object>(call_data))); } - // Prepare arguments for ApiCallEntryStub. - __ lea(eax, Operand(esp, 3 * kPointerSize)); - __ lea(ebx, Operand(esp, (argc + 3) * kPointerSize)); - __ Set(edx, Immediate(argc)); - - Object* callback = optimization.api_call_info()->callback(); - Address api_function_address = v8::ToCData<Address>(callback); - ApiFunction fun(api_function_address); - - ApiCallEntryStub stub(api_call_info_handle, &fun); - - __ EnterInternalFrame(); + // Set the number of arguments. + __ mov(eax, Immediate(argc + 4)); - // 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); - if (result->IsFailure()) { - *failure = Failure::cast(result); - return false; - } - - __ LeaveInternalFrame(); - __ ret((argc + 4) * kPointerSize); - return true; + // 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); } @@ -524,7 +515,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { arguments_(arguments), name_(name) {} - bool Compile(MacroAssembler* masm, + void Compile(MacroAssembler* masm, JSObject* object, JSObject* holder, String* name, @@ -533,8 +524,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { Register scratch1, Register scratch2, Register scratch3, - Label* miss, - Failure** failure) { + Label* miss) { ASSERT(holder->HasNamedInterceptor()); ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); @@ -545,18 +535,17 @@ class CallInterceptorCompiler BASE_EMBEDDED { CallOptimization optimization(lookup); if (optimization.is_constant_call()) { - return CompileCacheable(masm, - object, - receiver, - scratch1, - scratch2, - scratch3, - holder, - lookup, - name, - optimization, - miss, - failure); + CompileCacheable(masm, + object, + receiver, + scratch1, + scratch2, + scratch3, + holder, + lookup, + name, + optimization, + miss); } else { CompileRegular(masm, object, @@ -567,12 +556,11 @@ class CallInterceptorCompiler BASE_EMBEDDED { name, holder, miss); - return true; } } private: - bool CompileCacheable(MacroAssembler* masm, + void CompileCacheable(MacroAssembler* masm, JSObject* object, Register receiver, Register scratch1, @@ -582,8 +570,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { LookupResult* lookup, String* name, const CallOptimization& optimization, - Label* miss_label, - Failure** failure) { + Label* miss_label) { ASSERT(optimization.is_constant_call()); ASSERT(!lookup->holder()->IsGlobalObject()); @@ -645,11 +632,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { // Invoke function. if (can_do_fast_api_call) { - bool success = GenerateFastApiCall(masm, optimization, - arguments_.immediate(), failure); - if (!success) { - return false; - } + GenerateFastApiCall(masm, optimization, arguments_.immediate()); } else { __ InvokeFunction(optimization.constant_function(), arguments_, JUMP_FUNCTION); @@ -667,8 +650,6 @@ class CallInterceptorCompiler BASE_EMBEDDED { if (can_do_fast_api_call) { FreeSpaceForFastApiCall(masm, scratch1); } - - return true; } void CompileRegular(MacroAssembler* masm, @@ -924,7 +905,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(maybe_lookup_result)); + set_failure(Failure::cast(lookup_result)); return reg; } name = String::cast(lookup_result); @@ -1065,7 +1046,8 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object, __ EnterInternalFrame(); // Push the stack address where the list of arguments ends. - __ lea(scratch2, Operand(esp, -2 * kPointerSize)); + __ mov(scratch2, esp); + __ sub(Operand(scratch2), Immediate(2 * kPointerSize)); __ push(scratch2); __ push(receiver); // receiver __ push(reg); // holder @@ -1079,11 +1061,12 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object, __ 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. - STATIC_ASSERT(ApiGetterEntryStub::kStackSpace == 5); - __ lea(eax, Operand(esp, 4 * kPointerSize)); + __ mov(eax, esp); + __ add(Operand(eax), Immediate(4 * kPointerSize)); __ mov(ebx, esp); // 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); @@ -1094,7 +1077,7 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object, Object* result = NULL; // Initialization to please compiler. { MaybeObject* try_call_result = masm()->TryCallStub(&stub); if (!try_call_result->ToObject(&result)) { - *failure = Failure::cast(try_call_result); + *failure = Failure::cast(result); return false; } } @@ -2225,11 +2208,7 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object, } if (depth != kInvalidProtoDepth) { - Failure* failure; - bool success = GenerateFastApiCall(masm(), optimization, argc, &failure); - if (!success) { - return failure; - } + GenerateFastApiCall(masm(), optimization, argc); } else { __ InvokeFunction(function, arguments(), JUMP_FUNCTION); } @@ -2274,21 +2253,16 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object, __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); CallInterceptorCompiler compiler(this, arguments(), ecx); - Failure* failure; - bool success = compiler.Compile(masm(), - object, - holder, - name, - &lookup, - edx, - ebx, - edi, - eax, - &miss, - &failure); - if (!success) { - return false; - } + compiler.Compile(masm(), + object, + holder, + name, + &lookup, + edx, + ebx, + edi, + eax, + &miss); // Restore receiver. __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); diff --git a/deps/v8/src/jump-target-heavy.cc b/deps/v8/src/jump-target-heavy.cc index c3c22f1ac63..e0585e79429 100644 --- a/deps/v8/src/jump-target-heavy.cc +++ b/deps/v8/src/jump-target-heavy.cc @@ -414,9 +414,8 @@ void BreakTarget::Branch(Condition cc, Hint hint) { DeferredCode::DeferredCode() : masm_(CodeGeneratorScope::Current()->masm()), - statement_position_(masm_->positions_recorder()-> - current_statement_position()), - position_(masm_->positions_recorder()->current_position()), + statement_position_(masm_->current_statement_position()), + position_(masm_->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 36dc176bce7..19f7bfec0a6 100644 --- a/deps/v8/src/jump-target-light.cc +++ b/deps/v8/src/jump-target-light.cc @@ -36,9 +36,8 @@ namespace internal { DeferredCode::DeferredCode() : masm_(CodeGeneratorScope::Current()->masm()), - statement_position_(masm_->positions_recorder()-> - current_statement_position()), - position_(masm_->positions_recorder()->current_position()), + statement_position_(masm_->current_statement_position()), + position_(masm_->current_position()), frame_state_(*CodeGeneratorScope::Current()->frame()) { ASSERT(statement_position_ != RelocInfo::kNoPosition); ASSERT(position_ != RelocInfo::kNoPosition); diff --git a/deps/v8/src/objects-debug.cc b/deps/v8/src/objects-debug.cc index 2b79016a012..c0e5610abaf 100644 --- a/deps/v8/src/objects-debug.cc +++ b/deps/v8/src/objects-debug.cc @@ -997,8 +997,6 @@ void AccessorInfo::AccessorInfoPrint() { data()->ShortPrint(); PrintF("\n - flag: "); flag()->ShortPrint(); - PrintF("\n - load_stub_cache: "); - load_stub_cache()->ShortPrint(); } void AccessCheckInfo::AccessCheckInfoVerify() { @@ -1048,7 +1046,6 @@ void CallHandlerInfo::CallHandlerInfoVerify() { CHECK(IsCallHandlerInfo()); VerifyPointer(callback()); VerifyPointer(data()); - VerifyPointer(call_stub_cache()); } void CallHandlerInfo::CallHandlerInfoPrint() { @@ -1057,8 +1054,6 @@ void CallHandlerInfo::CallHandlerInfoPrint() { callback()->ShortPrint(); PrintF("\n - data: "); data()->ShortPrint(); - PrintF("\n - call_stub_cache: "); - call_stub_cache()->ShortPrint(); } void TemplateInfo::TemplateInfoVerify() { diff --git a/deps/v8/src/objects-inl.h b/deps/v8/src/objects-inl.h index 79d70e1141d..1852b549bf1 100644 --- a/deps/v8/src/objects-inl.h +++ b/deps/v8/src/objects-inl.h @@ -2557,7 +2557,6 @@ ACCESSORS(InterceptorInfo, data, Object, kDataOffset) ACCESSORS(CallHandlerInfo, callback, Object, kCallbackOffset) ACCESSORS(CallHandlerInfo, data, Object, kDataOffset) -ACCESSORS(CallHandlerInfo, call_stub_cache, Object, kCallStubCacheOffset) ACCESSORS(TemplateInfo, tag, Object, kTagOffset) ACCESSORS(TemplateInfo, property_list, Object, kPropertyListOffset) @@ -2672,7 +2671,6 @@ 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); \ @@ -2688,36 +2686,30 @@ SMI_ACCESSORS(SharedFunctionInfo, this_property_assignments_count, (value << 1) & ~kHeapObjectTag); \ } -#define PSEUDO_SMI_ACCESSORS_HI(holder, name, offset) \ - STATIC_ASSERT(holder::offset % kPointerSize == kIntSize); \ +#define PSEUDO_SMI_ACCESSORS_HI(holder, name, offset) \ 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, 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) +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) #endif diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index 9d975ec5164..6029ad545b4 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -5423,7 +5423,6 @@ class CallHandlerInfo: public Struct { public: DECL_ACCESSORS(callback, Object) DECL_ACCESSORS(data, Object) - DECL_ACCESSORS(call_stub_cache, Object) static inline CallHandlerInfo* cast(Object* obj); @@ -5434,8 +5433,7 @@ class CallHandlerInfo: public Struct { static const int kCallbackOffset = HeapObject::kHeaderSize; static const int kDataOffset = kCallbackOffset + kPointerSize; - static const int kCallStubCacheOffset = kDataOffset + kPointerSize; - static const int kSize = kCallStubCacheOffset + kPointerSize; + static const int kSize = kDataOffset + kPointerSize; private: DISALLOW_IMPLICIT_CONSTRUCTORS(CallHandlerInfo); diff --git a/deps/v8/src/parser.cc b/deps/v8/src/parser.cc index a0f3b7147f2..aad7a615a51 100644 --- a/deps/v8/src/parser.cc +++ b/deps/v8/src/parser.cc @@ -36,9 +36,9 @@ #include "messages.h" #include "parser.h" #include "platform.h" -#include "preparser.h" #include "runtime.h" #include "scopeinfo.h" +#include "scopes.h" #include "string-stream.h" #include "ast-inl.h" @@ -323,96 +323,302 @@ TemporaryScope::~TemporaryScope() { } -Handle<String> Parser::LookupSymbol(int symbol_id, +// 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, 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> 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; + // 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(); return result; } - Counters::total_preparse_symbols_skipped.Increment(); - return result; -} + virtual Handle<String> EmptySymbol() { + return Factory::empty_symbol(); + } -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)); + virtual Expression* NewProperty(Expression* obj, Expression* key, int pos) { + return new Property(obj, key, pos); } - return data; -} + + 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_; +}; -void CompleteParserRecorder::LogSymbol(int start, Vector<const char> literal) { - if (!is_recording_) return; +// 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; + } - 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]; + virtual void PauseRecording() { + pause_count_++; + is_recording_ = false; } - WriteNumber(id - 1); -} + virtual void ResumeRecording() { + ASSERT(pause_count_ > 0); + if (--pause_count_ == 0) is_recording_ = !has_error(); + } -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)); + protected: + bool has_error() { + return static_cast<bool>(preamble_[ScriptDataImpl::kHasErrorOffset]); } - if (!has_error()) { - symbol_store_.WriteTo( - Vector<byte>::cast(data.SubVector(symbol_start, total_size))); + bool is_recording() { + return is_recording_; } - return data; -} + + 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(); + + 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; + } + + 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_; +}; FunctionEntry ScriptDataImpl::GetFunctionEntry(int start) { @@ -485,7 +691,7 @@ PartialParserRecorder::PartialParserRecorder() preamble_[ScriptDataImpl::kSizeOffset] = 0; ASSERT_EQ(6, ScriptDataImpl::kHeaderSize); #ifdef DEBUG - prev_start_ = -1; + prev_start = -1; #endif } @@ -536,8 +742,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(); @@ -594,12 +800,120 @@ unsigned* ScriptDataImpl::ReadAddress(int position) { } -Scope* Parser::NewScope(Scope* parent, Scope::Type type, bool inside_with) { +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* 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 ∅ +} + + +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 @@ -702,9 +1016,11 @@ 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) - : symbol_cache_(pre_data ? pre_data->symbol_count() : 0), - script_(script), + : script_(script), scanner_(), top_scope_(NULL), with_nesting_level_(0), @@ -712,11 +1028,34 @@ 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); @@ -739,21 +1078,21 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source, in_global_context ? Scope::GLOBAL_SCOPE : Scope::EVAL_SCOPE; - Handle<String> no_name = Factory::empty_symbol(); + Handle<String> no_name = factory()->EmptySymbol(); FunctionLiteral* result = NULL; - { Scope* scope = NewScope(top_scope_, type, inside_with()); + { Scope* scope = factory()->NewScope(top_scope_, type, inside_with()); LexicalScope lexical_scope(&this->top_scope_, &this->with_nesting_level_, scope); TemporaryScope temp_scope(&this->temp_scope_); - ZoneList<Statement*>* body = new ZoneList<Statement*>(16); + ZoneListWrapper<Statement> body(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, + body.elements(), temp_scope.materialized_literal_count(), temp_scope.expected_property_count(), temp_scope.only_simple_this_property_assignments(), @@ -762,7 +1101,7 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source, 0, source->length(), false, - temp_scope.ContainsLoops()); + temp_scope.ContainsLoops())); } else if (scanner().stack_overflow()) { Top::StackOverflow(); } @@ -800,9 +1139,9 @@ FunctionLiteral* Parser::ParseLazy(Handle<SharedFunctionInfo> info) { { // Parse the function literal. - Handle<String> no_name = Factory::empty_symbol(); + Handle<String> no_name = factory()->EmptySymbol(); Scope* scope = - NewScope(top_scope_, Scope::GLOBAL_SCOPE, inside_with()); + factory()->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_); @@ -830,24 +1169,28 @@ 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 LookupSymbol(symbol_id, scanner_.literal()); + return factory()->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 Parser::ReportMessageAt(Scanner::Location source_location, - const char* type, - Vector<const char*> args) { +void AstBuildingParser::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()); @@ -859,6 +1202,13 @@ void Parser::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 { @@ -900,11 +1250,6 @@ 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"]. @@ -957,7 +1302,7 @@ class InitializationBlockFinder : public ParserFinder { } void EndBlock() { - if (block_size_ >= kMinInitializationBlock) { + if (block_size_ >= Parser::kMinInitializationBlock) { first_in_block_->mark_block_start(); last_in_block_->mark_block_end(); } @@ -1115,7 +1460,7 @@ class ThisNamedPropertyAssigmentFinder : public ParserFinder { }; -void* Parser::ParseSourceElements(ZoneList<Statement*>* processor, +void* Parser::ParseSourceElements(ZoneListWrapper<Statement>* processor, int end_token, bool* ok) { // SourceElements :: @@ -1147,7 +1492,7 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor, } // Propagate the collected information on this property assignments. - if (top_scope_->is_function_scope()) { + if (!is_pre_parsing_ && 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; @@ -1200,7 +1545,7 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) { case Token::SEMICOLON: Next(); - return EmptyStatement(); + return factory()->EmptyStatement(); case Token::IF: stmt = ParseIfStatement(labels, ok); @@ -1248,7 +1593,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) { @@ -1278,11 +1623,11 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) { } -VariableProxy* Parser::Declare(Handle<String> name, - Variable::Mode mode, - FunctionLiteral* fun, - bool resolve, - bool* ok) { +VariableProxy* AstBuildingParser::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 @@ -1337,13 +1682,13 @@ VariableProxy* Parser::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 @@ -1395,13 +1740,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 @@ -1431,10 +1776,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))); } @@ -1452,7 +1797,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 EmptyStatement(); + return factory()->EmptyStatement(); } @@ -1464,7 +1809,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) { @@ -1523,7 +1868,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 { @@ -1614,14 +1959,14 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN, // browsers where the global object (window) has lots of // properties defined in prototype objects. - if (top_scope_->is_global_scope()) { + if (!is_pre_parsing_ && 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 @@ -1633,18 +1978,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 @@ -1659,8 +2004,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(); @@ -1668,8 +2013,14 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN, if (!is_const && nvars == 1) { // We have a single, non-const variable. - ASSERT(last_var != NULL); - *var = last_var; + 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; + } } return block; @@ -1704,27 +2055,29 @@ 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 (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 (!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 (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)); } @@ -1741,10 +2094,10 @@ IfStatement* Parser::ParseIfStatement(ZoneStringList* labels, bool* ok) { if (peek() == Token::ELSE) { Next(); else_statement = ParseStatement(labels, CHECK_OK); - } else { - else_statement = EmptyStatement(); + } else if (!is_pre_parsing_) { + else_statement = factory()->EmptyStatement(); } - return new IfStatement(condition, then_statement, else_statement); + return NEW(IfStatement(condition, then_statement, else_statement)); } @@ -1760,17 +2113,19 @@ Statement* Parser::ParseContinueStatement(bool* ok) { label = ParseIdentifier(CHECK_OK); } IterationStatement* target = NULL; - 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); + 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)); + } } ExpectSemicolon(CHECK_OK); - return new ContinueStatement(target); + return NEW(ContinueStatement(target)); } @@ -1788,20 +2143,22 @@ 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 EmptyStatement(); + return factory()->EmptyStatement(); } BreakableStatement* target = NULL; - 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); + 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)); + } } ExpectSemicolon(CHECK_OK); - return new BreakStatement(target); + return NEW(BreakStatement(target)); } @@ -1819,10 +2176,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 (!top_scope_->is_function_scope()) { + if (!is_pre_parsing_ && !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(); @@ -1831,12 +2188,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)); } @@ -1845,7 +2202,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); @@ -1857,21 +2214,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); } @@ -1913,15 +2270,15 @@ CaseClause* Parser::ParseCaseClause(bool* default_seen_ptr, bool* ok) { } Expect(Token::COLON, CHECK_OK); - ZoneList<Statement*>* statements = new ZoneList<Statement*>(5); + ZoneListWrapper<Statement> statements = factory()->NewList<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); + return NEW(CaseClause(label, statements.elements())); } @@ -1930,7 +2287,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); @@ -1939,15 +2296,15 @@ SwitchStatement* Parser::ParseSwitchStatement(ZoneStringList* labels, Expect(Token::RPAREN, CHECK_OK); bool default_seen = false; - ZoneList<CaseClause*>* cases = new ZoneList<CaseClause*>(4); + ZoneListWrapper<CaseClause> cases = factory()->NewList<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); + if (statement) statement->Initialize(tag, cases.elements()); return statement; } @@ -1966,7 +2323,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))); } @@ -1984,7 +2341,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; @@ -2007,7 +2364,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) { @@ -2022,8 +2379,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); } @@ -2046,28 +2403,30 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { // to: // 'try { try { } catch { } } finally { }' - if (catch_block != NULL && finally_block != NULL) { + if (!is_pre_parsing_ && 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 (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)); + 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()); } - result->set_escaping_targets(catch_collector.targets()); } return result; @@ -2080,7 +2439,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); @@ -2113,7 +2472,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); @@ -2143,7 +2502,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); @@ -2151,12 +2510,17 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { Expect(Token::RPAREN, CHECK_OK); Statement* body = ParseStatement(NULL, CHECK_OK); - 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; + 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; + } + } else { init = variable_statement; } @@ -2172,7 +2536,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); @@ -2185,13 +2549,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. @@ -2207,7 +2571,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); @@ -2228,7 +2592,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; } @@ -2288,7 +2652,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)); } @@ -2310,8 +2674,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)); } @@ -2418,12 +2782,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)); } } } @@ -2436,19 +2800,19 @@ Expression* Parser::NewCompareNode(Token::Value op, Expression* y, int position) { ASSERT(op != Token::NE && op != Token::NE_STRICT); - if (op == Token::EQ || op == Token::EQ_STRICT) { + if (!is_pre_parsing_ && (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)); } @@ -2485,7 +2849,7 @@ Expression* Parser::ParseUnaryExpression(bool* ok) { } } - return new UnaryOperation(op, expression); + return NEW(UnaryOperation(op, expression)); } else if (Token::IsCountOp(op)) { op = Next(); @@ -2499,8 +2863,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); @@ -2524,8 +2888,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; } @@ -2548,7 +2912,7 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) { Consume(Token::LBRACK); int pos = scanner().location().beg_pos; Expression* index = ParseExpression(true, CHECK_OK); - result = new Property(result, index, pos); + result = factory()->NewProperty(result, index, pos); Expect(Token::RBRACK, CHECK_OK); break; } @@ -2565,15 +2929,17 @@ 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. - 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(); + 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(); + } } } - result = NewCall(result, args, pos); + result = factory()->NewCall(result, args, pos); break; } @@ -2581,7 +2947,7 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) { Consume(Token::PERIOD); int pos = scanner().location().beg_pos; Handle<String> name = ParseIdentifierName(CHECK_OK); - result = new Property(result, new Literal(name), pos); + result = factory()->NewProperty(result, NEW(Literal(name)), pos); if (fni_ != NULL) fni_->PushLiteralName(name); break; } @@ -2593,6 +2959,7 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) { } + Expression* Parser::ParseNewPrefix(PositionStack* stack, bool* ok) { // NewExpression :: // ('new')+ MemberExpression @@ -2617,7 +2984,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; } @@ -2659,7 +3026,7 @@ Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack, Consume(Token::LBRACK); int pos = scanner().location().beg_pos; Expression* index = ParseExpression(true, CHECK_OK); - result = new Property(result, index, pos); + result = factory()->NewProperty(result, index, pos); Expect(Token::RBRACK, CHECK_OK); break; } @@ -2667,7 +3034,7 @@ Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack, Consume(Token::PERIOD); int pos = scanner().location().beg_pos; Handle<String> name = ParseIdentifierName(CHECK_OK); - result = new Property(result, new Literal(name), pos); + result = factory()->NewProperty(result, NEW(Literal(name)), pos); if (fni_ != NULL) fni_->PushLiteralName(name); break; } @@ -2676,7 +3043,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: @@ -2695,7 +3062,7 @@ DebuggerStatement* Parser::ParseDebuggerStatement(bool* ok) { Expect(Token::DEBUGGER, CHECK_OK); ExpectSemicolon(CHECK_OK); - return new DebuggerStatement(); + return NEW(DebuggerStatement()); } @@ -2753,30 +3120,38 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) { switch (peek()) { case Token::THIS: { Consume(Token::THIS); - VariableProxy* recv = top_scope_->receiver(); - result = recv; + if (is_pre_parsing_) { + result = VariableProxySentinel::this_proxy(); + } else { + 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); - result = top_scope_->NewUnresolved(name, inside_with()); + if (is_pre_parsing_) { + result = VariableProxySentinel::identifier_proxy(); + } else { + result = top_scope_->NewUnresolved(name, inside_with()); + } break; } @@ -2791,7 +3166,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; } @@ -2869,7 +3244,7 @@ Expression* Parser::ParseArrayLiteral(bool* ok) { // ArrayLiteral :: // '[' Expression? (',' Expression?)* ']' - ZoneList<Expression*>* values = new ZoneList<Expression*>(4); + ZoneListWrapper<Expression> values = factory()->NewList<Expression>(4); Expect(Token::LBRACK, CHECK_OK); while (peek() != Token::RBRACK) { Expression* elem; @@ -2878,7 +3253,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); } @@ -2888,19 +3263,21 @@ 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, n = values->length(); i < n; i++) { - MaterializedLiteral* m_literal = values->at(i)->AsMaterializedLiteral(); + for (int i = 0; i < values.length(); 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; @@ -2911,12 +3288,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, - literal_index, is_simple, depth); + return NEW(ArrayLiteral(literals, values.elements(), + literal_index, is_simple, depth)); } @@ -3063,7 +3440,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); @@ -3080,8 +3457,8 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { // | (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral) // )*[','] '}' - ZoneList<ObjectLiteral::Property*>* properties = - new ZoneList<ObjectLiteral::Property*>(4); + ZoneListWrapper<ObjectLiteral::Property> properties = + factory()->NewList<ObjectLiteral::Property>(4); int number_of_boilerplate_properties = 0; Expect(Token::LBRACE, CHECK_OK); @@ -3104,7 +3481,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) { @@ -3115,7 +3492,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: { @@ -3127,7 +3504,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { key = NewNumberLiteral(index); break; } - key = new Literal(string); + key = NEW(Literal(string)); break; } case Token::NUMBER: { @@ -3141,7 +3518,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(); @@ -3155,11 +3532,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); @@ -3172,6 +3549,7 @@ 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); @@ -3179,13 +3557,13 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { bool is_simple = true; bool fast_elements = true; int depth = 1; - BuildObjectLiteralConstantProperties(properties, + BuildObjectLiteralConstantProperties(properties.elements(), constant_properties, &is_simple, &fast_elements, &depth); return new ObjectLiteral(constant_properties, - properties, + properties.elements(), literal_index, is_simple, fast_elements, @@ -3203,6 +3581,19 @@ 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(); @@ -3218,17 +3609,17 @@ ZoneList<Expression*>* Parser::ParseArguments(bool* ok) { // Arguments :: // '(' (AssignmentExpression)*[','] ')' - ZoneList<Expression*>* result = new ZoneList<Expression*>(4); + ZoneListWrapper<Expression> result = factory()->NewList<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; + return result.elements(); } @@ -3244,9 +3635,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::empty_symbol(); + Handle<String> name = is_named ? var_name : factory()->EmptySymbol(); // The function name, if any. - Handle<String> function_name = Factory::empty_symbol(); + Handle<String> function_name = factory()->EmptySymbol(); if (is_named && (type == EXPRESSION || type == NESTED)) { function_name = name; } @@ -3254,7 +3645,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name, int num_parameters = 0; // Parse function body. { Scope* scope = - NewScope(top_scope_, Scope::FUNCTION_SCOPE, inside_with()); + factory()->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_); @@ -3267,16 +3658,18 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name, bool done = (peek() == Token::RPAREN); while (!done) { Handle<String> param_name = ParseIdentifier(CHECK_OK); - top_scope_->AddParameter(top_scope_->DeclareLocal(param_name, - Variable::VAR)); - num_parameters++; + if (!is_pre_parsing_) { + 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); - ZoneList<Statement*>* body = new ZoneList<Statement*>(8); + ZoneListWrapper<Statement> body = factory()->NewList<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 @@ -3284,15 +3677,17 @@ 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 (!function_name.is_null() && function_name->length() > 0) { + if (!is_pre_parsing_ + && !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 @@ -3324,8 +3719,12 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name, this_property_assignments = Factory::empty_fixed_array(); Expect(Token::RBRACE, CHECK_OK); } else { - ParseSourceElements(body, Token::RBRACE, CHECK_OK); - + 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); + } materialized_literal_count = temp_scope.materialized_literal_count(); expected_property_count = temp_scope.expected_property_count(); only_simple_this_property_assignments = @@ -3334,12 +3733,19 @@ 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, + body.elements(), materialized_literal_count, expected_property_count, only_simple_this_property_assignments, @@ -3348,8 +3754,10 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name, start_pos, end_pos, function_name->length() > 0, - temp_scope.ContainsLoops()); - function_literal->set_function_token_position(function_token_position); + temp_scope.ContainsLoops())); + if (!is_pre_parsing_) { + function_literal->set_function_token_position(function_token_position); + } if (fni_ != NULL && !is_named) fni_->AddFunction(function_literal); return function_literal; @@ -3364,6 +3772,7 @@ 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 @@ -3399,7 +3808,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)); } @@ -3447,12 +3856,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())); } @@ -3555,7 +3964,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))); } @@ -3587,6 +3996,8 @@ 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()); @@ -3774,17 +4185,17 @@ Handle<Object> JsonParser::ParseJsonArray() { RegExpParser::RegExpParser(FlatStringReader* in, Handle<String>* error, bool multiline) - : error_(error), - captures_(NULL), - in_(in), - current_(kEndMarker), - next_pos_(0), - capture_count_(0), + : current_(kEndMarker), 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); } @@ -4592,6 +5003,23 @@ 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) { @@ -4635,50 +5063,17 @@ int ScriptDataImpl::ReadNumber(byte** source) { } -// 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; - } - preparser::PreParser<Scanner, PartialParserRecorder> parser; - Scanner scanner; - scanner.Initialize(source, stream, JAVASCRIPT); - PartialParserRecorder recorder; - if (!parser.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); -} - - ScriptDataImpl* ParserApi::PreParse(Handle<String> source, unibrow::CharacterStream* stream, v8::Extension* extension) { Handle<Script> no_script; - preparser::PreParser<Scanner, CompleteParserRecorder> parser; - Scanner scanner; - scanner.Initialize(source, stream, JAVASCRIPT); - bool allow_lazy = FLAG_lazy && (extension == NULL); - CompleteParserRecorder recorder; - if (!parser.PreParseProgram(&scanner, &recorder, allow_lazy)) { - Top::StackOverflow(); - return NULL; - } + 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 = recorder.ExtractData(); + Vector<unsigned> store = parser.recorder()->ExtractData(); return new ScriptDataImpl(store); } @@ -4710,13 +5105,14 @@ bool ParserApi::Parse(CompilationInfo* info) { FunctionLiteral* result = NULL; Handle<Script> script = info->script(); if (info->is_lazy()) { - Parser parser(script, true, NULL, NULL); + AstBuildingParser 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(); - Parser parser(script, allow_natives_syntax, info->extension(), pre_data); + AstBuildingParser 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(); @@ -4738,4 +5134,6 @@ 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 667410b3ce3..19b382e8ded 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; @@ -177,125 +177,6 @@ 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 @@ -315,8 +196,6 @@ 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 @@ -532,44 +411,51 @@ 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, - ScriptDataImpl* pre_data); + Parser(Handle<Script> script, bool allow_natives_syntax, + v8::Extension* extension, ParserMode is_pre_parsing, + ParserFactory* factory, ParserLog* log, 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); - void ReportMessageAt(Scanner::Location loc, - const char* message, - Vector<const char*> args); + // 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; protected: + enum Mode { PARSE_LAZILY, PARSE_EAGERLY @@ -578,9 +464,28 @@ class Parser { // Report syntax error void ReportUnexpectedToken(Token::Value token); void ReportInvalidPreparseData(Handle<String> name, bool* ok); - void ReportMessage(const char* message, Vector<const char*> args); + + 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_; 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_; } @@ -589,7 +494,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(ZoneList<Statement*>* processor, + void* ParseSourceElements(ZoneListWrapper<Statement>* processor, int end_token, bool* ok); Statement* ParseStatement(ZoneStringList* labels, bool* ok); Statement* ParseFunctionDeclaration(bool* ok); @@ -702,10 +607,10 @@ class Parser { bool* ok); // Parser support - VariableProxy* Declare(Handle<String> name, Variable::Mode mode, - FunctionLiteral* fun, - bool resolve, - bool* ok); + virtual VariableProxy* Declare(Handle<String> name, Variable::Mode mode, + FunctionLiteral* fun, + bool resolve, + bool* ok) = 0; bool TargetStackContainsLabel(Handle<String> label); BreakableStatement* LookupBreakTarget(Handle<String> label, bool* ok); @@ -713,28 +618,6 @@ class Parser { void RegisterTargetUse(BreakTarget* target, Target* stop); - // Factory methods. - - Statement* EmptyStatement() { - static v8::internal::EmptyStatement empty; - return ∅ - } - - 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); @@ -756,24 +639,6 @@ 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_; }; @@ -808,9 +673,6 @@ 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 89003ba83f9..c0eb21395fe 100644 --- a/deps/v8/src/platform-linux.cc +++ b/deps/v8/src/platform-linux.cc @@ -99,12 +99,30 @@ uint64_t OS::CpuFeaturesImpliedByPlatform() { #ifdef __arm__ -static bool CPUInfoContainsString(const char * search_string) { +bool OS::ArmCpuHasFeature(CpuFeature feature) { + const char* search_string = NULL; 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; @@ -131,43 +149,6 @@ static bool CPUInfoContainsString(const char * search_string) { // 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__ @@ -828,17 +809,8 @@ 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. - 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 + int result = usleep(sampler_->interval_ * 1000 - 100); + ASSERT(result == 0 || errno == EINTR); USE(result); } } @@ -871,7 +843,6 @@ Sampler::Sampler(int interval, bool profiling) Sampler::~Sampler() { - ASSERT(!data_->signal_sender_launched_); delete data_; } diff --git a/deps/v8/src/preparser.h b/deps/v8/src/preparser.h deleted file mode 100644 index 44c55cf7db7..00000000000 --- a/deps/v8/src/preparser.h +++ /dev/null @@ -1,1414 +0,0 @@ -// 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" - -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) { - Expect(i::Token::CATCH, CHECK_OK); - Expect(i::Token::LPAREN, CHECK_OK); - ParseIdentifier(CHECK_OK); - Expect(i::Token::RPAREN, CHECK_OK); - ParseBlock(CHECK_OK); - catch_or_finally_seen = true; - } - if (peek() == i::Token::FINALLY) { - Expect(i::Token::FINALLY, CHECK_OK); - 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); - 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, strlen(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/profile-generator.cc b/deps/v8/src/profile-generator.cc index 29f9ab4d353..a4d9a828dd4 100644 --- a/deps/v8/src/profile-generator.cc +++ b/deps/v8/src/profile-generator.cc @@ -1848,6 +1848,22 @@ 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, @@ -1877,11 +1893,19 @@ class IndexedReferencesExtractor : public ObjectVisitor { void HeapSnapshotGenerator::ExtractReferences(HeapObject* obj) { // We need to reference JS global objects from snapshot's root. - // We use JSGlobalProxy because this is what embedder (e.g. browser) - // uses for the global object. + // 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. if (obj->IsJSGlobalProxy()) { + int global_security_token = GetGlobalSecurityToken(); JSGlobalProxy* proxy = JSGlobalProxy::cast(obj); - SetRootReference(proxy->map()->prototype()); + 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()); + } return; } diff --git a/deps/v8/src/profile-generator.h b/deps/v8/src/profile-generator.h index b691a056e85..6f63f6a122b 100644 --- a/deps/v8/src/profile-generator.h +++ b/deps/v8/src/profile-generator.h @@ -948,6 +948,8 @@ 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 9e708fd07b8..51f4b094d37 100644 --- a/deps/v8/src/regexp.js +++ b/deps/v8/src/regexp.js @@ -71,6 +71,9 @@ function DoConstructRegExp(object, pattern, flags, isConstructorCall) { } } + if (!isConstructorCall) { + regExpCache.type = 'none'; + } %RegExpInitializeObject(object, pattern, global, ignoreCase, multiline); // Call internal function to compile the pattern. @@ -118,6 +121,22 @@ 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); @@ -159,6 +178,32 @@ 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)) { @@ -172,13 +217,11 @@ function RegExpExec(string) { } else { s = ToString(string); } - var lastIndex = this.lastIndex; + var global = this.global; // 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; @@ -194,9 +237,16 @@ function RegExpExec(string) { if (matchIndices === null) { if (global) { + // Cache negative result only if initial lastIndex was zero. this.lastIndex = 0; + if (lastIndex !== 0) return matchIndices; } - return null; + 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. } // Successful match. @@ -204,9 +254,17 @@ function RegExpExec(string) { 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; + } @@ -231,22 +289,33 @@ 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 lastIndex = this.lastIndex; + var length = s.length; // 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) { + if (i < 0 || i > length) { this.lastIndex = 0; return false; } @@ -254,6 +323,8 @@ function RegExpTest(string) { 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 '?' @@ -263,7 +334,7 @@ function RegExpTest(string) { if (!%_ObjectEquals(regexp_key, this)) { regexp_key = this; regexp_val = new $RegExp(this.source.substring(2, this.source.length), - (global ? 'g' : '') + (this.global ? 'g' : '') + (this.ignoreCase ? 'i' : '') + (this.multiline ? 'm' : '')); } @@ -274,13 +345,24 @@ function RegExpTest(string) { // matchIndices is either null or the lastMatchInfo array. var matchIndices = %_RegExpExec(this, s, i, lastMatchInfo); - if (matchIndices === null) { - if (global) this.lastIndex = 0; - return false; + var result = (matchIndices !== null); + if (result) { + lastMatchInfoOverride = null; } - lastMatchInfoOverride = null; - if (global) this.lastIndex = lastMatchInfo[CAPTURE1]; - return true; + if (global) { + if (result) { + this.lastIndex = lastMatchInfo[CAPTURE1]; + return true; + } else { + this.lastIndex = 0; + if (lastIndex !== 0) return false; + } + } + cache.type = 'test'; + cache.regExp = this; + cache.subject = s; + cache.answer = result; + return result; } @@ -428,6 +510,7 @@ 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 5534db557ce..fc1a0232295 100644 --- a/deps/v8/src/runtime.cc +++ b/deps/v8/src/runtime.cc @@ -1424,6 +1424,66 @@ 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); @@ -8831,6 +8891,12 @@ 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 756099b413f..72a80379701 100644 --- a/deps/v8/src/runtime.h +++ b/deps/v8/src/runtime.h @@ -162,6 +162,7 @@ namespace internal { F(RegExpExecMultiple, 4, 1) \ F(RegExpInitializeObject, 5, 1) \ F(RegExpConstructResult, 3, 1) \ + F(RegExpCloneResult, 1, 1) \ \ /* JSON */ \ F(ParseJson, 1, 1) \ @@ -324,6 +325,7 @@ 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) \ @@ -424,7 +426,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) \ @@ -436,6 +438,7 @@ 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 deleted file mode 100644 index 6e9d40e0d19..00000000000 --- a/deps/v8/src/scanner-base.cc +++ /dev/null @@ -1,167 +0,0 @@ -// 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 "scanner-base.h" - -namespace v8 { -namespace internal { - -// ---------------------------------------------------------------------------- -// 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 deleted file mode 100644 index 500870b5759..00000000000 --- a/deps/v8/src/scanner-base.h +++ /dev/null @@ -1,165 +0,0 @@ -// 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 "token.h" -#include "unicode.h" - -namespace v8 { -namespace internal { - -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(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 a24952ac247..79d63f1774d 100755 --- a/deps/v8/src/scanner.cc +++ b/deps/v8/src/scanner.cc @@ -184,6 +184,142 @@ 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 diff --git a/deps/v8/src/scanner.h b/deps/v8/src/scanner.h index 1f49fd0e6ec..dab3d672815 100644 --- a/deps/v8/src/scanner.h +++ b/deps/v8/src/scanner.h @@ -30,7 +30,6 @@ #include "token.h" #include "char-predicates-inl.h" -#include "scanner-base.h" namespace v8 { namespace internal { @@ -143,6 +142,127 @@ 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 }; diff --git a/deps/v8/src/spaces.cc b/deps/v8/src/spaces.cc index 2f3e41aea49..e3fb9233129 100644 --- a/deps/v8/src/spaces.cc +++ b/deps/v8/src/spaces.cc @@ -270,9 +270,8 @@ void CodeRange::TearDown() { // ----------------------------------------------------------------------------- // MemoryAllocator // -intptr_t MemoryAllocator::capacity_ = 0; -intptr_t MemoryAllocator::capacity_executable_ = 0; -intptr_t MemoryAllocator::size_ = 0; +intptr_t MemoryAllocator::capacity_ = 0; +intptr_t MemoryAllocator::size_ = 0; intptr_t MemoryAllocator::size_executable_ = 0; List<MemoryAllocator::MemoryAllocationCallbackRegistration> @@ -303,10 +302,8 @@ int MemoryAllocator::Pop() { } -bool MemoryAllocator::Setup(intptr_t capacity, intptr_t capacity_executable) { +bool MemoryAllocator::Setup(intptr_t capacity) { 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 @@ -349,7 +346,6 @@ 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; } @@ -361,31 +357,16 @@ 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) { - // 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); + if (executable == EXECUTABLE && CodeRange::exists()) { + mem = CodeRange::AllocateRawMemory(requested, allocated); } else { - mem = OS::Allocate(requested, allocated, false); + mem = OS::Allocate(requested, allocated, (executable == EXECUTABLE)); } int alloced = static_cast<int>(*allocated); size_ += alloced; + if (executable == EXECUTABLE) size_executable_ += alloced; #ifdef DEBUG ZapBlock(reinterpret_cast<Address>(mem), alloced); #endif @@ -410,7 +391,6 @@ void MemoryAllocator::FreeRawMemory(void* mem, if (executable == EXECUTABLE) size_executable_ -= static_cast<int>(length); ASSERT(size_ >= 0); - ASSERT(size_executable_ >= 0); } diff --git a/deps/v8/src/spaces.h b/deps/v8/src/spaces.h index 0c10d2c7795..3ed2fe8b98a 100644 --- a/deps/v8/src/spaces.h +++ b/deps/v8/src/spaces.h @@ -491,8 +491,8 @@ class CodeRange : public AllStatic { class MemoryAllocator : public AllStatic { public: // Initializes its internal bookkeeping structures. - // Max capacity of the total space and executable memory limit. - static bool Setup(intptr_t max_capacity, intptr_t capacity_executable); + // Max capacity of the total space. + static bool Setup(intptr_t max_capacity); // Deletes valid chunks. static void TearDown(); @@ -590,12 +590,6 @@ class MemoryAllocator : public AllStatic { // Returns allocated spaces in bytes. static intptr_t Size() { return size_; } - // Returns the maximum available executable bytes of heaps. - static int 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_; } @@ -659,8 +653,6 @@ 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_; diff --git a/deps/v8/src/string.js b/deps/v8/src/string.js index d82ce05237e..d97f632b88d 100644 --- a/deps/v8/src/string.js +++ b/deps/v8/src/string.js @@ -144,6 +144,16 @@ 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 @@ -162,12 +172,33 @@ 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. - return %StringMatch(subject, regexp, lastMatchInfo); + 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; } // 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); } @@ -200,6 +231,7 @@ 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 { @@ -241,10 +273,24 @@ function StringReplace(search, replace) { // Helper function for regular expressions in String.prototype.replace. function StringReplaceRegExp(subject, regexp, replace) { - return %StringReplaceRegExpWithString(subject, - regexp, - TO_STRING_INLINE(replace), - lastMatchInfo); + 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; } @@ -559,12 +605,34 @@ 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) { - if (DoRegExpExec(separator, subject, 0, 0) != null) { + cache.answerSaved = true; + if (splitMatch(separator, subject, 0, 0) != null) { + cache.answer = []; return []; } + cache.answer = [subject]; return [subject]; } @@ -612,6 +680,8 @@ 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 0523d885f97..0ed1b0d9147 100644 --- a/deps/v8/src/strtod.cc +++ b/deps/v8/src/strtod.cc @@ -31,7 +31,6 @@ #include "v8.h" #include "strtod.h" -#include "bignum.h" #include "cached-powers.h" #include "double.h" @@ -84,12 +83,44 @@ 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); -// 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; + +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); +} + static Vector<const char> TrimLeadingZeros(Vector<const char> buffer) { for (int i = 0; i < buffer.length(); i++) { @@ -111,23 +142,6 @@ 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. @@ -360,81 +374,20 @@ 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); - trimmed = - Vector<const char>(significant_buffer, kMaxSignificantDecimalDigits); - exponent = significant_exponent; - } if (exponent + trimmed.length() - 1 >= kMaxDecimalPower) return V8_INFINITY; if (exponent + trimmed.length() <= kMinDecimalPower) return 0.0; - double guess; - if (DoubleStrtod(trimmed, exponent, &guess) || - DiyFpStrtod(trimmed, exponent, &guess)) { - return guess; + double result; + if (DoubleStrtod(trimmed, exponent, &result) || + DiyFpStrtod(trimmed, exponent, &result)) { + return result; } - return BignumStrtod(trimmed, exponent, guess); + return old_strtod(trimmed, exponent); } } } // namespace v8::internal diff --git a/deps/v8/src/token.h b/deps/v8/src/token.h index 74d9539f498..ebc7fea1cd5 100644 --- a/deps/v8/src/token.h +++ b/deps/v8/src/token.h @@ -28,8 +28,6 @@ #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 7096ba35ab2..45a4cd60f8d 100644 --- a/deps/v8/src/utils.cc +++ b/deps/v8/src/utils.cc @@ -37,6 +37,34 @@ 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); @@ -246,4 +274,12 @@ 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 86f4259ac61..05217677885 100644 --- a/deps/v8/src/utils.h +++ b/deps/v8/src/utils.h @@ -31,8 +31,6 @@ #include <stdlib.h> #include <string.h> -#include "checks.h" - namespace v8 { namespace internal { @@ -144,19 +142,7 @@ 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. -// 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; -} - +uint32_t RoundUpToPowerOf2(uint32_t x); template <typename T> @@ -230,18 +216,65 @@ class BitField { // ---------------------------------------------------------------------------- // Hash function. -// 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; -} +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); // ---------------------------------------------------------------------------- @@ -383,6 +416,23 @@ 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: @@ -434,6 +484,13 @@ 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. @@ -642,6 +699,156 @@ 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) { @@ -670,16 +877,56 @@ static inline int CompareChars(const lchar* lhs, const rchar* rhs, int chars) { } -// Calculate 10^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; +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); + + // The type-based aliasing rule allows the compiler to assume that pointers of // different types (for some definition of different) never alias each other. // Thus the following code does not work: diff --git a/deps/v8/src/v8.h b/deps/v8/src/v8.h index 1cb8d2f1a66..9dbdf4c28a9 100644 --- a/deps/v8/src/v8.h +++ b/deps/v8/src/v8.h @@ -56,7 +56,7 @@ #include "globals.h" #include "checks.h" #include "allocation.h" -#include "v8utils.h" +#include "utils.h" #include "flags.h" // Objects & heap diff --git a/deps/v8/src/v8utils.h b/deps/v8/src/v8utils.h deleted file mode 100644 index a907c9f5563..00000000000 --- a/deps/v8/src/v8utils.h +++ /dev/null @@ -1,301 +0,0 @@ -// 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 b45510ca1b8..e27b9153fcc 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 6 +#define BUILD_NUMBER 3 #define PATCH_LEVEL 0 #define CANDIDATE_VERSION false diff --git a/deps/v8/src/x64/assembler-x64.cc b/deps/v8/src/x64/assembler-x64.cc index caed7c8aa9b..bf5ee5bbb77 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), positions_recorder_(this) { + : code_targets_(100) { if (buffer == NULL) { // Do our own buffer management. if (buffer_size <= kMinimalBufferSize) { @@ -337,7 +337,10 @@ 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 @@ -842,7 +845,7 @@ void Assembler::call(Label* L) { void Assembler::call(Handle<Code> target, RelocInfo::Mode rmode) { - positions_recorder()->WriteRecordedPositions(); + WriteRecordedPositions(); EnsureSpace ensure_space(this); last_pc_ = pc_; // 1110 1000 #32-bit disp. @@ -2932,14 +2935,14 @@ void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) { } void Assembler::RecordJSReturn() { - positions_recorder()->WriteRecordedPositions(); + WriteRecordedPositions(); EnsureSpace ensure_space(this); RecordRelocInfo(RelocInfo::JS_RETURN); } void Assembler::RecordDebugBreakSlot() { - positions_recorder()->WriteRecordedPositions(); + WriteRecordedPositions(); EnsureSpace ensure_space(this); RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT); } @@ -2953,6 +2956,47 @@ 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 c7f763222e6..bbc10106276 100644 --- a/deps/v8/src/x64/assembler-x64.h +++ b/deps/v8/src/x64/assembler-x64.h @@ -1174,9 +1174,13 @@ class Assembler : public Malloced { // Use --debug_code to enable. void RecordComment(const char* msg); - int pc_offset() const { return static_cast<int>(pc_ - buffer_); } + void RecordPosition(int pos); + void RecordStatementPosition(int pos); + bool WriteRecordedPositions(); - PositionsRecorder* positions_recorder() { return &positions_recorder_; } + 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_; } // 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 @@ -1400,8 +1404,11 @@ class Assembler : public Malloced { // push-pop elimination byte* last_pc_; - PositionsRecorder positions_recorder_; - friend class PositionsRecorder; + // source position information + int current_statement_position_; + int current_position_; + int written_statement_position_; + int written_position_; }; diff --git a/deps/v8/src/x64/codegen-x64.cc b/deps/v8/src/x64/codegen-x64.cc index e0e40950e90..0faf775d51c 100644 --- a/deps/v8/src/x64/codegen-x64.cc +++ b/deps/v8/src/x64/codegen-x64.cc @@ -2956,7 +2956,7 @@ void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { CodeForStatementPosition(node); Load(node->expression()); Result return_value = frame_->Pop(); - masm()->positions_recorder()->WriteRecordedPositions(); + masm()->WriteRecordedPositions(); if (function_return_is_shadowed_) { function_return_.Jump(&return_value); } else { @@ -6564,6 +6564,86 @@ 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, diff --git a/deps/v8/src/x64/codegen-x64.h b/deps/v8/src/x64/codegen-x64.h index 1853c8327aa..795732451c3 100644 --- a/deps/v8/src/x64/codegen-x64.h +++ b/deps/v8/src/x64/codegen-x64.h @@ -656,6 +656,8 @@ 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 00ea684582a..4e0f6d4b624 100644 --- a/deps/v8/src/x64/full-codegen-x64.cc +++ b/deps/v8/src/x64/full-codegen-x64.cc @@ -1717,14 +1717,12 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr, // Code common for calls using the IC. ZoneList<Expression*>* args = expr->arguments(); int arg_count = args->length(); - { PreserveStatementPositionScope scope(masm()->positions_recorder()); - for (int i = 0; i < arg_count; i++) { - VisitForStackValue(args->at(i)); - } - __ Move(rcx, name); + for (int i = 0; i < arg_count; i++) { + VisitForStackValue(args->at(i)); } + __ Move(rcx, name); // Record source position for debugger. - SetSourcePosition(expr->position(), FORCED_POSITION); + SetSourcePosition(expr->position()); // Call the IC initialization code. InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, @@ -1742,15 +1740,13 @@ void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, // Code common for calls using the IC. ZoneList<Expression*>* args = expr->arguments(); int arg_count = args->length(); - { PreserveStatementPositionScope scope(masm()->positions_recorder()); - for (int i = 0; i < arg_count; i++) { - VisitForStackValue(args->at(i)); - } - VisitForAccumulatorValue(key); - __ movq(rcx, rax); + 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(), FORCED_POSITION); + SetSourcePosition(expr->position()); // Call the IC initialization code. InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; Handle<Code> ic = CodeGenerator::ComputeKeyedCallInitialize(arg_count, @@ -1766,13 +1762,11 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr) { // Code common for calls using the call stub. ZoneList<Expression*>* args = expr->arguments(); int arg_count = args->length(); - { PreserveStatementPositionScope scope(masm()->positions_recorder()); - for (int i = 0; i < arg_count; i++) { - VisitForStackValue(args->at(i)); - } + for (int i = 0; i < arg_count; i++) { + VisitForStackValue(args->at(i)); } // Record source position for debugger. - SetSourcePosition(expr->position(), FORCED_POSITION); + SetSourcePosition(expr->position()); InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); __ CallStub(&stub); @@ -1793,38 +1787,37 @@ 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(); - { PreserveStatementPositionScope pos_scope(masm()->positions_recorder()); - VisitForStackValue(fun); - __ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot. - - // Push the arguments. - for (int i = 0; i < arg_count; i++) { - VisitForStackValue(args->at(i)); - } + for (int i = 0; i < arg_count; i++) { + VisitForStackValue(args->at(i)); + } - // Push copy of the function - found below the arguments. - __ push(Operand(rsp, (arg_count + 1) * kPointerSize)); + // Push copy of the function - found below the arguments. + __ push(Operand(rsp, (arg_count + 1) * kPointerSize)); - // Push copy of the first argument or undefined if it doesn't exist. - if (arg_count > 0) { - __ push(Operand(rsp, arg_count * kPointerSize)); - } else { + // 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 the receiver of the enclosing function and do runtime call. - __ push(Operand(rbp, (2 + scope()->num_parameters()) * kPointerSize)); - __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3); + // 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); - // 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(), FORCED_POSITION); + SetSourcePosition(expr->position()); InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); __ CallStub(&stub); @@ -1841,37 +1834,35 @@ void FullCodeGenerator::VisitCall(Call* expr) { // Call to a lookup slot (dynamically introduced variable). Label 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 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); - } + // 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); } EmitCallWithStub(expr); @@ -1882,24 +1873,18 @@ void FullCodeGenerator::VisitCall(Call* expr) { Literal* key = prop->key()->AsLiteral(); if (key != NULL && key->handle()->IsSymbol()) { // Call to a named property, use call IC. - { PreserveStatementPositionScope scope(masm()->positions_recorder()); - VisitForStackValue(prop->obj()); - } + 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. - { PreserveStatementPositionScope scope(masm()->positions_recorder()); - VisitForStackValue(prop->obj()); - } + VisitForStackValue(prop->obj()); if (prop->is_synthetic()) { - { PreserveStatementPositionScope scope(masm()->positions_recorder()); - VisitForAccumulatorValue(prop->key()); - __ movq(rdx, Operand(rsp, 0)); - } + VisitForAccumulatorValue(prop->key()); + __ movq(rdx, Operand(rsp, 0)); // Record source code position for IC call. - SetSourcePosition(prop->position(), FORCED_POSITION); + SetSourcePosition(prop->position()); Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); EmitCallIC(ic, RelocInfo::CODE_TARGET); // Pop receiver. @@ -1924,9 +1909,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { loop_depth() == 0) { lit->set_try_full_codegen(true); } - { PreserveStatementPositionScope scope(masm()->positions_recorder()); - VisitForStackValue(fun); - } + VisitForStackValue(fun); // Load global receiver object. __ movq(rbx, CodeGenerator::GlobalObject()); __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset)); diff --git a/deps/v8/src/x64/ic-x64.cc b/deps/v8/src/x64/ic-x64.cc index 9ec781487be..1d95b7f663d 100644 --- a/deps/v8/src/x64/ic-x64.cc +++ b/deps/v8/src/x64/ic-x64.cc @@ -33,6 +33,7 @@ #include "ic-inl.h" #include "runtime.h" #include "stub-cache.h" +#include "utils.h" namespace v8 { namespace internal { diff --git a/deps/v8/test/cctest/SConscript b/deps/v8/test/cctest/SConscript index 620cd825cca..006653c2e8e 100644 --- a/deps/v8/test/cctest/SConscript +++ b/deps/v8/test/cctest/SConscript @@ -41,7 +41,6 @@ SOURCES = { 'test-alloc.cc', 'test-api.cc', 'test-ast.cc', - 'test-bignum.cc', 'test-circular-queue.cc', 'test-compiler.cc', 'test-conversions.cc', diff --git a/deps/v8/test/cctest/test-assembler-arm.cc b/deps/v8/test/cctest/test-assembler-arm.cc index 0f12f985a36..4f90b613a83 100644 --- a/deps/v8/test/cctest/test-assembler-arm.cc +++ b/deps/v8/test/cctest/test-assembler-arm.cc @@ -397,72 +397,4 @@ 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.cc b/deps/v8/test/cctest/test-bignum.cc deleted file mode 100644 index 9aa5ef30d0a..00000000000 --- a/deps/v8/test/cctest/test-bignum.cc +++ /dev/null @@ -1,1502 +0,0 @@ -// 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 748e3e8d91e..d59e2f5ad11 100644 --- a/deps/v8/test/cctest/test-debug.cc +++ b/deps/v8/test/cctest/test-debug.cc @@ -902,7 +902,6 @@ 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, @@ -910,17 +909,12 @@ 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) { - if (break_point_hit_count < max_break_point_hit_count) { - // Count the number of breaks. - break_point_hit_count++; + if (event == v8::Break && 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(); - } else if (terminate_after_max_break_point_hit) { - // Terminate execution after the last break if requested. - v8::V8::TerminateExecution(); - } + // Set the break flag again to come back here as soon as possible. + v8::Debug::DebugBreak(); } } @@ -6898,33 +6892,4 @@ 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-double.cc b/deps/v8/test/cctest/test-double.cc index 3594a4fe32a..a7a604ea433 100644 --- a/deps/v8/test/cctest/test-double.cc +++ b/deps/v8/test/cctest/test-double.cc @@ -202,19 +202,3 @@ 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-heap-profiler.cc b/deps/v8/test/cctest/test-heap-profiler.cc index b165190b0a9..b86a3361605 100644 --- a/deps/v8/test/cctest/test-heap-profiler.cc +++ b/deps/v8/test/cctest/test-heap-profiler.cc @@ -388,10 +388,14 @@ namespace { class NamedEntriesDetector { public: NamedEntriesDetector() - : has_A2(false), has_B2(false), has_C2(false) { + : has_A1(false), has_B1(false), has_C1(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; @@ -401,6 +405,9 @@ 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; @@ -457,7 +464,21 @@ 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" @@ -477,7 +498,14 @@ TEST(HeapSnapshot) { const_cast<i::HeapEntry*>( reinterpret_cast<const i::HeapEntry*>(global_env2))->PaintAllReachable(); - // Verify, that JS global object of env2 has '..2' properties. + // 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")); const v8::HeapGraphNode* a2_node = GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "a2"); CHECK_NE(NULL, a2_node); @@ -490,6 +518,9 @@ 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-mark-compact.cc b/deps/v8/test/cctest/test-mark-compact.cc index 994256712f0..ea5afecc1e3 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, 4*MB); + Heap::ConfigureHeap(2*256*KB, 4*MB); InitializeVM(); @@ -101,7 +101,7 @@ TEST(Promotion) { TEST(NoPromotion) { - Heap::ConfigureHeap(2*256*KB, 4*MB, 4*MB); + Heap::ConfigureHeap(2*256*KB, 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 7ae8dcfa386..02503f225ca 100755 --- a/deps/v8/test/cctest/test-parsing.cc +++ b/deps/v8/test/cctest/test-parsing.cc @@ -26,7 +26,6 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <stdlib.h> -#include <stdio.h> #include "v8.h" @@ -35,8 +34,7 @@ #include "parser.h" #include "utils.h" #include "execution.h" -#include "scanner.h" -#include "preparser.h" + #include "cctest.h" namespace i = ::v8::internal; @@ -241,32 +239,3 @@ 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()); - } -} diff --git a/deps/v8/test/cctest/test-spaces.cc b/deps/v8/test/cctest/test-spaces.cc index b399a4ef182..06f1bfaca29 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(), Heap::MaxExecutableSize())); + CHECK(MemoryAllocator::Setup(Heap::MaxReserved())); 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(), Heap::MaxExecutableSize())); + CHECK(MemoryAllocator::Setup(Heap::MaxReserved())); NewSpace new_space; @@ -172,7 +172,7 @@ TEST(NewSpace) { TEST(OldSpace) { CHECK(Heap::ConfigureHeapDefault()); - CHECK(MemoryAllocator::Setup(Heap::MaxReserved(), Heap::MaxExecutableSize())); + CHECK(MemoryAllocator::Setup(Heap::MaxReserved())); 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 d71d126b48d..56b26ea1eb9 100644 --- a/deps/v8/test/cctest/test-strtod.cc +++ b/deps/v8/test/cctest/test-strtod.cc @@ -4,10 +4,7 @@ #include "v8.h" -#include "bignum.h" #include "cctest.h" -#include "diy-fp.h" -#include "double.h" #include "strtod.h" using namespace v8::internal; @@ -205,14 +202,11 @@ 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/1e22. Both floating-point + // The following number is the result of 89255.0/1e-22. 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)); @@ -258,160 +252,4 @@ TEST(Strtod) { StrtodChar("1234567890123456789052345", 114)); CHECK_EQ(1234567890123456789052345e115, StrtodChar("1234567890123456789052345", 115)); - - // 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-927.js b/deps/v8/test/mjsunit/regress/regress-927.js deleted file mode 100644 index c671f7d480c..00000000000 --- a/deps/v8/test/mjsunit/regress/regress-927.js +++ /dev/null @@ -1,33 +0,0 @@ -// 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-conditional-position.js b/deps/v8/test/mjsunit/regress/regress-conditional-position.js deleted file mode 100644 index cd8f7bd7457..00000000000 --- a/deps/v8/test/mjsunit/regress/regress-conditional-position.js +++ /dev/null @@ -1,95 +0,0 @@ -// 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 c741f6a3e59..59d3ad3ee38 100644 --- a/deps/v8/test/mjsunit/string-split.js +++ b/deps/v8/test/mjsunit/string-split.js @@ -27,45 +27,76 @@ expected = ["A", undefined, "B", "bold", "/", "B", "and", undefined, "CODE", "coded", "/", "CODE", ""]; result = "A<B>bold</B>and<CODE>coded</CODE>".split(/<(\/)?([^<>]+)>/); -assertArrayEquals(expected, result); +assertArrayEquals(expected, result, 1); +expected = ["a", "b"]; +result = "ab".split(/a*?/); +assertArrayEquals(expected, result, 2); -assertArrayEquals(["a", "b"], "ab".split(/a*?/)); +expected = ["", "b"]; +result = "ab".split(/a*/); +assertArrayEquals(expected, result, 3); -assertArrayEquals(["", "b"], "ab".split(/a*/)); +expected = ["a"]; +result = "ab".split(/a*?/, 1); +assertArrayEquals(expected, result, 4); -assertArrayEquals(["a"], "ab".split(/a*?/, 1)); +expected = [""]; +result = "ab".split(/a*/, 1); +assertArrayEquals(expected, result, 5); -assertArrayEquals([""], "ab".split(/a*/, 1)); +expected = ["as","fas","fas","f"]; +result = "asdfasdfasdf".split("d"); +assertArrayEquals(expected, result, 6); -assertArrayEquals(["as","fas","fas","f"], "asdfasdfasdf".split("d")); +expected = ["as","fas","fas","f"]; +result = "asdfasdfasdf".split("d", -1); +assertArrayEquals(expected, result, 7); -assertArrayEquals(["as","fas","fas","f"], "asdfasdfasdf".split("d", -1)); +expected = ["as", "fas"]; +result = "asdfasdfasdf".split("d", 2); +assertArrayEquals(expected, result, 8); -assertArrayEquals(["as", "fas"], "asdfasdfasdf".split("d", 2)); +expected = []; +result = "asdfasdfasdf".split("d", 0); +assertArrayEquals(expected, result, 9); -assertArrayEquals([], "asdfasdfasdf".split("d", 0)); +expected = ["as","fas","fas",""]; +result = "asdfasdfasd".split("d"); +assertArrayEquals(expected, result, 10); -assertArrayEquals(["as","fas","fas",""], "asdfasdfasd".split("d")); +expected = []; +result = "".split(""); +assertArrayEquals(expected, result, 11); -assertArrayEquals([], "".split("")); +expected = [""] +result = "".split("a"); +assertArrayEquals(expected, result, 12); -assertArrayEquals([""], "".split("a")); +expected = ["a","b"] +result = "axxb".split(/x*/); +assertArrayEquals(expected, result, 13); -assertArrayEquals(["a","b"], "axxb".split(/x*/)); +expected = ["a","b"] +result = "axxb".split(/x+/); +assertArrayEquals(expected, result, 14); -assertArrayEquals(["a","b"], "axxb".split(/x+/)); - -assertArrayEquals(["a","","b"], "axxb".split(/x/)); +expected = ["a","","b"] +result = "axxb".split(/x/); +assertArrayEquals(expected, result, 15); // This was http://b/issue?id=1151354 -assertArrayEquals(["div", "#id", ".class"], "div#id.class".split(/(?=[#.])/)); - +expected = ["div", "#id", ".class"] +result = "div#id.class".split(/(?=[#.])/); +assertArrayEquals(expected, result, 16); -assertArrayEquals(["div", "#i", "d", ".class"], "div#id.class".split(/(?=[d#.])/)); - -assertArrayEquals(["a", "b", "c"], "abc".split(/(?=.)/)); +expected = ["div", "#i", "d", ".class"] +result = "div#id.class".split(/(?=[d#.])/); +assertArrayEquals(expected, result, 17); +expected = ["a", "b", "c"] +result = "abc".split(/(?=.)/); +assertArrayEquals(expected, result, 18); /* "ab".split(/((?=.))/) * @@ -77,23 +108,19 @@ assertArrayEquals(["a", "b", "c"], "abc".split(/(?=.)/)); * * Opera seems to have this right. The others make no sense. */ -assertArrayEquals(["a", "", "b"], "ab".split(/((?=.))/)); +expected = ["a", "", "b"] +result = "ab".split(/((?=.))/); +assertArrayEquals(expected, result, 19); /* "ab".split(/(?=)/) * * KJS: a,b * SM: ab * IE: a,b - * Opera: a,bb + * Opera: a,b * V8: a,b */ -assertArrayEquals(["a", "b"], "ab".split(/(?=)/)); - +expected = ["a", "b"] +result = "ab".split(/(?=)/); +assertArrayEquals(expected, result, 20); -// 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 65b86203222..17d556f1cf7 100644 --- a/deps/v8/tools/gyp/v8.gyp +++ b/deps/v8/tools/gyp/v8.gyp @@ -280,8 +280,6 @@ '../../src/ast.cc', '../../src/ast-inl.h', '../../src/ast.h', - '../../src/bignum.cc', - '../../src/bignum.h', '../../src/bootstrapper.cc', '../../src/bootstrapper.h', '../../src/builtins.cc', @@ -428,8 +426,6 @@ '../../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', diff --git a/deps/v8/tools/presubmit.py b/deps/v8/tools/presubmit.py index ebf8bd89396..e69c9a85ac8 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', 'include', 'samples', join('test', 'cctest')] + return ['src', 'public', 'samples', join('test', 'cctest')] def ProcessFiles(self, files, path): good_files_cache = FileContentsCache('.cpplint-cache') diff --git a/deps/v8/tools/v8.xcodeproj/project.pbxproj b/deps/v8/tools/v8.xcodeproj/project.pbxproj index 5f93c78a8e3..08558cc5b0e 100644 --- a/deps/v8/tools/v8.xcodeproj/project.pbxproj +++ b/deps/v8/tools/v8.xcodeproj/project.pbxproj @@ -115,7 +115,6 @@ 89A88E180E71A6960043BA31 /* property.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF16D0E719B8F00D62E90 /* property.cc */; }; 89A88E190E71A6970043BA31 /* rewriter.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF16F0E719B8F00D62E90 /* rewriter.cc */; }; 89A88E1A0E71A69B0043BA31 /* runtime.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1710E719B8F00D62E90 /* runtime.cc */; }; - 89A88E1B0E71A69D0043BA31 /* scanner-base.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1730E719B8F00D62E90 /* scanner-base.cc */; }; 89A88E1B0E71A69D0043BA31 /* scanner.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1730E719B8F00D62E90 /* scanner.cc */; }; 89A88E1C0E71A69E0043BA31 /* scopeinfo.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1760E719B8F00D62E90 /* scopeinfo.cc */; }; 89A88E1D0E71A6A00043BA31 /* scopes.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1780E719B8F00D62E90 /* scopes.cc */; }; @@ -178,7 +177,6 @@ 89F23C6C0E78D5B2006B2466 /* property.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF16D0E719B8F00D62E90 /* property.cc */; }; 89F23C6D0E78D5B2006B2466 /* rewriter.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF16F0E719B8F00D62E90 /* rewriter.cc */; }; 89F23C6E0E78D5B2006B2466 /* runtime.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1710E719B8F00D62E90 /* runtime.cc */; }; - 89F23C6F0E78D5B2006B2466 /* scanner-base.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1730E719B8F00D62E90 /* scanner-base.cc */; }; 89F23C6F0E78D5B2006B2466 /* scanner.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1730E719B8F00D62E90 /* scanner.cc */; }; 89F23C700E78D5B2006B2466 /* scopeinfo.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1760E719B8F00D62E90 /* scopeinfo.cc */; }; 89F23C710E78D5B2006B2466 /* scopes.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1780E719B8F00D62E90 /* scopes.cc */; }; @@ -483,8 +481,6 @@ 897FF1700E719B8F00D62E90 /* rewriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rewriter.h; sourceTree = "<group>"; }; 897FF1710E719B8F00D62E90 /* runtime.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = runtime.cc; sourceTree = "<group>"; }; 897FF1720E719B8F00D62E90 /* runtime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = runtime.h; sourceTree = "<group>"; }; - 897FF1730E719B8F00D62E90 /* scanner-base.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = scanner-base.cc; sourceTree = "<group>"; }; - 897FF1740E719B8F00D62E90 /* scanner-base.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scanner-base.h; sourceTree = "<group>"; }; 897FF1730E719B8F00D62E90 /* scanner.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = scanner.cc; sourceTree = "<group>"; }; 897FF1740E719B8F00D62E90 /* scanner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scanner.h; sourceTree = "<group>"; }; 897FF1750E719B8F00D62E90 /* SConscript */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SConscript; sourceTree = "<group>"; }; @@ -947,8 +943,6 @@ 897FF1700E719B8F00D62E90 /* rewriter.h */, 897FF1710E719B8F00D62E90 /* runtime.cc */, 897FF1720E719B8F00D62E90 /* runtime.h */, - 897FF1730E719B8F00D62E90 /* scanner-base.cc */, - 897FF1740E719B8F00D62E90 /* scanner-base.h */, 897FF1730E719B8F00D62E90 /* scanner.cc */, 897FF1740E719B8F00D62E90 /* scanner.h */, 897FF1760E719B8F00D62E90 /* scopeinfo.cc */, @@ -1354,7 +1348,6 @@ 58950D630F5551AF00F3E8BA /* register-allocator.cc in Sources */, 89A88E190E71A6970043BA31 /* rewriter.cc in Sources */, 89A88E1A0E71A69B0043BA31 /* runtime.cc in Sources */, - 89A88E1B0E71A69D0043BA31 /* scanner-base.cc in Sources */, 89A88E1B0E71A69D0043BA31 /* scanner.cc in Sources */, 89A88E1C0E71A69E0043BA31 /* scopeinfo.cc in Sources */, 89A88E1D0E71A6A00043BA31 /* scopes.cc in Sources */, @@ -1479,7 +1472,6 @@ 58950D640F5551B500F3E8BA /* register-allocator.cc in Sources */, 89F23C6D0E78D5B2006B2466 /* rewriter.cc in Sources */, 89F23C6E0E78D5B2006B2466 /* runtime.cc in Sources */, - 89F23C6F0E78D5B2006B2466 /* scanner-base.cc in Sources */, 89F23C6F0E78D5B2006B2466 /* scanner.cc in Sources */, 89F23C700E78D5B2006B2466 /* scopeinfo.cc in Sources */, 89F23C710E78D5B2006B2466 /* scopes.cc in Sources */, diff --git a/deps/v8/tools/visual_studio/v8_base.vcproj b/deps/v8/tools/visual_studio/v8_base.vcproj index d1ee48d6da7..62d450152f8 100644 --- a/deps/v8/tools/visual_studio/v8_base.vcproj +++ b/deps/v8/tools/visual_studio/v8_base.vcproj @@ -145,22 +145,6 @@ </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> @@ -257,22 +241,6 @@ > </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> @@ -914,14 +882,6 @@ > </File> <File - RelativePath="..\..\src\scanner-base.cc" - > - </File> - <File - RelativePath="..\..\src\scanner-base.h" - > - </File> - <File RelativePath="..\..\src\scanner.cc" > </File> |