Browse Source

Upgrade V8 to 2.5.6

v0.7.4-release
Ryan Dahl 14 years ago
parent
commit
564a48643b
  1. 1
      deps/v8/AUTHORS
  2. 23
      deps/v8/ChangeLog
  3. 4
      deps/v8/include/v8-debug.h
  4. 64
      deps/v8/include/v8.h
  5. 53
      deps/v8/include/v8stdint.h
  6. 2
      deps/v8/src/SConscript
  7. 15
      deps/v8/src/api.cc
  8. 114
      deps/v8/src/arm/assembler-arm.cc
  9. 41
      deps/v8/src/arm/assembler-arm.h
  10. 67
      deps/v8/src/arm/codegen-arm.cc
  11. 2
      deps/v8/src/arm/codegen-arm.h
  12. 7
      deps/v8/src/arm/constants-arm.h
  13. 119
      deps/v8/src/arm/full-codegen-arm.cc
  14. 4
      deps/v8/src/arm/ic-arm.cc
  15. 26
      deps/v8/src/arm/macro-assembler-arm.cc
  16. 108
      deps/v8/src/arm/simulator-arm.cc
  17. 3
      deps/v8/src/arm/simulator-arm.h
  18. 49
      deps/v8/src/assembler.cc
  19. 61
      deps/v8/src/assembler.h
  20. 767
      deps/v8/src/bignum.cc
  21. 140
      deps/v8/src/bignum.h
  22. 9
      deps/v8/src/checks.cc
  23. 19
      deps/v8/src/checks.h
  24. 28
      deps/v8/src/code-stubs.h
  25. 32
      deps/v8/src/codegen.cc
  26. 1
      deps/v8/src/compiler.cc
  27. 6
      deps/v8/src/conversions.cc
  28. 32
      deps/v8/src/debug-debugger.js
  29. 1
      deps/v8/src/debug.cc
  30. 32
      deps/v8/src/double.h
  31. 1
      deps/v8/src/flag-definitions.h
  32. 12
      deps/v8/src/full-codegen.cc
  33. 4
      deps/v8/src/full-codegen.h
  34. 6
      deps/v8/src/global-handles.cc
  35. 3
      deps/v8/src/global-handles.h
  36. 3
      deps/v8/src/globals.h
  37. 7
      deps/v8/src/heap-inl.h
  38. 72
      deps/v8/src/heap.cc
  39. 26
      deps/v8/src/heap.h
  40. 54
      deps/v8/src/ia32/assembler-ia32.cc
  41. 17
      deps/v8/src/ia32/assembler-ia32.h
  42. 20
      deps/v8/src/ia32/code-stubs-ia32.cc
  43. 90
      deps/v8/src/ia32/codegen-ia32.cc
  44. 5
      deps/v8/src/ia32/codegen-ia32.h
  45. 106
      deps/v8/src/ia32/full-codegen-ia32.cc
  46. 1
      deps/v8/src/ia32/ic-ia32.cc
  47. 2
      deps/v8/src/ia32/macro-assembler-ia32.h
  48. 178
      deps/v8/src/ia32/stub-cache-ia32.cc
  49. 5
      deps/v8/src/jump-target-heavy.cc
  50. 5
      deps/v8/src/jump-target-light.cc
  51. 5
      deps/v8/src/objects-debug.cc
  52. 42
      deps/v8/src/objects-inl.h
  53. 4
      deps/v8/src/objects.h
  54. 1102
      deps/v8/src/parser.cc
  55. 238
      deps/v8/src/parser.h
  56. 71
      deps/v8/src/platform-linux.cc
  57. 1414
      deps/v8/src/preparser.h
  58. 30
      deps/v8/src/profile-generator.cc
  59. 2
      deps/v8/src/profile-generator.h
  60. 115
      deps/v8/src/regexp.js
  61. 66
      deps/v8/src/runtime.cc
  62. 5
      deps/v8/src/runtime.h
  63. 167
      deps/v8/src/scanner-base.cc
  64. 165
      deps/v8/src/scanner-base.h
  65. 136
      deps/v8/src/scanner.cc
  66. 122
      deps/v8/src/scanner.h
  67. 34
      deps/v8/src/spaces.cc
  68. 12
      deps/v8/src/spaces.h
  69. 82
      deps/v8/src/string.js
  70. 129
      deps/v8/src/strtod.cc
  71. 2
      deps/v8/src/token.h
  72. 36
      deps/v8/src/utils.cc
  73. 315
      deps/v8/src/utils.h
  74. 2
      deps/v8/src/v8.h
  75. 301
      deps/v8/src/v8utils.h
  76. 2
      deps/v8/src/version.cc
  77. 54
      deps/v8/src/x64/assembler-x64.cc
  78. 15
      deps/v8/src/x64/assembler-x64.h
  79. 82
      deps/v8/src/x64/codegen-x64.cc
  80. 2
      deps/v8/src/x64/codegen-x64.h
  81. 157
      deps/v8/src/x64/full-codegen-x64.cc
  82. 1
      deps/v8/src/x64/ic-x64.cc
  83. 1
      deps/v8/test/cctest/SConscript
  84. 68
      deps/v8/test/cctest/test-assembler-arm.cc
  85. 1502
      deps/v8/test/cctest/test-bignum.cc
  86. 45
      deps/v8/test/cctest/test-debug.cc
  87. 16
      deps/v8/test/cctest/test-double.cc
  88. 35
      deps/v8/test/cctest/test-heap-profiler.cc
  89. 4
      deps/v8/test/cctest/test-mark-compact.cc
  90. 33
      deps/v8/test/cctest/test-parsing.cc
  91. 6
      deps/v8/test/cctest/test-spaces.cc
  92. 164
      deps/v8/test/cctest/test-strtod.cc
  93. 33
      deps/v8/test/mjsunit/regress/regress-927.js
  94. 95
      deps/v8/test/mjsunit/regress/regress-conditional-position.js
  95. 91
      deps/v8/test/mjsunit/string-split.js
  96. 4
      deps/v8/tools/gyp/v8.gyp
  97. 2
      deps/v8/tools/presubmit.py
  98. 8
      deps/v8/tools/v8.xcodeproj/project.pbxproj
  99. 40
      deps/v8/tools/visual_studio/v8_base.vcproj

1
deps/v8/AUTHORS

@ -9,6 +9,7 @@ ARM Ltd.
Hewlett-Packard Development Company, LP
Alexander Botero-Lowry <alexbl@FreeBSD.org>
Alexandre Rames <alexandre.rames@arm.com>
Alexandre Vassalotti <avassalotti@gmail.com>
Andreas Anyuru <andreas.anyuru@gmail.com>
Burcu Dogan <burcujdogan@gmail.com>

23
deps/v8/ChangeLog

@ -1,3 +1,26 @@
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

4
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

64
deps/v8/include/v8.h

@ -38,23 +38,9 @@
#ifndef V8_H_
#define V8_H_
#include <stdio.h>
#include "v8stdint.h"
#ifdef _WIN32
// When compiling on MinGW stdint.h is available.
#ifdef __MINGW32__
#include <stdint.h>
#else // __MINGW32__
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef short int16_t; // NOLINT
typedef unsigned short uint16_t; // NOLINT
typedef int int32_t;
typedef unsigned int uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
// intptr_t and friends are defined in crtdefs.h through stdio.h.
#endif // __MINGW32__
// Setup for Windows DLL export/import. When building the V8 DLL the
// BUILDING_V8_SHARED needs to be defined. When building a program which uses
@ -76,8 +62,6 @@ typedef unsigned __int64 uint64_t;
#else // _WIN32
#include <stdint.h>
// Setup for Linux shared library export. There is no need to distinguish
// between building or using the V8 shared library, but we should not
// export symbols when we are building a static library.
@ -127,7 +111,6 @@ class Arguments;
class Object;
class Heap;
class Top;
}
@ -476,10 +459,10 @@ class V8EXPORT HandleScope {
level = 0;
}
};
void Leave();
internal::Object** prev_next_;
internal::Object** prev_limit_;
@ -1055,7 +1038,7 @@ class String : public Primitive {
*/
V8EXPORT bool IsExternalAscii() const;
class V8EXPORT ExternalStringResourceBase {
class V8EXPORT ExternalStringResourceBase { // NOLINT
public:
virtual ~ExternalStringResourceBase() {}
@ -2365,12 +2348,15 @@ class V8EXPORT ResourceConstraints {
void set_max_young_space_size(int value) { max_young_space_size_ = value; }
int max_old_space_size() const { return max_old_space_size_; }
void set_max_old_space_size(int value) { max_old_space_size_ = value; }
int max_executable_size() { return max_executable_size_; }
void set_max_executable_size(int value) { max_executable_size_ = value; }
uint32_t* stack_limit() const { return stack_limit_; }
// Sets an address beyond which the VM's stack may not grow.
void set_stack_limit(uint32_t* value) { stack_limit_ = value; }
private:
int max_young_space_size_;
int max_old_space_size_;
int max_executable_size_;
uint32_t* stack_limit_;
};
@ -2502,13 +2488,18 @@ class V8EXPORT HeapStatistics {
public:
HeapStatistics();
size_t total_heap_size() { return total_heap_size_; }
size_t total_heap_size_executable() { return total_heap_size_executable_; }
size_t used_heap_size() { return used_heap_size_; }
private:
void set_total_heap_size(size_t size) { total_heap_size_ = size; }
void set_total_heap_size_executable(size_t size) {
total_heap_size_executable_ = size;
}
void set_used_heap_size(size_t size) { used_heap_size_ = size; }
size_t total_heap_size_;
size_t total_heap_size_executable_;
size_t used_heap_size_;
friend class V8;
@ -3260,8 +3251,8 @@ class V8EXPORT Locker {
/**
* An interface for exporting data from V8, using "push" model.
*/
class V8EXPORT OutputStream {
public:
class V8EXPORT OutputStream { // NOLINT
public:
enum OutputEncoding {
kAscii = 0 // 7-bit ASCII.
};
@ -3291,6 +3282,8 @@ public:
namespace internal {
const int kPointerSize = sizeof(void*); // NOLINT
const int kIntSize = sizeof(int); // NOLINT
// Tag information for HeapObject.
const int kHeapObjectTag = 1;
@ -3326,19 +3319,19 @@ template <> struct SmiConstants<8> {
}
};
const int kSmiShiftSize = SmiConstants<sizeof(void*)>::kSmiShiftSize;
const int kSmiValueSize = SmiConstants<sizeof(void*)>::kSmiValueSize;
const int kSmiShiftSize = SmiConstants<kPointerSize>::kSmiShiftSize;
const int kSmiValueSize = SmiConstants<kPointerSize>::kSmiValueSize;
template <size_t ptr_size> struct InternalConstants;
// Internal constants for 32-bit systems.
template <> struct InternalConstants<4> {
static const int kStringResourceOffset = 3 * sizeof(void*);
static const int kStringResourceOffset = 3 * kPointerSize;
};
// Internal constants for 64-bit systems.
template <> struct InternalConstants<8> {
static const int kStringResourceOffset = 3 * sizeof(void*);
static const int kStringResourceOffset = 3 * kPointerSize;
};
/**
@ -3352,12 +3345,12 @@ class Internals {
// These values match non-compiler-dependent values defined within
// the implementation of v8.
static const int kHeapObjectMapOffset = 0;
static const int kMapInstanceTypeOffset = sizeof(void*) + sizeof(int);
static const int kMapInstanceTypeOffset = kPointerSize + kIntSize;
static const int kStringResourceOffset =
InternalConstants<sizeof(void*)>::kStringResourceOffset;
InternalConstants<kPointerSize>::kStringResourceOffset;
static const int kProxyProxyOffset = sizeof(void*);
static const int kJSObjectHeaderSize = 3 * sizeof(void*);
static const int kProxyProxyOffset = kPointerSize;
static const int kJSObjectHeaderSize = 3 * kPointerSize;
static const int kFullStringRepresentationMask = 0x07;
static const int kExternalTwoByteRepresentationTag = 0x02;
@ -3375,7 +3368,7 @@ class Internals {
}
static inline int SmiValue(internal::Object* value) {
return SmiConstants<sizeof(void*)>::SmiToInt(value);
return SmiConstants<kPointerSize>::SmiToInt(value);
}
static inline int GetInstanceType(internal::Object* obj) {
@ -3404,10 +3397,9 @@ class Internals {
uint8_t* addr = reinterpret_cast<uint8_t*>(ptr) + offset - kHeapObjectTag;
return *reinterpret_cast<T*>(addr);
}
};
}
} // namespace internal
template <class T>
@ -3567,7 +3559,7 @@ Local<Value> Object::UncheckedGetInternalField(int index) {
// If the object is a plain JSObject, which is the common case,
// we know where to find the internal fields and can return the
// value directly.
int offset = I::kJSObjectHeaderSize + (sizeof(void*) * index);
int offset = I::kJSObjectHeaderSize + (internal::kPointerSize * index);
O* value = I::ReadField<O*>(obj, offset);
O** result = HandleScope::CreateHandle(value);
return Local<Value>(reinterpret_cast<Value*>(result));
@ -3603,7 +3595,7 @@ void* Object::GetPointerFromInternalField(int index) {
// If the object is a plain JSObject, which is the common case,
// we know where to find the internal fields and can return the
// value directly.
int offset = I::kJSObjectHeaderSize + (sizeof(void*) * index);
int offset = I::kJSObjectHeaderSize + (internal::kPointerSize * index);
O* value = I::ReadField<O*>(obj, offset);
return I::GetExternalPointer(value);
}

53
deps/v8/include/v8stdint.h

@ -0,0 +1,53 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Load definitions of standard types.
#ifndef V8STDINT_H_
#define V8STDINT_H_
#include <stdio.h>
#if defined(_WIN32) && !defined(__MINGW32__)
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef short int16_t; // NOLINT
typedef unsigned short uint16_t; // NOLINT
typedef int int32_t;
typedef unsigned int uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
// intptr_t and friends are defined in crtdefs.h through stdio.h.
#else
#include <stdint.h>
#endif
#endif // V8STDINT_H_

2
deps/v8/src/SConscript

@ -40,6 +40,7 @@ SOURCES = {
api.cc
assembler.cc
ast.cc
bignum.cc
bootstrapper.cc
builtins.cc
cached-powers.cc
@ -95,6 +96,7 @@ SOURCES = {
register-allocator.cc
rewriter.cc
runtime.cc
scanner-base.cc
scanner.cc
scopeinfo.cc
scopes.cc

15
deps/v8/src/api.cc

@ -43,7 +43,6 @@
#include "serialize.h"
#include "snapshot.h"
#include "top.h"
#include "utils.h"
#include "v8threads.h"
#include "version.h"
@ -394,14 +393,18 @@ v8::Handle<Boolean> False() {
ResourceConstraints::ResourceConstraints()
: max_young_space_size_(0),
max_old_space_size_(0),
max_executable_size_(0),
stack_limit_(NULL) { }
bool SetResourceConstraints(ResourceConstraints* constraints) {
int young_space_size = constraints->max_young_space_size();
int old_gen_size = constraints->max_old_space_size();
if (young_space_size != 0 || old_gen_size != 0) {
bool result = i::Heap::ConfigureHeap(young_space_size / 2, old_gen_size);
int max_executable_size = constraints->max_executable_size();
if (young_space_size != 0 || old_gen_size != 0 || max_executable_size != 0) {
bool result = i::Heap::ConfigureHeap(young_space_size / 2,
old_gen_size,
max_executable_size);
if (!result) return false;
}
if (constraints->stack_limit() != NULL) {
@ -3260,11 +3263,15 @@ bool v8::V8::Dispose() {
}
HeapStatistics::HeapStatistics(): total_heap_size_(0), used_heap_size_(0) { }
HeapStatistics::HeapStatistics(): total_heap_size_(0),
total_heap_size_executable_(0),
used_heap_size_(0) { }
void v8::V8::GetHeapStatistics(HeapStatistics* heap_statistics) {
heap_statistics->set_total_heap_size(i::Heap::CommittedMemory());
heap_statistics->set_total_heap_size_executable(
i::Heap::CommittedMemoryExecutable());
heap_statistics->set_used_heap_size(i::Heap::SizeOfObjects());
}

114
deps/v8/src/arm/assembler-arm.cc

@ -317,7 +317,8 @@ static const Instr kLdrStrOffsetMask = 0x00000fff;
static const int kMinimalBufferSize = 4*KB;
static byte* spare_buffer_ = NULL;
Assembler::Assembler(void* buffer, int buffer_size) {
Assembler::Assembler(void* buffer, int buffer_size)
: positions_recorder_(this) {
if (buffer == NULL) {
// Do our own buffer management.
if (buffer_size <= kMinimalBufferSize) {
@ -354,10 +355,6 @@ Assembler::Assembler(void* buffer, int buffer_size) {
no_const_pool_before_ = 0;
last_const_pool_end_ = 0;
last_bound_pos_ = 0;
current_statement_position_ = RelocInfo::kNoPosition;
current_position_ = RelocInfo::kNoPosition;
written_statement_position_ = current_statement_position_;
written_position_ = current_position_;
}
@ -752,15 +749,15 @@ static bool fits_shifter(uint32_t imm32,
// if they can be encoded in the ARM's 12 bits of immediate-offset instruction
// space. There is no guarantee that the relocated location can be similarly
// encoded.
static bool MustUseConstantPool(RelocInfo::Mode rmode) {
if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
bool Operand::must_use_constant_pool() const {
if (rmode_ == RelocInfo::EXTERNAL_REFERENCE) {
#ifdef DEBUG
if (!Serializer::enabled()) {
Serializer::TooLateToEnableNow();
}
#endif // def DEBUG
return Serializer::enabled();
} else if (rmode == RelocInfo::NONE) {
} else if (rmode_ == RelocInfo::NONE) {
return false;
}
return true;
@ -769,7 +766,7 @@ static bool MustUseConstantPool(RelocInfo::Mode rmode) {
bool Operand::is_single_instruction() const {
if (rm_.is_valid()) return true;
if (MustUseConstantPool(rmode_)) return false;
if (must_use_constant_pool()) return false;
uint32_t dummy1, dummy2;
return fits_shifter(imm32_, &dummy1, &dummy2, NULL);
}
@ -785,7 +782,7 @@ void Assembler::addrmod1(Instr instr,
// Immediate.
uint32_t rotate_imm;
uint32_t immed_8;
if (MustUseConstantPool(x.rmode_) ||
if (x.must_use_constant_pool() ||
!fits_shifter(x.imm32_, &rotate_imm, &immed_8, &instr)) {
// The immediate operand cannot be encoded as a shifter operand, so load
// it first to register ip and change the original instruction to use ip.
@ -794,8 +791,7 @@ void Assembler::addrmod1(Instr instr,
CHECK(!rn.is(ip)); // rn should never be ip, or will be trashed
Condition cond = static_cast<Condition>(instr & CondMask);
if ((instr & ~CondMask) == 13*B21) { // mov, S not set
if (MustUseConstantPool(x.rmode_) ||
!CpuFeatures::IsSupported(ARMv7)) {
if (x.must_use_constant_pool() || !CpuFeatures::IsSupported(ARMv7)) {
RecordRelocInfo(x.rmode_, x.imm32_);
ldr(rd, MemOperand(pc, 0), cond);
} else {
@ -806,7 +802,7 @@ void Assembler::addrmod1(Instr instr,
} else {
// If this is not a mov or mvn instruction we may still be able to avoid
// a constant pool entry by using mvn or movw.
if (!MustUseConstantPool(x.rmode_) &&
if (!x.must_use_constant_pool() &&
(instr & kMovMvnMask) != kMovMvnPattern) {
mov(ip, x, LeaveCC, cond);
} else {
@ -999,7 +995,7 @@ void Assembler::bl(int branch_offset, Condition cond) {
void Assembler::blx(int branch_offset) { // v5 and above
WriteRecordedPositions();
positions_recorder()->WriteRecordedPositions();
ASSERT((branch_offset & 1) == 0);
int h = ((branch_offset & 2) >> 1)*B24;
int imm24 = branch_offset >> 2;
@ -1009,14 +1005,14 @@ void Assembler::blx(int branch_offset) { // v5 and above
void Assembler::blx(Register target, Condition cond) { // v5 and above
WriteRecordedPositions();
positions_recorder()->WriteRecordedPositions();
ASSERT(!target.is(pc));
emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | 3*B4 | target.code());
}
void Assembler::bx(Register target, Condition cond) { // v5 and above, plus v4t
WriteRecordedPositions();
positions_recorder()->WriteRecordedPositions();
ASSERT(!target.is(pc)); // use of pc is actually allowed, but discouraged
emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | B4 | target.code());
}
@ -1114,7 +1110,7 @@ void Assembler::orr(Register dst, Register src1, const Operand& src2,
void Assembler::mov(Register dst, const Operand& src, SBit s, Condition cond) {
if (dst.is(pc)) {
WriteRecordedPositions();
positions_recorder()->WriteRecordedPositions();
}
// Don't allow nop instructions in the form mov rn, rn to be generated using
// the mov instruction. They must be generated using nop(int)
@ -1339,7 +1335,7 @@ void Assembler::msr(SRegisterFieldMask fields, const Operand& src,
// Immediate.
uint32_t rotate_imm;
uint32_t immed_8;
if (MustUseConstantPool(src.rmode_) ||
if (src.must_use_constant_pool() ||
!fits_shifter(src.imm32_, &rotate_imm, &immed_8, NULL)) {
// Immediate operand cannot be encoded, load it first to register ip.
RecordRelocInfo(src.rmode_, src.imm32_);
@ -1359,7 +1355,7 @@ void Assembler::msr(SRegisterFieldMask fields, const Operand& src,
// Load/Store instructions.
void Assembler::ldr(Register dst, const MemOperand& src, Condition cond) {
if (dst.is(pc)) {
WriteRecordedPositions();
positions_recorder()->WriteRecordedPositions();
}
addrmod2(cond | B26 | L, dst, src);
@ -2148,6 +2144,7 @@ static Instr EncodeVCVT(const VFPType dst_type,
const int dst_code,
const VFPType src_type,
const int src_code,
Assembler::ConversionMode mode,
const Condition cond) {
ASSERT(src_type != dst_type);
int D, Vd, M, Vm;
@ -2166,7 +2163,7 @@ static Instr EncodeVCVT(const VFPType dst_type,
if (IsIntegerVFPType(dst_type)) {
opc2 = IsSignedVFPType(dst_type) ? 0x5 : 0x4;
sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0;
op = 1; // round towards zero
op = mode;
} else {
ASSERT(IsIntegerVFPType(src_type));
opc2 = 0x0;
@ -2190,57 +2187,64 @@ static Instr EncodeVCVT(const VFPType dst_type,
void Assembler::vcvt_f64_s32(const DwVfpRegister dst,
const SwVfpRegister src,
ConversionMode mode,
const Condition cond) {
ASSERT(CpuFeatures::IsEnabled(VFP3));
emit(EncodeVCVT(F64, dst.code(), S32, src.code(), cond));
emit(EncodeVCVT(F64, dst.code(), S32, src.code(), mode, cond));
}
void Assembler::vcvt_f32_s32(const SwVfpRegister dst,
const SwVfpRegister src,
ConversionMode mode,
const Condition cond) {
ASSERT(CpuFeatures::IsEnabled(VFP3));
emit(EncodeVCVT(F32, dst.code(), S32, src.code(), cond));
emit(EncodeVCVT(F32, dst.code(), S32, src.code(), mode, cond));
}
void Assembler::vcvt_f64_u32(const DwVfpRegister dst,
const SwVfpRegister src,
ConversionMode mode,
const Condition cond) {
ASSERT(CpuFeatures::IsEnabled(VFP3));
emit(EncodeVCVT(F64, dst.code(), U32, src.code(), cond));
emit(EncodeVCVT(F64, dst.code(), U32, src.code(), mode, cond));
}
void Assembler::vcvt_s32_f64(const SwVfpRegister dst,
const DwVfpRegister src,
ConversionMode mode,
const Condition cond) {
ASSERT(CpuFeatures::IsEnabled(VFP3));
emit(EncodeVCVT(S32, dst.code(), F64, src.code(), cond));
emit(EncodeVCVT(S32, dst.code(), F64, src.code(), mode, cond));
}
void Assembler::vcvt_u32_f64(const SwVfpRegister dst,
const DwVfpRegister src,
ConversionMode mode,
const Condition cond) {
ASSERT(CpuFeatures::IsEnabled(VFP3));
emit(EncodeVCVT(U32, dst.code(), F64, src.code(), cond));
emit(EncodeVCVT(U32, dst.code(), F64, src.code(), mode, cond));
}
void Assembler::vcvt_f64_f32(const DwVfpRegister dst,
const SwVfpRegister src,
ConversionMode mode,
const Condition cond) {
ASSERT(CpuFeatures::IsEnabled(VFP3));
emit(EncodeVCVT(F64, dst.code(), F32, src.code(), cond));
emit(EncodeVCVT(F64, dst.code(), F32, src.code(), mode, cond));
}
void Assembler::vcvt_f32_f64(const SwVfpRegister dst,
const DwVfpRegister src,
ConversionMode mode,
const Condition cond) {
ASSERT(CpuFeatures::IsEnabled(VFP3));
emit(EncodeVCVT(F32, dst.code(), F64, src.code(), cond));
emit(EncodeVCVT(F32, dst.code(), F64, src.code(), mode, cond));
}
@ -2333,6 +2337,16 @@ void Assembler::vcmp(const DwVfpRegister src1,
}
void Assembler::vmsr(Register dst, Condition cond) {
// Instruction details available in ARM DDI 0406A, A8-652.
// cond(31-28) | 1110 (27-24) | 1110(23-20)| 0001 (19-16) |
// Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
ASSERT(CpuFeatures::IsEnabled(VFP3));
emit(cond | 0xE*B24 | 0xE*B20 | B16 |
dst.code()*B12 | 0xA*B8 | B4);
}
void Assembler::vmrs(Register dst, Condition cond) {
// Instruction details available in ARM DDI 0406A, A8-652.
// cond(31-28) | 1110 (27-24) | 1111(23-20)| 0001 (19-16) |
@ -2343,7 +2357,6 @@ void Assembler::vmrs(Register dst, Condition cond) {
}
void Assembler::vsqrt(const DwVfpRegister dst,
const DwVfpRegister src,
const Condition cond) {
@ -2377,14 +2390,14 @@ void Assembler::BlockConstPoolFor(int instructions) {
// Debugging.
void Assembler::RecordJSReturn() {
WriteRecordedPositions();
positions_recorder()->WriteRecordedPositions();
CheckBuffer();
RecordRelocInfo(RelocInfo::JS_RETURN);
}
void Assembler::RecordDebugBreakSlot() {
WriteRecordedPositions();
positions_recorder()->WriteRecordedPositions();
CheckBuffer();
RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
}
@ -2398,47 +2411,6 @@ void Assembler::RecordComment(const char* msg) {
}
void Assembler::RecordPosition(int pos) {
if (pos == RelocInfo::kNoPosition) return;
ASSERT(pos >= 0);
current_position_ = pos;
}
void Assembler::RecordStatementPosition(int pos) {
if (pos == RelocInfo::kNoPosition) return;
ASSERT(pos >= 0);
current_statement_position_ = pos;
}
bool Assembler::WriteRecordedPositions() {
bool written = false;
// Write the statement position if it is different from what was written last
// time.
if (current_statement_position_ != written_statement_position_) {
CheckBuffer();
RecordRelocInfo(RelocInfo::STATEMENT_POSITION, current_statement_position_);
written_statement_position_ = current_statement_position_;
written = true;
}
// Write the position if it is different from what was written last time and
// also different from the written statement position.
if (current_position_ != written_position_ &&
current_position_ != written_statement_position_) {
CheckBuffer();
RecordRelocInfo(RelocInfo::POSITION, current_position_);
written_position_ = current_position_;
written = true;
}
// Return whether something was written.
return written;
}
void Assembler::GrowBuffer() {
if (!own_buffer_) FATAL("external code buffer is too small");

41
deps/v8/src/arm/assembler-arm.h

@ -448,6 +448,7 @@ class Operand BASE_EMBEDDED {
// Return true of this operand fits in one instruction so that no
// 2-instruction solution with a load into the ip register is necessary.
bool is_single_instruction() const;
bool must_use_constant_pool() const;
inline int32_t immediate() const {
ASSERT(!rm_.is_valid());
@ -1007,26 +1008,37 @@ class Assembler : public Malloced {
void vmov(const Register dst,
const SwVfpRegister src,
const Condition cond = al);
enum ConversionMode {
FPSCRRounding = 0,
RoundToZero = 1
};
void vcvt_f64_s32(const DwVfpRegister dst,
const SwVfpRegister src,
ConversionMode mode = RoundToZero,
const Condition cond = al);
void vcvt_f32_s32(const SwVfpRegister dst,
const SwVfpRegister src,
ConversionMode mode = RoundToZero,
const Condition cond = al);
void vcvt_f64_u32(const DwVfpRegister dst,
const SwVfpRegister src,
ConversionMode mode = RoundToZero,
const Condition cond = al);
void vcvt_s32_f64(const SwVfpRegister dst,
const DwVfpRegister src,
ConversionMode mode = RoundToZero,
const Condition cond = al);
void vcvt_u32_f64(const SwVfpRegister dst,
const DwVfpRegister src,
ConversionMode mode = RoundToZero,
const Condition cond = al);
void vcvt_f64_f32(const DwVfpRegister dst,
const SwVfpRegister src,
ConversionMode mode = RoundToZero,
const Condition cond = al);
void vcvt_f32_f64(const SwVfpRegister dst,
const DwVfpRegister src,
ConversionMode mode = RoundToZero,
const Condition cond = al);
void vadd(const DwVfpRegister dst,
@ -1055,6 +1067,8 @@ class Assembler : public Malloced {
const Condition cond = al);
void vmrs(const Register dst,
const Condition cond = al);
void vmsr(const Register dst,
const Condition cond = al);
void vsqrt(const DwVfpRegister dst,
const DwVfpRegister src,
const Condition cond = al);
@ -1117,13 +1131,9 @@ class Assembler : public Malloced {
// Use --debug_code to enable.
void RecordComment(const char* msg);
void RecordPosition(int pos);
void RecordStatementPosition(int pos);
bool WriteRecordedPositions();
int pc_offset() const { return pc_ - buffer_; }
int current_position() const { return current_position_; }
int current_statement_position() const { return current_statement_position_; }
PositionsRecorder* positions_recorder() { return &positions_recorder_; }
bool can_peephole_optimize(int instructions) {
if (!FLAG_peephole_optimization) return false;
@ -1259,12 +1269,6 @@ class Assembler : public Malloced {
// The bound position, before this we cannot do instruction elimination.
int last_bound_pos_;
// source position information
int current_position_;
int current_statement_position_;
int written_position_;
int written_statement_position_;
// Code emission
inline void CheckBuffer();
void GrowBuffer();
@ -1290,8 +1294,21 @@ class Assembler : public Malloced {
friend class RelocInfo;
friend class CodePatcher;
friend class BlockConstPoolScope;
PositionsRecorder positions_recorder_;
friend class PositionsRecorder;
friend class EnsureSpace;
};
class EnsureSpace BASE_EMBEDDED {
public:
explicit EnsureSpace(Assembler* assembler) {
assembler->CheckBuffer();
}
};
} } // namespace v8::internal
#endif // V8_ARM_ASSEMBLER_ARM_H_

67
deps/v8/src/arm/codegen-arm.cc

@ -5496,73 +5496,6 @@ void CodeGenerator::GenerateRegExpConstructResult(ZoneList<Expression*>* args) {
}
void CodeGenerator::GenerateRegExpCloneResult(ZoneList<Expression*>* args) {
ASSERT_EQ(1, args->length());
Load(args->at(0));
frame_->PopToR0();
{
VirtualFrame::SpilledScope spilled_scope(frame_);
Label done;
Label call_runtime;
__ BranchOnSmi(r0, &done);
// Load JSRegExp map into r1. Check that argument object has this map.
// Arguments to this function should be results of calling RegExp exec,
// which is either an unmodified JSRegExpResult or null. Anything not having
// the unmodified JSRegExpResult map is returned unmodified.
// This also ensures that elements are fast.
__ ldr(r1, ContextOperand(cp, Context::GLOBAL_INDEX));
__ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalContextOffset));
__ ldr(r1, ContextOperand(r1, Context::REGEXP_RESULT_MAP_INDEX));
__ ldr(ip, FieldMemOperand(r0, HeapObject::kMapOffset));
__ cmp(r1, Operand(ip));
__ b(ne, &done);
if (FLAG_debug_code) {
__ LoadRoot(r2, Heap::kEmptyFixedArrayRootIndex);
__ ldr(ip, FieldMemOperand(r0, JSObject::kPropertiesOffset));
__ cmp(ip, r2);
__ Check(eq, "JSRegExpResult: default map but non-empty properties.");
}
// All set, copy the contents to a new object.
__ AllocateInNewSpace(JSRegExpResult::kSize,
r2,
r3,
r4,
&call_runtime,
NO_ALLOCATION_FLAGS);
// Store RegExpResult map as map of allocated object.
ASSERT(JSRegExpResult::kSize == 6 * kPointerSize);
// Copy all fields (map is already in r1) from (untagged) r0 to r2.
// Change map of elements array (ends up in r4) to be a FixedCOWArray.
__ bic(r0, r0, Operand(kHeapObjectTagMask));
__ ldm(ib, r0, r3.bit() | r4.bit() | r5.bit() | r6.bit() | r7.bit());
__ stm(ia, r2,
r1.bit() | r3.bit() | r4.bit() | r5.bit() | r6.bit() | r7.bit());
ASSERT(JSRegExp::kElementsOffset == 2 * kPointerSize);
// Check whether elements array is empty fixed array, and otherwise make
// it copy-on-write (it never should be empty unless someone is messing
// with the arguments to the runtime function).
__ LoadRoot(ip, Heap::kEmptyFixedArrayRootIndex);
__ add(r0, r2, Operand(kHeapObjectTag)); // Tag result and move it to r0.
__ cmp(r4, ip);
__ b(eq, &done);
__ LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex);
__ str(ip, FieldMemOperand(r4, HeapObject::kMapOffset));
__ b(&done);
__ bind(&call_runtime);
__ push(r0);
__ CallRuntime(Runtime::kRegExpCloneResult, 1);
__ bind(&done);
}
frame_->EmitPush(r0);
}
class DeferredSearchCache: public DeferredCode {
public:
DeferredSearchCache(Register dst, Register cache, Register key)

2
deps/v8/src/arm/codegen-arm.h

@ -518,8 +518,6 @@ class CodeGenerator: public AstVisitor {
void GenerateRegExpConstructResult(ZoneList<Expression*>* args);
void GenerateRegExpCloneResult(ZoneList<Expression*>* args);
// Support for fast native caches.
void GenerateGetFromCache(ZoneList<Expression*>* args);

7
deps/v8/src/arm/constants-arm.h

@ -206,6 +206,13 @@ enum VFPRegPrecision {
kDoublePrecision = 1
};
// VFP rounding modes. See ARM DDI 0406B Page A2-29.
enum FPSCRRoundingModes {
RN, // Round to Nearest.
RP, // Round towards Plus Infinity.
RM, // Round towards Minus Infinity.
RZ // Round towards zero.
};
typedef int32_t instr_t;

119
deps/v8/src/arm/full-codegen-arm.cc

@ -1688,12 +1688,14 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
// Code common for calls using the IC.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
}
__ mov(r2, Operand(name));
}
__ mov(r2, Operand(name));
// Record source position for debugger.
SetSourcePosition(expr->position());
SetSourcePosition(expr->position(), FORCED_POSITION);
// Call the IC initialization code.
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop);
@ -1710,13 +1712,15 @@ void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
// Code common for calls using the IC.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
}
VisitForAccumulatorValue(key);
__ mov(r2, r0);
}
VisitForAccumulatorValue(key);
__ mov(r2, r0);
// Record source position for debugger.
SetSourcePosition(expr->position());
SetSourcePosition(expr->position(), FORCED_POSITION);
// Call the IC initialization code.
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic = CodeGenerator::ComputeKeyedCallInitialize(arg_count,
@ -1732,11 +1736,13 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr) {
// Code common for calls using the call stub.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
}
}
// Record source position for debugger.
SetSourcePosition(expr->position());
SetSourcePosition(expr->position(), FORCED_POSITION);
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
__ CallStub(&stub);
@ -1756,41 +1762,45 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// resolve the function we need to call and the receiver of the
// call. Then we call the resolved function using the given
// arguments.
VisitForStackValue(fun);
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
__ push(r2); // Reserved receiver slot.
// Push the arguments.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
}
// Push copy of the function - found below the arguments.
__ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ push(r1);
{ PreserveStatementPositionScope pos_scope(masm()->positions_recorder());
VisitForStackValue(fun);
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
__ push(r2); // Reserved receiver slot.
// Push the arguments.
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
}
// Push copy of the first argument or undefined if it doesn't exist.
if (arg_count > 0) {
__ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
// Push copy of the function - found below the arguments.
__ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ push(r1);
} else {
__ push(r2);
}
// Push the receiver of the enclosing function and do runtime call.
__ ldr(r1, MemOperand(fp, (2 + scope()->num_parameters()) * kPointerSize));
__ push(r1);
__ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
// Push copy of the first argument or undefined if it doesn't exist.
if (arg_count > 0) {
__ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
__ push(r1);
} else {
__ push(r2);
}
// The runtime call returns a pair of values in r0 (function) and
// r1 (receiver). Touch up the stack with the right values.
__ str(r0, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ str(r1, MemOperand(sp, arg_count * kPointerSize));
// Push the receiver of the enclosing function and do runtime call.
__ ldr(r1,
MemOperand(fp, (2 + scope()->num_parameters()) * kPointerSize));
__ push(r1);
__ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
// The runtime call returns a pair of values in r0 (function) and
// r1 (receiver). Touch up the stack with the right values.
__ str(r0, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ str(r1, MemOperand(sp, arg_count * kPointerSize));
}
// Record source position for debugger.
SetSourcePosition(expr->position());
SetSourcePosition(expr->position(), FORCED_POSITION);
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
__ CallStub(&stub);
@ -1807,12 +1817,14 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// Call to a lookup slot (dynamically introduced variable).
Label slow, done;
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
NOT_INSIDE_TYPEOF,
&slow,
&done);
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
NOT_INSIDE_TYPEOF,
&slow,
&done);
}
__ bind(&slow);
// Call the runtime to find the function to call (returned in r0)
@ -1846,17 +1858,23 @@ void FullCodeGenerator::VisitCall(Call* expr) {
Literal* key = prop->key()->AsLiteral();
if (key != NULL && key->handle()->IsSymbol()) {
// Call to a named property, use call IC.
VisitForStackValue(prop->obj());
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
VisitForStackValue(prop->obj());
}
EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
} else {
// Call to a keyed property.
// For a synthetic property use keyed load IC followed by function call,
// for a regular property use keyed CallIC.
VisitForStackValue(prop->obj());
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
VisitForStackValue(prop->obj());
}
if (prop->is_synthetic()) {
VisitForAccumulatorValue(prop->key());
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
VisitForAccumulatorValue(prop->key());
}
// Record source code position for IC call.
SetSourcePosition(prop->position());
SetSourcePosition(prop->position(), FORCED_POSITION);
__ pop(r1); // We do not need to keep the receiver.
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
@ -1879,7 +1897,10 @@ void FullCodeGenerator::VisitCall(Call* expr) {
loop_depth() == 0) {
lit->set_try_full_codegen(true);
}
VisitForStackValue(fun);
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
VisitForStackValue(fun);
}
// Load global receiver object.
__ ldr(r1, CodeGenerator::GlobalObject());
__ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));

4
deps/v8/src/arm/ic-arm.cc

@ -1988,9 +1988,9 @@ void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,
// Not infinity or NaN simply convert to int.
if (IsElementTypeSigned(array_type)) {
__ vcvt_s32_f64(s0, d0, ne);
__ vcvt_s32_f64(s0, d0, Assembler::RoundToZero, ne);
} else {
__ vcvt_u32_f64(s0, d0, ne);
__ vcvt_u32_f64(s0, d0, Assembler::RoundToZero, ne);
}
__ vmov(r5, s0, ne);

26
deps/v8/src/arm/macro-assembler-arm.cc

@ -129,7 +129,7 @@ void MacroAssembler::Call(intptr_t target, RelocInfo::Mode rmode,
// address is loaded. The mov method will automatically record
// positions when pc is the target, since this is not the case here
// we have to do it explicitly.
WriteRecordedPositions();
positions_recorder()->WriteRecordedPositions();
mov(ip, Operand(target, rmode), LeaveCC, cond);
blx(ip, cond);
@ -220,20 +220,20 @@ void MacroAssembler::Move(Register dst, Register src) {
void MacroAssembler::And(Register dst, Register src1, const Operand& src2,
Condition cond) {
if (!CpuFeatures::IsSupported(ARMv7) || src2.is_single_instruction()) {
and_(dst, src1, src2, LeaveCC, cond);
return;
}
int32_t immediate = src2.immediate();
if (immediate == 0) {
if (!src2.is_reg() &&
!src2.must_use_constant_pool() &&
src2.immediate() == 0) {
mov(dst, Operand(0, RelocInfo::NONE), LeaveCC, cond);
return;
}
if (IsPowerOf2(immediate + 1) && ((immediate & 1) != 0)) {
ubfx(dst, src1, 0, WhichPowerOf2(immediate + 1), cond);
return;
} else if (!src2.is_single_instruction() &&
!src2.must_use_constant_pool() &&
CpuFeatures::IsSupported(ARMv7) &&
IsPowerOf2(src2.immediate() + 1)) {
ubfx(dst, src1, 0, WhichPowerOf2(src2.immediate() + 1), cond);
} else {
and_(dst, src1, src2, LeaveCC, cond);
}
and_(dst, src1, src2, LeaveCC, cond);
}

108
deps/v8/src/arm/simulator-arm.cc

@ -705,6 +705,7 @@ Simulator::Simulator() {
z_flag_FPSCR_ = false;
c_flag_FPSCR_ = false;
v_flag_FPSCR_ = false;
FPSCR_rounding_mode_ = RZ;
inv_op_vfp_flag_ = false;
div_zero_vfp_flag_ = false;
@ -2501,10 +2502,45 @@ void Simulator::DecodeTypeVFP(Instr* instr) {
(instr->VAField() == 0x7) &&
(instr->Bits(19, 16) == 0x1)) {
// vmrs
if (instr->RtField() == 0xF)
uint32_t rt = instr->RtField();
if (rt == 0xF) {
Copy_FPSCR_to_APSR();
else
UNIMPLEMENTED(); // Not used by V8.
} else {
// Emulate FPSCR from the Simulator flags.
uint32_t fpscr = (n_flag_FPSCR_ << 31) |
(z_flag_FPSCR_ << 30) |
(c_flag_FPSCR_ << 29) |
(v_flag_FPSCR_ << 28) |
(inexact_vfp_flag_ << 4) |
(underflow_vfp_flag_ << 3) |
(overflow_vfp_flag_ << 2) |
(div_zero_vfp_flag_ << 1) |
(inv_op_vfp_flag_ << 0) |
(FPSCR_rounding_mode_ << 22);
set_register(rt, fpscr);
}
} else if ((instr->VLField() == 0x0) &&
(instr->VCField() == 0x0) &&
(instr->VAField() == 0x7) &&
(instr->Bits(19, 16) == 0x1)) {
// vmsr
uint32_t rt = instr->RtField();
if (rt == pc) {
UNREACHABLE();
} else {
uint32_t rt_value = get_register(rt);
n_flag_FPSCR_ = (rt_value >> 31) & 1;
z_flag_FPSCR_ = (rt_value >> 30) & 1;
c_flag_FPSCR_ = (rt_value >> 29) & 1;
v_flag_FPSCR_ = (rt_value >> 28) & 1;
inexact_vfp_flag_ = (rt_value >> 4) & 1;
underflow_vfp_flag_ = (rt_value >> 3) & 1;
overflow_vfp_flag_ = (rt_value >> 2) & 1;
div_zero_vfp_flag_ = (rt_value >> 1) & 1;
inv_op_vfp_flag_ = (rt_value >> 0) & 1;
FPSCR_rounding_mode_ =
static_cast<FPSCRRoundingModes>((rt_value >> 22) & 3);
}
} else {
UNIMPLEMENTED(); // Not used by V8.
}
@ -2605,29 +2641,71 @@ void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr) {
if (to_integer) {
bool unsigned_integer = (instr->Bit(16) == 0);
FPSCRRoundingModes mode;
if (instr->Bit(7) != 1) {
// Only rounding towards zero supported.
UNIMPLEMENTED(); // Not used by V8.
// Use FPSCR defined rounding mode.
mode = FPSCR_rounding_mode_;
// Only RZ and RM modes are supported.
ASSERT((mode == RM) || (mode == RZ));
} else {
// VFP uses round towards zero by default.
mode = RZ;
}
int dst = instr->VFPDRegCode(kSinglePrecision);
int src = instr->VFPMRegCode(src_precision);
int32_t kMaxInt = v8::internal::kMaxInt;
int32_t kMinInt = v8::internal::kMinInt;
switch (mode) {
case RM:
if (src_precision == kDoublePrecision) {
double val = get_double_from_d_register(src);
if (src_precision == kDoublePrecision) {
double val = get_double_from_d_register(src);
inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val);
int sint = unsigned_integer ? static_cast<uint32_t>(val) :
static_cast<int32_t>(val);
int sint = unsigned_integer ? static_cast<uint32_t>(val) :
static_cast<int32_t>(val);
sint = sint > val ? sint - 1 : sint;
set_s_register_from_sinteger(dst, sint);
} else {
float val = get_float_from_s_register(src);
set_s_register_from_sinteger(dst, sint);
} else {
float val = get_float_from_s_register(src);
inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val);
int sint = unsigned_integer ? static_cast<uint32_t>(val) :
static_cast<int32_t>(val);
int sint = unsigned_integer ? static_cast<uint32_t>(val) :
static_cast<int32_t>(val);
sint = sint > val ? sint - 1 : sint;
set_s_register_from_sinteger(dst, sint);
set_s_register_from_sinteger(dst, sint);
}
break;
case RZ:
if (src_precision == kDoublePrecision) {
double val = get_double_from_d_register(src);
inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val);
int sint = unsigned_integer ? static_cast<uint32_t>(val) :
static_cast<int32_t>(val);
set_s_register_from_sinteger(dst, sint);
} else {
float val = get_float_from_s_register(src);
inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val);
int sint = unsigned_integer ? static_cast<uint32_t>(val) :
static_cast<int32_t>(val);
set_s_register_from_sinteger(dst, sint);
}
break;
default:
UNREACHABLE();
}
} else {
bool unsigned_integer = (instr->Bit(7) == 0);

3
deps/v8/src/arm/simulator-arm.h

@ -306,6 +306,9 @@ class Simulator {
bool c_flag_FPSCR_;
bool v_flag_FPSCR_;
// VFP rounding mode. See ARM DDI 0406B Page A2-29.
FPSCRRoundingModes FPSCR_rounding_mode_;
// VFP FP exception flags architecture state.
bool inv_op_vfp_flag_;
bool div_zero_vfp_flag_;

49
deps/v8/src/assembler.cc

@ -804,4 +804,53 @@ ExternalReference ExternalReference::debug_step_in_fp_address() {
}
#endif
void PositionsRecorder::RecordPosition(int pos,
PositionRecordingType recording_type) {
ASSERT(pos != RelocInfo::kNoPosition);
ASSERT(pos >= 0);
current_position_ = pos;
current_position_recording_type_ = recording_type;
}
void PositionsRecorder::RecordStatementPosition(int pos) {
ASSERT(pos != RelocInfo::kNoPosition);
ASSERT(pos >= 0);
current_statement_position_ = pos;
}
bool PositionsRecorder::WriteRecordedPositions() {
bool written = false;
// Write the statement position if it is different from what was written last
// time.
if (current_statement_position_ != written_statement_position_) {
EnsureSpace ensure_space(assembler_);
assembler_->RecordRelocInfo(RelocInfo::STATEMENT_POSITION,
current_statement_position_);
written_statement_position_ = current_statement_position_;
written = true;
}
// Write the position if it is different from what was written last time and
// also different from the written statement position or was forced.
if (current_position_ != written_position_ &&
(current_position_ != current_statement_position_ || !written) &&
(current_position_ != written_statement_position_
|| current_position_recording_type_ == FORCED_POSITION)) {
EnsureSpace ensure_space(assembler_);
assembler_->RecordRelocInfo(RelocInfo::POSITION, current_position_);
written_position_ = current_position_;
written = true;
}
current_position_recording_type_ = NORMAL_POSITION;
// Return whether something was written.
return written;
}
} } // namespace v8::internal

61
deps/v8/src/assembler.h

@ -584,6 +584,67 @@ class ExternalReference BASE_EMBEDDED {
};
// -----------------------------------------------------------------------------
// Position recording support
enum PositionRecordingType { FORCED_POSITION, NORMAL_POSITION };
class PositionsRecorder BASE_EMBEDDED {
public:
explicit PositionsRecorder(Assembler* assembler)
: assembler_(assembler),
current_position_(RelocInfo::kNoPosition),
current_position_recording_type_(NORMAL_POSITION),
written_position_(RelocInfo::kNoPosition),
current_statement_position_(RelocInfo::kNoPosition),
written_statement_position_(RelocInfo::kNoPosition) { }
// Set current position to pos. If recording_type is FORCED_POSITION then
// WriteRecordedPositions will write this position even if it is equal to
// statement position previously written for another pc.
void RecordPosition(int pos,
PositionRecordingType recording_type = NORMAL_POSITION);
// Set current statement position to pos.
void RecordStatementPosition(int pos);
// Write recorded positions to relocation information.
bool WriteRecordedPositions();
int current_position() const { return current_position_; }
int current_statement_position() const { return current_statement_position_; }
private:
Assembler* assembler_;
int current_position_;
PositionRecordingType current_position_recording_type_;
int written_position_;
int current_statement_position_;
int written_statement_position_;
};
class PreserveStatementPositionScope BASE_EMBEDDED {
public:
explicit PreserveStatementPositionScope(PositionsRecorder* positions_recorder)
: positions_recorder_(positions_recorder),
statement_position_(positions_recorder->current_statement_position()) {}
~PreserveStatementPositionScope() {
if (statement_position_ != RelocInfo::kNoPosition) {
positions_recorder_->RecordStatementPosition(statement_position_);
}
}
private:
PositionsRecorder* positions_recorder_;
int statement_position_;
};
// -----------------------------------------------------------------------------
// Utility functions

767
deps/v8/src/bignum.cc

@ -0,0 +1,767 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "v8.h"
#include "bignum.h"
#include "utils.h"
namespace v8 {
namespace internal {
Bignum::Bignum()
: bigits_(bigits_buffer_, kBigitCapacity), used_digits_(0), exponent_(0) {
for (int i = 0; i < kBigitCapacity; ++i) {
bigits_[i] = 0;
}
}
template<typename S>
static int BitSize(S value) {
return 8 * sizeof(value);
}
// Guaranteed to lie in one Bigit.
void Bignum::AssignUInt16(uint16_t value) {
ASSERT(kBigitSize >= BitSize(value));
Zero();
if (value == 0) return;
EnsureCapacity(1);
bigits_[0] = value;
used_digits_ = 1;
}
void Bignum::AssignUInt64(uint64_t value) {
const int kUInt64Size = 64;
Zero();
if (value == 0) return;
int needed_bigits = kUInt64Size / kBigitSize + 1;
EnsureCapacity(needed_bigits);
for (int i = 0; i < needed_bigits; ++i) {
bigits_[i] = value & kBigitMask;
value = value >> kBigitSize;
}
used_digits_ = needed_bigits;
Clamp();
}
void Bignum::AssignBignum(const Bignum& other) {
exponent_ = other.exponent_;
for (int i = 0; i < other.used_digits_; ++i) {
bigits_[i] = other.bigits_[i];
}
// Clear the excess digits (if there were any).
for (int i = other.used_digits_; i < used_digits_; ++i) {
bigits_[i] = 0;
}
used_digits_ = other.used_digits_;
}
static uint64_t ReadUInt64(Vector<const char> buffer,
int from,
int digits_to_read) {
uint64_t result = 0;
for (int i = from; i < from + digits_to_read; ++i) {
int digit = buffer[i] - '0';
ASSERT(0 <= digit && digit <= 9);
result = result * 10 + digit;
}
return result;
}
void Bignum::AssignDecimalString(Vector<const char> value) {
// 2^64 = 18446744073709551616 > 10^19
const int kMaxUint64DecimalDigits = 19;
Zero();
int length = value.length();
int pos = 0;
// Let's just say that each digit needs 4 bits.
while (length >= kMaxUint64DecimalDigits) {
uint64_t digits = ReadUInt64(value, pos, kMaxUint64DecimalDigits);
pos += kMaxUint64DecimalDigits;
length -= kMaxUint64DecimalDigits;
MultiplyByPowerOfTen(kMaxUint64DecimalDigits);
AddUInt64(digits);
}
uint64_t digits = ReadUInt64(value, pos, length);
MultiplyByPowerOfTen(length);
AddUInt64(digits);
Clamp();
}
static int HexCharValue(char c) {
if ('0' <= c && c <= '9') return c - '0';
if ('a' <= c && c <= 'f') return 10 + c - 'a';
if ('A' <= c && c <= 'F') return 10 + c - 'A';
UNREACHABLE();
return 0; // To make compiler happy.
}
void Bignum::AssignHexString(Vector<const char> value) {
Zero();
int length = value.length();
int needed_bigits = length * 4 / kBigitSize + 1;
EnsureCapacity(needed_bigits);
int string_index = length - 1;
for (int i = 0; i < needed_bigits - 1; ++i) {
// These bigits are guaranteed to be "full".
Chunk current_bigit = 0;
for (int j = 0; j < kBigitSize / 4; j++) {
current_bigit += HexCharValue(value[string_index--]) << (j * 4);
}
bigits_[i] = current_bigit;
}
used_digits_ = needed_bigits - 1;
Chunk most_significant_bigit = 0; // Could be = 0;
for (int j = 0; j <= string_index; ++j) {
most_significant_bigit <<= 4;
most_significant_bigit += HexCharValue(value[j]);
}
if (most_significant_bigit != 0) {
bigits_[used_digits_] = most_significant_bigit;
used_digits_++;
}
Clamp();
}
void Bignum::AddUInt64(uint64_t operand) {
if (operand == 0) return;
Bignum other;
other.AssignUInt64(operand);
AddBignum(other);
}
void Bignum::AddBignum(const Bignum& other) {
ASSERT(IsClamped());
ASSERT(other.IsClamped());
// If this has a greater exponent than other append zero-bigits to this.
// After this call exponent_ <= other.exponent_.
Align(other);
// There are two possibilities:
// aaaaaaaaaaa 0000 (where the 0s represent a's exponent)
// bbbbb 00000000
// ----------------
// ccccccccccc 0000
// or
// aaaaaaaaaa 0000
// bbbbbbbbb 0000000
// -----------------
// cccccccccccc 0000
// In both cases we might need a carry bigit.
EnsureCapacity(1 + Max(BigitLength(), other.BigitLength()) - exponent_);
Chunk carry = 0;
int bigit_pos = other.exponent_ - exponent_;
ASSERT(bigit_pos >= 0);
for (int i = 0; i < other.used_digits_; ++i) {
Chunk sum = bigits_[bigit_pos] + other.bigits_[i] + carry;
bigits_[bigit_pos] = sum & kBigitMask;
carry = sum >> kBigitSize;
bigit_pos++;
}
while (carry != 0) {
Chunk sum = bigits_[bigit_pos] + carry;
bigits_[bigit_pos] = sum & kBigitMask;
carry = sum >> kBigitSize;
bigit_pos++;
}
used_digits_ = Max(bigit_pos, used_digits_);
ASSERT(IsClamped());
}
void Bignum::SubtractBignum(const Bignum& other) {
ASSERT(IsClamped());
ASSERT(other.IsClamped());
// We require this to be bigger than other.
ASSERT(LessEqual(other, *this));
Align(other);
int offset = other.exponent_ - exponent_;
Chunk borrow = 0;
int i;
for (i = 0; i < other.used_digits_; ++i) {
ASSERT((borrow == 0) || (borrow == 1));
Chunk difference = bigits_[i + offset] - other.bigits_[i] - borrow;
bigits_[i + offset] = difference & kBigitMask;
borrow = difference >> (kChunkSize - 1);
}
while (borrow != 0) {
Chunk difference = bigits_[i + offset] - borrow;
bigits_[i + offset] = difference & kBigitMask;
borrow = difference >> (kChunkSize - 1);
++i;
}
Clamp();
}
void Bignum::ShiftLeft(int shift_amount) {
if (used_digits_ == 0) return;
exponent_ += shift_amount / kBigitSize;
int local_shift = shift_amount % kBigitSize;
EnsureCapacity(used_digits_ + 1);
BigitsShiftLeft(local_shift);
}
void Bignum::MultiplyByUInt32(uint32_t factor) {
if (factor == 1) return;
if (factor == 0) {
Zero();
return;
}
if (used_digits_ == 0) return;
// The product of a bigit with the factor is of size kBigitSize + 32.
// Assert that this number + 1 (for the carry) fits into double chunk.
ASSERT(kDoubleChunkSize >= kBigitSize + 32 + 1);
DoubleChunk carry = 0;
for (int i = 0; i < used_digits_; ++i) {
DoubleChunk product = static_cast<DoubleChunk>(factor) * bigits_[i] + carry;
bigits_[i] = static_cast<Chunk>(product & kBigitMask);
carry = (product >> kBigitSize);
}
while (carry != 0) {
EnsureCapacity(used_digits_ + 1);
bigits_[used_digits_] = carry & kBigitMask;
used_digits_++;
carry >>= kBigitSize;
}
}
void Bignum::MultiplyByUInt64(uint64_t factor) {
if (factor == 1) return;
if (factor == 0) {
Zero();
return;
}
ASSERT(kBigitSize < 32);
uint64_t carry = 0;
uint64_t low = factor & 0xFFFFFFFF;
uint64_t high = factor >> 32;
for (int i = 0; i < used_digits_; ++i) {
uint64_t product_low = low * bigits_[i];
uint64_t product_high = high * bigits_[i];
uint64_t tmp = (carry & kBigitMask) + product_low;
bigits_[i] = tmp & kBigitMask;
carry = (carry >> kBigitSize) + (tmp >> kBigitSize) +
(product_high << (32 - kBigitSize));
}
while (carry != 0) {
EnsureCapacity(used_digits_ + 1);
bigits_[used_digits_] = carry & kBigitMask;
used_digits_++;
carry >>= kBigitSize;
}
}
void Bignum::MultiplyByPowerOfTen(int exponent) {
const uint64_t kFive27 = V8_2PART_UINT64_C(0x6765c793, fa10079d);
const uint16_t kFive1 = 5;
const uint16_t kFive2 = kFive1 * 5;
const uint16_t kFive3 = kFive2 * 5;
const uint16_t kFive4 = kFive3 * 5;
const uint16_t kFive5 = kFive4 * 5;
const uint16_t kFive6 = kFive5 * 5;
const uint32_t kFive7 = kFive6 * 5;
const uint32_t kFive8 = kFive7 * 5;
const uint32_t kFive9 = kFive8 * 5;
const uint32_t kFive10 = kFive9 * 5;
const uint32_t kFive11 = kFive10 * 5;
const uint32_t kFive12 = kFive11 * 5;
const uint32_t kFive13 = kFive12 * 5;
const uint32_t kFive1_to_12[] =
{ kFive1, kFive2, kFive3, kFive4, kFive5, kFive6,
kFive7, kFive8, kFive9, kFive10, kFive11, kFive12 };
ASSERT(exponent >= 0);
if (exponent == 0) return;
if (used_digits_ == 0) return;
// We shift by exponent at the end just before returning.
int remaining_exponent = exponent;
while (remaining_exponent >= 27) {
MultiplyByUInt64(kFive27);
remaining_exponent -= 27;
}
while (remaining_exponent >= 13) {
MultiplyByUInt32(kFive13);
remaining_exponent -= 13;
}
if (remaining_exponent > 0) {
MultiplyByUInt32(kFive1_to_12[remaining_exponent - 1]);
}
ShiftLeft(exponent);
}
void Bignum::Square() {
ASSERT(IsClamped());
int product_length = 2 * used_digits_;
EnsureCapacity(product_length);
// Comba multiplication: compute each column separately.
// Example: r = a2a1a0 * b2b1b0.
// r = 1 * a0b0 +
// 10 * (a1b0 + a0b1) +
// 100 * (a2b0 + a1b1 + a0b2) +
// 1000 * (a2b1 + a1b2) +
// 10000 * a2b2
//
// In the worst case we have to accumulate nb-digits products of digit*digit.
//
// Assert that the additional number of bits in a DoubleChunk are enough to
// sum up used_digits of Bigit*Bigit.
if ((1 << (2 * (kChunkSize - kBigitSize))) <= used_digits_) {
UNIMPLEMENTED();
}
DoubleChunk accumulator = 0;
// First shift the digits so we don't overwrite them.
int copy_offset = used_digits_;
for (int i = 0; i < used_digits_; ++i) {
bigits_[copy_offset + i] = bigits_[i];
}
// We have two loops to avoid some 'if's in the loop.
for (int i = 0; i < used_digits_; ++i) {
// Process temporary digit i with power i.
// The sum of the two indices must be equal to i.
int bigit_index1 = i;
int bigit_index2 = 0;
// Sum all of the sub-products.
while (bigit_index1 >= 0) {
Chunk chunk1 = bigits_[copy_offset + bigit_index1];
Chunk chunk2 = bigits_[copy_offset + bigit_index2];
accumulator += static_cast<DoubleChunk>(chunk1) * chunk2;
bigit_index1--;
bigit_index2++;
}
bigits_[i] = static_cast<Chunk>(accumulator) & kBigitMask;
accumulator >>= kBigitSize;
}
for (int i = used_digits_; i < product_length; ++i) {
int bigit_index1 = used_digits_ - 1;
int bigit_index2 = i - bigit_index1;
// Invariant: sum of both indices is again equal to i.
// Inner loop runs 0 times on last iteration, emptying accumulator.
while (bigit_index2 < used_digits_) {
Chunk chunk1 = bigits_[copy_offset + bigit_index1];
Chunk chunk2 = bigits_[copy_offset + bigit_index2];
accumulator += static_cast<DoubleChunk>(chunk1) * chunk2;
bigit_index1--;
bigit_index2++;
}
// The overwritten bigits_[i] will never be read in further loop iterations,
// because bigit_index1 and bigit_index2 are always greater
// than i - used_digits_.
bigits_[i] = static_cast<Chunk>(accumulator) & kBigitMask;
accumulator >>= kBigitSize;
}
// Since the result was guaranteed to lie inside the number the
// accumulator must be 0 now.
ASSERT(accumulator == 0);
// Don't forget to update the used_digits and the exponent.
used_digits_ = product_length;
exponent_ *= 2;
Clamp();
}
void Bignum::AssignPowerUInt16(uint16_t base, int power_exponent) {
ASSERT(base != 0);
ASSERT(power_exponent >= 0);
if (power_exponent == 0) {
AssignUInt16(1);
return;
}
Zero();
int shifts = 0;
// We expect base to be in range 2-32, and most often to be 10.
// It does not make much sense to implement different algorithms for counting
// the bits.
while ((base & 1) == 0) {
base >>= 1;
shifts++;
}
int bit_size = 0;
int tmp_base = base;
while (tmp_base != 0) {
tmp_base >>= 1;
bit_size++;
}
int final_size = bit_size * power_exponent;
// 1 extra bigit for the shifting, and one for rounded final_size.
EnsureCapacity(final_size / kBigitSize + 2);
// Left to Right exponentiation.
int mask = 1;
while (power_exponent >= mask) mask <<= 1;
// The mask is now pointing to the bit above the most significant 1-bit of
// power_exponent.
// Get rid of first 1-bit;
mask >>= 2;
uint64_t this_value = base;
bool delayed_multipliciation = false;
const uint64_t max_32bits = 0xFFFFFFFF;
while (mask != 0 && this_value <= max_32bits) {
this_value = this_value * this_value;
// Verify that there is enough space in this_value to perform the
// multiplication. The first bit_size bits must be 0.
if ((power_exponent & mask) != 0) {
uint64_t base_bits_mask =
~((static_cast<uint64_t>(1) << (64 - bit_size)) - 1);
bool high_bits_zero = (this_value & base_bits_mask) == 0;
if (high_bits_zero) {
this_value *= base;
} else {
delayed_multipliciation = true;
}
}
mask >>= 1;
}
AssignUInt64(this_value);
if (delayed_multipliciation) {
MultiplyByUInt32(base);
}
// Now do the same thing as a bignum.
while (mask != 0) {
Square();
if ((power_exponent & mask) != 0) {
MultiplyByUInt32(base);
}
mask >>= 1;
}
// And finally add the saved shifts.
ShiftLeft(shifts * power_exponent);
}
// Precondition: this/other < 16bit.
uint16_t Bignum::DivideModuloIntBignum(const Bignum& other) {
ASSERT(IsClamped());
ASSERT(other.IsClamped());
ASSERT(other.used_digits_ > 0);
// Easy case: if we have less digits than the divisor than the result is 0.
// Note: this handles the case where this == 0, too.
if (BigitLength() < other.BigitLength()) {
return 0;
}
Align(other);
uint16_t result = 0;
// Start by removing multiples of 'other' until both numbers have the same
// number of digits.
while (BigitLength() > other.BigitLength()) {
// This naive approach is extremely inefficient if the this divided other
// might be big. This function is implemented for doubleToString where
// the result should be small (less than 10).
ASSERT(other.bigits_[other.used_digits_ - 1] >= ((1 << kBigitSize) / 16));
// Remove the multiples of the first digit.
// Example this = 23 and other equals 9. -> Remove 2 multiples.
result += bigits_[used_digits_ - 1];
SubtractTimes(other, bigits_[used_digits_ - 1]);
}
ASSERT(BigitLength() == other.BigitLength());
// Both bignums are at the same length now.
// Since other has more than 0 digits we know that the access to
// bigits_[used_digits_ - 1] is safe.
Chunk this_bigit = bigits_[used_digits_ - 1];
Chunk other_bigit = other.bigits_[other.used_digits_ - 1];
if (other.used_digits_ == 1) {
// Shortcut for easy (and common) case.
int quotient = this_bigit / other_bigit;
bigits_[used_digits_ - 1] = this_bigit - other_bigit * quotient;
result += quotient;
Clamp();
return result;
}
int division_estimate = this_bigit / (other_bigit + 1);
result += division_estimate;
SubtractTimes(other, division_estimate);
if (other_bigit * (division_estimate + 1) > this_bigit) {
// No need to even try to subtract. Even if other's remaining digits were 0
// another subtraction would be too much.
return result;
}
while (LessEqual(other, *this)) {
SubtractBignum(other);
result++;
}
return result;
}
template<typename S>
static int SizeInHexChars(S number) {
ASSERT(number > 0);
int result = 0;
while (number != 0) {
number >>= 4;
result++;
}
return result;
}
static char HexCharOfValue(int value) {
ASSERT(0 <= value && value <= 16);
if (value < 10) return value + '0';
return value - 10 + 'A';
}
bool Bignum::ToHexString(char* buffer, int buffer_size) const {
ASSERT(IsClamped());
// Each bigit must be printable as separate hex-character.
ASSERT(kBigitSize % 4 == 0);
const int kHexCharsPerBigit = kBigitSize / 4;
if (used_digits_ == 0) {
if (buffer_size < 2) return false;
buffer[0] = '0';
buffer[1] = '\0';
return true;
}
// We add 1 for the terminating '\0' character.
int needed_chars = (BigitLength() - 1) * kHexCharsPerBigit +
SizeInHexChars(bigits_[used_digits_ - 1]) + 1;
if (needed_chars > buffer_size) return false;
int string_index = needed_chars - 1;
buffer[string_index--] = '\0';
for (int i = 0; i < exponent_; ++i) {
for (int j = 0; j < kHexCharsPerBigit; ++j) {
buffer[string_index--] = '0';
}
}
for (int i = 0; i < used_digits_ - 1; ++i) {
Chunk current_bigit = bigits_[i];
for (int j = 0; j < kHexCharsPerBigit; ++j) {
buffer[string_index--] = HexCharOfValue(current_bigit & 0xF);
current_bigit >>= 4;
}
}
// And finally the last bigit.
Chunk most_significant_bigit = bigits_[used_digits_ - 1];
while (most_significant_bigit != 0) {
buffer[string_index--] = HexCharOfValue(most_significant_bigit & 0xF);
most_significant_bigit >>= 4;
}
return true;
}
Bignum::Chunk Bignum::BigitAt(int index) const {
if (index >= BigitLength()) return 0;
if (index < exponent_) return 0;
return bigits_[index - exponent_];
}
int Bignum::Compare(const Bignum& a, const Bignum& b) {
ASSERT(a.IsClamped());
ASSERT(b.IsClamped());
int bigit_length_a = a.BigitLength();
int bigit_length_b = b.BigitLength();
if (bigit_length_a < bigit_length_b) return -1;
if (bigit_length_a > bigit_length_b) return +1;
for (int i = bigit_length_a - 1; i >= Min(a.exponent_, b.exponent_); --i) {
Chunk bigit_a = a.BigitAt(i);
Chunk bigit_b = b.BigitAt(i);
if (bigit_a < bigit_b) return -1;
if (bigit_a > bigit_b) return +1;
// Otherwise they are equal up to this digit. Try the next digit.
}
return 0;
}
int Bignum::PlusCompare(const Bignum& a, const Bignum& b, const Bignum& c) {
ASSERT(a.IsClamped());
ASSERT(b.IsClamped());
ASSERT(c.IsClamped());
if (a.BigitLength() < b.BigitLength()) {
return PlusCompare(b, a, c);
}
if (a.BigitLength() + 1 < c.BigitLength()) return -1;
if (a.BigitLength() > c.BigitLength()) return +1;
// The exponent encodes 0-bigits. So if there are more 0-digits in 'a' than
// 'b' has digits, then the bigit-length of 'a'+'b' must be equal to the one
// of 'a'.
if (a.exponent_ >= b.BigitLength() && a.BigitLength() < c.BigitLength()) {
return -1;
}
Chunk borrow = 0;
// Starting at min_exponent all digits are == 0. So no need to compare them.
int min_exponent = Min(Min(a.exponent_, b.exponent_), c.exponent_);
for (int i = c.BigitLength() - 1; i >= min_exponent; --i) {
Chunk chunk_a = a.BigitAt(i);
Chunk chunk_b = b.BigitAt(i);
Chunk chunk_c = c.BigitAt(i);
Chunk sum = chunk_a + chunk_b;
if (sum > chunk_c + borrow) {
return +1;
} else {
borrow = chunk_c + borrow - sum;
if (borrow > 1) return -1;
borrow <<= kBigitSize;
}
}
if (borrow == 0) return 0;
return -1;
}
void Bignum::Clamp() {
while (used_digits_ > 0 && bigits_[used_digits_ - 1] == 0) {
used_digits_--;
}
if (used_digits_ == 0) {
// Zero.
exponent_ = 0;
}
}
bool Bignum::IsClamped() const {
return used_digits_ == 0 || bigits_[used_digits_ - 1] != 0;
}
void Bignum::Zero() {
for (int i = 0; i < used_digits_; ++i) {
bigits_[i] = 0;
}
used_digits_ = 0;
exponent_ = 0;
}
void Bignum::Align(const Bignum& other) {
if (exponent_ > other.exponent_) {
// If "X" represents a "hidden" digit (by the exponent) then we are in the
// following case (a == this, b == other):
// a: aaaaaaXXXX or a: aaaaaXXX
// b: bbbbbbX b: bbbbbbbbXX
// We replace some of the hidden digits (X) of a with 0 digits.
// a: aaaaaa000X or a: aaaaa0XX
int zero_digits = exponent_ - other.exponent_;
EnsureCapacity(used_digits_ + zero_digits);
for (int i = used_digits_ - 1; i >= 0; --i) {
bigits_[i + zero_digits] = bigits_[i];
}
for (int i = 0; i < zero_digits; ++i) {
bigits_[i] = 0;
}
used_digits_ += zero_digits;
exponent_ -= zero_digits;
ASSERT(used_digits_ >= 0);
ASSERT(exponent_ >= 0);
}
}
void Bignum::BigitsShiftLeft(int shift_amount) {
ASSERT(shift_amount < kBigitSize);
ASSERT(shift_amount >= 0);
Chunk carry = 0;
for (int i = 0; i < used_digits_; ++i) {
Chunk new_carry = bigits_[i] >> (kBigitSize - shift_amount);
bigits_[i] = ((bigits_[i] << shift_amount) + carry) & kBigitMask;
carry = new_carry;
}
if (carry != 0) {
bigits_[used_digits_] = carry;
used_digits_++;
}
}
void Bignum::SubtractTimes(const Bignum& other, int factor) {
ASSERT(exponent_ <= other.exponent_);
if (factor < 3) {
for (int i = 0; i < factor; ++i) {
SubtractBignum(other);
}
return;
}
Chunk borrow = 0;
int exponent_diff = other.exponent_ - exponent_;
for (int i = 0; i < other.used_digits_; ++i) {
DoubleChunk product = static_cast<DoubleChunk>(factor) * other.bigits_[i];
DoubleChunk remove = borrow + product;
Chunk difference = bigits_[i + exponent_diff] - (remove & kBigitMask);
bigits_[i + exponent_diff] = difference & kBigitMask;
borrow = static_cast<Chunk>((difference >> (kChunkSize - 1)) +
(remove >> kBigitSize));
}
for (int i = other.used_digits_ + exponent_diff; i < used_digits_; ++i) {
if (borrow == 0) return;
Chunk difference = bigits_[i] - borrow;
bigits_[i] = difference & kBigitMask;
borrow = difference >> (kChunkSize - 1);
++i;
}
Clamp();
}
} } // namespace v8::internal

140
deps/v8/src/bignum.h

@ -0,0 +1,140 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef V8_BIGNUM_H_
#define V8_BIGNUM_H_
namespace v8 {
namespace internal {
class Bignum {
public:
// 3584 = 128 * 28. We can represent 2^3584 > 10^1000 accurately.
// This bignum can encode much bigger numbers, since it contains an
// exponent.
static const int kMaxSignificantBits = 3584;
Bignum();
void AssignUInt16(uint16_t value);
void AssignUInt64(uint64_t value);
void AssignBignum(const Bignum& other);
void AssignDecimalString(Vector<const char> value);
void AssignHexString(Vector<const char> value);
void AssignPowerUInt16(uint16_t base, int exponent);
void AddUInt16(uint16_t operand);
void AddUInt64(uint64_t operand);
void AddBignum(const Bignum& other);
// Precondition: this >= other.
void SubtractBignum(const Bignum& other);
void Square();
void ShiftLeft(int shift_amount);
void MultiplyByUInt32(uint32_t factor);
void MultiplyByUInt64(uint64_t factor);
void MultiplyByPowerOfTen(int exponent);
void Times10() { return MultiplyByUInt32(10); }
// Pseudocode:
// int result = this / other;
// this = this % other;
// In the worst case this function is in O(this/other).
uint16_t DivideModuloIntBignum(const Bignum& other);
bool ToHexString(char* buffer, int buffer_size) const;
static int Compare(const Bignum& a, const Bignum& b);
static bool Equal(const Bignum& a, const Bignum& b) {
return Compare(a, b) == 0;
}
static bool LessEqual(const Bignum& a, const Bignum& b) {
return Compare(a, b) <= 0;
}
static bool Less(const Bignum& a, const Bignum& b) {
return Compare(a, b) < 0;
}
// Returns Compare(a + b, c);
static int PlusCompare(const Bignum& a, const Bignum& b, const Bignum& c);
// Returns a + b == c
static bool PlusEqual(const Bignum& a, const Bignum& b, const Bignum& c) {
return PlusCompare(a, b, c) == 0;
}
// Returns a + b <= c
static bool PlusLessEqual(const Bignum& a, const Bignum& b, const Bignum& c) {
return PlusCompare(a, b, c) <= 0;
}
// Returns a + b < c
static bool PlusLess(const Bignum& a, const Bignum& b, const Bignum& c) {
return PlusCompare(a, b, c) < 0;
}
private:
typedef uint32_t Chunk;
typedef uint64_t DoubleChunk;
static const int kChunkSize = sizeof(Chunk) * 8;
static const int kDoubleChunkSize = sizeof(DoubleChunk) * 8;
// With bigit size of 28 we loose some bits, but a double still fits easily
// into two chunks, and more importantly we can use the Comba multiplication.
static const int kBigitSize = 28;
static const Chunk kBigitMask = (1 << kBigitSize) - 1;
// Every instance allocates kBigitLength chunks on the stack. Bignums cannot
// grow. There are no checks if the stack-allocated space is sufficient.
static const int kBigitCapacity = kMaxSignificantBits / kBigitSize;
void EnsureCapacity(int size) {
if (size > kBigitCapacity) {
UNREACHABLE();
}
}
void Align(const Bignum& other);
void Clamp();
bool IsClamped() const;
void Zero();
// Requires this to have enough capacity (no tests done).
// Updates used_digits_ if necessary.
// by must be < kBigitSize.
void BigitsShiftLeft(int shift_amount);
// BigitLength includes the "hidden" digits encoded in the exponent.
int BigitLength() const { return used_digits_ + exponent_; }
Chunk BigitAt(int index) const;
void SubtractTimes(const Bignum& other, int factor);
Chunk bigits_buffer_[kBigitCapacity];
// A vector backed by bigits_buffer_. This way accesses to the array are
// checked for out-of-bounds errors.
Vector<Chunk> bigits_;
int used_digits_;
// The Bignum's value equals value(bigits_) * 2^(exponent_ * kBigitSize).
int exponent_;
DISALLOW_COPY_AND_ASSIGN(Bignum);
};
} } // namespace v8::internal
#endif // V8_BIGNUM_H_

9
deps/v8/src/checks.cc

@ -98,3 +98,12 @@ void API_Fatal(const char* location, const char* format, ...) {
i::OS::PrintError("\n#\n\n");
i::OS::Abort();
}
namespace v8 { namespace internal {
bool EnableSlowAsserts() { return FLAG_enable_slow_asserts; }
intptr_t HeapObjectTagMask() { return kHeapObjectTagMask; }
} } // namespace v8::internal

19
deps/v8/src/checks.h

@ -30,7 +30,7 @@
#include <string.h>
#include "flags.h"
#include "../include/v8stdint.h"
extern "C" void V8_Fatal(const char* file, int line, const char* format, ...);
void API_Fatal(const char* location, const char* format, ...);
@ -279,6 +279,12 @@ template <int> class StaticAssertionHelper { };
SEMI_STATIC_JOIN(__StaticAssertTypedef__, __LINE__)
namespace v8 { namespace internal {
bool EnableSlowAsserts();
} } // namespace v8::internal
// The ASSERT macro is equivalent to CHECK except that it only
// generates code in debug builds.
#ifdef DEBUG
@ -287,7 +293,7 @@ template <int> class StaticAssertionHelper { };
#define ASSERT_EQ(v1, v2) CHECK_EQ(v1, v2)
#define ASSERT_NE(v1, v2) CHECK_NE(v1, v2)
#define ASSERT_GE(v1, v2) CHECK_GE(v1, v2)
#define SLOW_ASSERT(condition) if (FLAG_enable_slow_asserts) CHECK(condition)
#define SLOW_ASSERT(condition) if (EnableSlowAsserts()) CHECK(condition)
#else
#define ASSERT_RESULT(expr) (expr)
#define ASSERT(condition) ((void) 0)
@ -303,11 +309,16 @@ template <int> class StaticAssertionHelper { };
// and release compilation modes behaviour.
#define STATIC_ASSERT(test) STATIC_CHECK(test)
namespace v8 { namespace internal {
intptr_t HeapObjectTagMask();
} } // namespace v8::internal
#define ASSERT_TAG_ALIGNED(address) \
ASSERT((reinterpret_cast<intptr_t>(address) & kHeapObjectTagMask) == 0)
ASSERT((reinterpret_cast<intptr_t>(address) & HeapObjectTagMask()) == 0)
#define ASSERT_SIZE_TAG_ALIGNED(size) ASSERT((size & kHeapObjectTagMask) == 0)
#define ASSERT_SIZE_TAG_ALIGNED(size) ASSERT((size & HeapObjectTagMask()) == 0)
#define ASSERT_NOT_NULL(p) ASSERT_NE(NULL, p)

28
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 "ApiEntryStub"; }
const char* GetName() { return "ApiGetterEntryStub"; }
// The accessor info associated with the function.
Handle<AccessorInfo> info_;
// The function to be called.
@ -550,6 +550,32 @@ 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() { }

32
deps/v8/src/codegen.cc

@ -70,9 +70,10 @@ void CodeGenerator::ProcessDeferred() {
DeferredCode* code = deferred_.RemoveLast();
ASSERT(masm_ == code->masm());
// Record position of deferred code stub.
masm_->RecordStatementPosition(code->statement_position());
masm_->positions_recorder()->RecordStatementPosition(
code->statement_position());
if (code->position() != RelocInfo::kNoPosition) {
masm_->RecordPosition(code->position());
masm_->positions_recorder()->RecordPosition(code->position());
}
// Generate the code.
Comment cmnt(masm_, code->comment());
@ -402,10 +403,10 @@ bool CodeGenerator::RecordPositions(MacroAssembler* masm,
int pos,
bool right_here) {
if (pos != RelocInfo::kNoPosition) {
masm->RecordStatementPosition(pos);
masm->RecordPosition(pos);
masm->positions_recorder()->RecordStatementPosition(pos);
masm->positions_recorder()->RecordPosition(pos);
if (right_here) {
return masm->WriteRecordedPositions();
return masm->positions_recorder()->WriteRecordedPositions();
}
}
return false;
@ -435,7 +436,7 @@ void CodeGenerator::CodeForDoWhileConditionPosition(DoWhileStatement* stmt) {
void CodeGenerator::CodeForSourcePosition(int pos) {
if (FLAG_debug_info && pos != RelocInfo::kNoPosition) {
masm()->RecordPosition(pos);
masm()->positions_recorder()->RecordPosition(pos);
}
}
@ -481,8 +482,8 @@ int CEntryStub::MinorKey() {
}
bool ApiGetterEntryStub::GetCustomCache(Code** code_out) {
Object* cache = info()->load_stub_cache();
// Implementation of CodeStub::GetCustomCache.
static bool GetCustomCacheHelper(Object* cache, Code** code_out) {
if (cache->IsUndefined()) {
return false;
} else {
@ -492,9 +493,24 @@ bool ApiGetterEntryStub::GetCustomCache(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

1
deps/v8/src/compiler.cc

@ -279,7 +279,6 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
// in that case too.
ScriptDataImpl* pre_data = input_pre_data;
if (pre_data == NULL
&& FLAG_lazy
&& source_length >= FLAG_min_preparse_length) {
pre_data = ParserApi::PartialPreParse(source, NULL, extension);
}

6
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 = 20;
const int kMaxDigitsBeforePoint = 21;
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 '.' and the '\0' byte.
// Add space for the '\0' byte.
const int kDecimalRepCapacity =
kMaxDigitsBeforePoint + kMaxDigitsAfterPoint + 2;
kMaxDigitsBeforePoint + kMaxDigitsAfterPoint + 1;
char decimal_rep[kDecimalRepCapacity];
int decimal_rep_length;
bool status = DoubleToAscii(value, DTOA_FIXED, f,

32
deps/v8/src/debug-debugger.js

@ -897,10 +897,6 @@ ExecutionState.prototype.frame = function(opt_index) {
return new FrameMirror(this.break_id, opt_index);
};
ExecutionState.prototype.cframesValue = function(opt_from_index, opt_to_index) {
return %GetCFrames(this.break_id);
};
ExecutionState.prototype.setSelectedFrame = function(index) {
var i = %ToNumber(index);
if (i < 0 || i >= this.frameCount()) throw new Error('Illegal frame index.');
@ -1751,11 +1747,6 @@ DebugCommandProcessor.prototype.backtraceRequest_ = function(request, response)
};
DebugCommandProcessor.prototype.backtracec = function(cmd, args) {
return this.exec_state_.cframesValue();
};
DebugCommandProcessor.prototype.frameRequest_ = function(request, response) {
// No frames no source.
if (this.exec_state_.frameCount() == 0) {
@ -2205,29 +2196,6 @@ function NumberToHex8Str(n) {
return r;
};
DebugCommandProcessor.prototype.formatCFrames = function(cframes_value) {
var result = "";
if (cframes_value == null || cframes_value.length == 0) {
result += "(stack empty)";
} else {
for (var i = 0; i < cframes_value.length; ++i) {
if (i != 0) result += "\n";
result += this.formatCFrame(cframes_value[i]);
}
}
return result;
};
DebugCommandProcessor.prototype.formatCFrame = function(cframe_value) {
var result = "";
result += "0x" + NumberToHex8Str(cframe_value.address);
if (!IS_UNDEFINED(cframe_value.text)) {
result += " " + cframe_value.text;
}
return result;
}
/**
* Convert an Object to its debugger protocol representation. The representation

1
deps/v8/src/debug.cc

@ -1839,6 +1839,7 @@ bool Debug::IsDebugGlobal(GlobalObject* global) {
void Debug::ClearMirrorCache() {
PostponeInterruptsScope postpone;
HandleScope scope;
ASSERT(Top::context() == *Debug::debug_context());

32
deps/v8/src/double.h

@ -54,18 +54,20 @@ class Double {
explicit Double(DiyFp diy_fp)
: d64_(DiyFpToUint64(diy_fp)) {}
// The value encoded by this Double must be greater or equal to +0.0.
// It must not be special (infinity, or NaN).
DiyFp AsDiyFp() const {
ASSERT(Sign() > 0);
ASSERT(!IsSpecial());
return DiyFp(Significand(), Exponent());
}
// this->Significand() must not be 0.
// The value encoded by this Double must be strictly greater than 0.
DiyFp AsNormalizedDiyFp() const {
ASSERT(value() > 0.0);
uint64_t f = Significand();
int e = Exponent();
ASSERT(f != 0);
// The current double could be a denormal.
while ((f & kHiddenBit) == 0) {
f <<= 1;
@ -82,6 +84,20 @@ class Double {
return d64_;
}
// Returns the next greater double. Returns +infinity on input +infinity.
double NextDouble() const {
if (d64_ == kInfinity) return Double(kInfinity).value();
if (Sign() < 0 && Significand() == 0) {
// -0.0
return 0.0;
}
if (Sign() < 0) {
return Double(d64_ - 1).value();
} else {
return Double(d64_ + 1).value();
}
}
int Exponent() const {
if (IsDenormal()) return kDenormalExponent;
@ -120,24 +136,30 @@ class Double {
((d64 & kSignificandMask) != 0);
}
bool IsInfinite() const {
uint64_t d64 = AsUint64();
return ((d64 & kExponentMask) == kExponentMask) &&
((d64 & kSignificandMask) == 0);
}
int Sign() const {
uint64_t d64 = AsUint64();
return (d64 & kSignMask) == 0? 1: -1;
}
// Precondition: the value encoded by this Double must be greater or equal
// than +0.0.
DiyFp UpperBoundary() const {
ASSERT(Sign() > 0);
return DiyFp(Significand() * 2 + 1, Exponent() - 1);
}
// Returns the two boundaries of this.
// The bigger boundary (m_plus) is normalized. The lower boundary has the same
// exponent as m_plus.
// Precondition: the value encoded by this Double must be greater than 0.
void NormalizedBoundaries(DiyFp* out_m_minus, DiyFp* out_m_plus) const {
ASSERT(value() > 0.0);
DiyFp v = this->AsDiyFp();
bool significand_is_zero = (v.f() == kHiddenBit);
DiyFp m_plus = DiyFp::Normalize(DiyFp((v.f() << 1) + 1, v.e() - 1));

1
deps/v8/src/flag-definitions.h

@ -186,6 +186,7 @@ DEFINE_bool(always_inline_smi_code, false,
// heap.cc
DEFINE_int(max_new_space_size, 0, "max size of the new generation (in kBytes)")
DEFINE_int(max_old_space_size, 0, "max size of the old generation (in Mbytes)")
DEFINE_int(max_executable_size, 0, "max size of executable memory (in Mbytes)")
DEFINE_bool(gc_global, false, "always perform global GCs")
DEFINE_int(gc_interval, -1, "garbage collect after <n> allocations")
DEFINE_bool(trace_gc, false,

12
deps/v8/src/full-codegen.cc

@ -563,9 +563,10 @@ void FullCodeGenerator::SetStatementPosition(int pos) {
}
void FullCodeGenerator::SetSourcePosition(int pos) {
void FullCodeGenerator::SetSourcePosition(
int pos, PositionRecordingType recording_type) {
if (FLAG_debug_info && pos != RelocInfo::kNoPosition) {
masm_->RecordPosition(pos);
masm_->positions_recorder()->RecordPosition(pos, recording_type);
}
}
@ -1225,13 +1226,6 @@ int FullCodeGenerator::TryCatch::Exit(int stack_depth) {
}
void FullCodeGenerator::EmitRegExpCloneResult(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
VisitForStackValue(args->at(0));
__ CallRuntime(Runtime::kRegExpCloneResult, 1);
context()->Plug(result_register());
}
#undef __

4
deps/v8/src/full-codegen.h

@ -423,7 +423,9 @@ class FullCodeGenerator: public AstVisitor {
void SetStatementPosition(Statement* stmt);
void SetExpressionPosition(Expression* expr, int pos);
void SetStatementPosition(int pos);
void SetSourcePosition(int pos);
void SetSourcePosition(
int pos,
PositionRecordingType recording_type = NORMAL_POSITION);
// Non-local control flow support.
void EnterFinallyBlock();

6
deps/v8/src/global-handles.cc

@ -372,13 +372,14 @@ void GlobalHandles::IdentifyWeakHandles(WeakSlotCallback f) {
int post_gc_processing_count = 0;
void GlobalHandles::PostGarbageCollectionProcessing() {
bool GlobalHandles::PostGarbageCollectionProcessing() {
// Process weak global handle callbacks. This must be done after the
// GC is completely done, because the callbacks may invoke arbitrary
// API functions.
// At the same time deallocate all DESTROYED nodes.
ASSERT(Heap::gc_state() == Heap::NOT_IN_GC);
const int initial_post_gc_processing_count = ++post_gc_processing_count;
bool next_gc_likely_to_collect_more = false;
Node** p = &head_;
while (*p != NULL) {
if ((*p)->PostGarbageCollectionProcessing()) {
@ -399,6 +400,7 @@ void GlobalHandles::PostGarbageCollectionProcessing() {
}
node->set_next_free(first_deallocated());
set_first_deallocated(node);
next_gc_likely_to_collect_more = true;
} else {
p = (*p)->next_addr();
}
@ -407,6 +409,8 @@ void GlobalHandles::PostGarbageCollectionProcessing() {
if (first_deallocated()) {
first_deallocated()->set_next(head());
}
return next_gc_likely_to_collect_more;
}

3
deps/v8/src/global-handles.h

@ -96,7 +96,8 @@ class GlobalHandles : public AllStatic {
static bool IsWeak(Object** location);
// Process pending weak handles.
static void PostGarbageCollectionProcessing();
// Returns true if next major GC is likely to collect more garbage.
static bool PostGarbageCollectionProcessing();
// Iterates over all strong handles.
static void IterateStrongRoots(ObjectVisitor* v);

3
deps/v8/src/globals.h

@ -193,10 +193,9 @@ 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;

7
deps/v8/src/heap-inl.h

@ -330,6 +330,11 @@ void Heap::ScavengeObject(HeapObject** p, HeapObject* object) {
}
bool Heap::CollectGarbage(AllocationSpace space) {
return CollectGarbage(space, SelectGarbageCollector(space));
}
MaybeObject* Heap::PrepareForCompare(String* str) {
// Always flatten small strings and force flattening of long strings
// after we have accumulated a certain amount we failed to flatten.
@ -413,7 +418,7 @@ void Heap::SetLastScriptId(Object* last_script_id) {
} \
if (!__maybe_object__->IsRetryAfterGC()) RETURN_EMPTY; \
Counters::gc_last_resort_from_handles.Increment(); \
Heap::CollectAllGarbage(false); \
Heap::CollectAllAvailableGarbage(); \
{ \
AlwaysAllocateScope __scope__; \
__maybe_object__ = FUNCTION_CALL; \

72
deps/v8/src/heap.cc

@ -83,16 +83,19 @@ 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
@ -172,6 +175,12 @@ intptr_t Heap::CommittedMemory() {
lo_space_->Size();
}
intptr_t Heap::CommittedMemoryExecutable() {
if (!HasBeenSetup()) return 0;
return MemoryAllocator::SizeExecutable();
}
intptr_t Heap::Available() {
if (!HasBeenSetup()) return 0;
@ -429,7 +438,31 @@ void Heap::CollectAllGarbage(bool force_compaction) {
}
void Heap::CollectGarbage(AllocationSpace space) {
void Heap::CollectAllAvailableGarbage() {
// Since we are ignoring the return value, the exact choice of space does
// not matter, so long as we do not specify NEW_SPACE, which would not
// cause a full GC.
MarkCompactCollector::SetForceCompaction(true);
// Major GC would invoke weak handle callbacks on weakly reachable
// handles, but won't collect weakly reachable objects until next
// major GC. Therefore if we collect aggressively and weak handle callback
// has been invoked, we rerun major GC to release objects which become
// garbage.
// Note: as weak callbacks can execute arbitrary code, we cannot
// hope that eventually there will be no weak callbacks invocations.
// Therefore stop recollecting after several attempts.
const int kMaxNumberOfAttempts = 7;
for (int attempt = 0; attempt < kMaxNumberOfAttempts; attempt++) {
if (!CollectGarbage(OLD_POINTER_SPACE, MARK_COMPACTOR)) {
break;
}
}
MarkCompactCollector::SetForceCompaction(false);
}
bool Heap::CollectGarbage(AllocationSpace space, GarbageCollector collector) {
// The VM is in the GC state until exiting this function.
VMState state(GC);
@ -442,13 +475,14 @@ void Heap::CollectGarbage(AllocationSpace space) {
allocation_timeout_ = Max(6, FLAG_gc_interval);
#endif
bool next_gc_likely_to_collect_more = false;
{ GCTracer tracer;
GarbageCollectionPrologue();
// The GC count was incremented in the prologue. Tell the tracer about
// it.
tracer.set_gc_count(gc_count_);
GarbageCollector collector = SelectGarbageCollector(space);
// Tell the tracer which collector we've selected.
tracer.set_collector(collector);
@ -456,7 +490,8 @@ void Heap::CollectGarbage(AllocationSpace space) {
? &Counters::gc_scavenger
: &Counters::gc_compactor;
rate->Start();
PerformGarbageCollection(collector, &tracer);
next_gc_likely_to_collect_more =
PerformGarbageCollection(collector, &tracer);
rate->Stop();
GarbageCollectionEpilogue();
@ -467,6 +502,8 @@ void Heap::CollectGarbage(AllocationSpace space) {
if (FLAG_log_gc) HeapProfiler::WriteSample();
if (CpuProfiler::is_profiling()) CpuProfiler::ProcessMovedFunctions();
#endif
return next_gc_likely_to_collect_more;
}
@ -653,8 +690,10 @@ void Heap::UpdateSurvivalRateTrend(int start_new_space_size) {
survival_rate_ = survival_rate;
}
void Heap::PerformGarbageCollection(GarbageCollector collector,
bool Heap::PerformGarbageCollection(GarbageCollector collector,
GCTracer* tracer) {
bool next_gc_likely_to_collect_more = false;
if (collector != SCAVENGER) {
PROFILE(CodeMovingGCEvent());
}
@ -720,7 +759,8 @@ void Heap::PerformGarbageCollection(GarbageCollector collector,
if (collector == MARK_COMPACTOR) {
DisableAssertNoAllocation allow_allocation;
GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
GlobalHandles::PostGarbageCollectionProcessing();
next_gc_likely_to_collect_more =
GlobalHandles::PostGarbageCollectionProcessing();
}
// Update relocatables.
@ -747,6 +787,8 @@ void Heap::PerformGarbageCollection(GarbageCollector collector,
global_gc_epilogue_callback_();
}
VerifySymbolTable();
return next_gc_likely_to_collect_more;
}
@ -4280,7 +4322,9 @@ static bool heap_configured = false;
// TODO(1236194): Since the heap size is configurable on the command line
// and through the API, we should gracefully handle the case that the heap
// size is not big enough to fit all the initial objects.
bool Heap::ConfigureHeap(int max_semispace_size, int max_old_gen_size) {
bool Heap::ConfigureHeap(int max_semispace_size,
int max_old_gen_size,
int max_executable_size) {
if (HasBeenSetup()) return false;
if (max_semispace_size > 0) max_semispace_size_ = max_semispace_size;
@ -4301,6 +4345,15 @@ bool Heap::ConfigureHeap(int max_semispace_size, int max_old_gen_size) {
}
if (max_old_gen_size > 0) max_old_generation_size_ = max_old_gen_size;
if (max_executable_size > 0) {
max_executable_size_ = RoundUp(max_executable_size, Page::kPageSize);
}
// The max executable size must be less than or equal to the max old
// generation size.
if (max_executable_size_ > max_old_generation_size_) {
max_executable_size_ = max_old_generation_size_;
}
// The new space size must be a power of two to support single-bit testing
// for containment.
@ -4318,8 +4371,9 @@ bool Heap::ConfigureHeap(int max_semispace_size, int max_old_gen_size) {
bool Heap::ConfigureHeapDefault() {
return ConfigureHeap(
FLAG_max_new_space_size * (KB / 2), FLAG_max_old_space_size * MB);
return ConfigureHeap(FLAG_max_new_space_size / 2 * KB,
FLAG_max_old_space_size * MB,
FLAG_max_executable_size * MB);
}
@ -4402,7 +4456,7 @@ bool Heap::Setup(bool create_heap_objects) {
// space. The chunk is double the size of the requested reserved
// new space size to ensure that we can find a pair of semispaces that
// are contiguous and aligned to their size.
if (!MemoryAllocator::Setup(MaxReserved())) return false;
if (!MemoryAllocator::Setup(MaxReserved(), MaxExecutableSize())) return false;
void* chunk =
MemoryAllocator::ReserveInitialChunk(4 * reserved_semispace_size_);
if (chunk == NULL) return false;

26
deps/v8/src/heap.h

@ -222,7 +222,9 @@ class Heap : public AllStatic {
public:
// Configure heap size before setup. Return false if the heap has been
// setup already.
static bool ConfigureHeap(int max_semispace_size, int max_old_gen_size);
static bool ConfigureHeap(int max_semispace_size,
int max_old_gen_size,
int max_executable_size);
static bool ConfigureHeapDefault();
// Initializes the global object heap. If create_heap_objects is true,
@ -253,6 +255,7 @@ class Heap : public AllStatic {
static int ReservedSemiSpaceSize() { return reserved_semispace_size_; }
static int InitialSemiSpaceSize() { return initial_semispace_size_; }
static intptr_t MaxOldGenerationSize() { return max_old_generation_size_; }
static intptr_t MaxExecutableSize() { return max_executable_size_; }
// Returns the capacity of the heap in bytes w/o growing. Heap grows when
// more spaces are needed until it reaches the limit.
@ -261,6 +264,9 @@ class Heap : public AllStatic {
// Returns the amount of memory currently committed for the heap.
static intptr_t CommittedMemory();
// Returns the amount of executable memory currently committed for the heap.
static intptr_t CommittedMemoryExecutable();
// Returns the available bytes in space w/o growing.
// Heap doesn't guarantee that it can allocate an object that requires
// all available bytes. Check MaxHeapObjectSize() instead.
@ -705,13 +711,22 @@ class Heap : public AllStatic {
static void GarbageCollectionEpilogue();
// Performs garbage collection operation.
// Returns whether required_space bytes are available after the collection.
static void CollectGarbage(AllocationSpace space);
// Returns whether there is a chance that another major GC could
// collect more garbage.
static bool CollectGarbage(AllocationSpace space, GarbageCollector collector);
// Performs garbage collection operation.
// Returns whether there is a chance that another major GC could
// collect more garbage.
inline static bool CollectGarbage(AllocationSpace space);
// Performs a full garbage collection. Force compaction if the
// parameter is true.
static void CollectAllGarbage(bool force_compaction);
// Last hope GC, should try to squeeze as much as possible.
static void CollectAllAvailableGarbage();
// Notify the heap that a context has been disposed.
static int NotifyContextDisposed() { return ++contexts_disposed_; }
@ -1087,6 +1102,7 @@ class Heap : public AllStatic {
static int max_semispace_size_;
static int initial_semispace_size_;
static intptr_t max_old_generation_size_;
static intptr_t max_executable_size_;
static intptr_t code_range_size_;
// For keeping track of how much data has survived
@ -1246,7 +1262,9 @@ class Heap : public AllStatic {
static GarbageCollector SelectGarbageCollector(AllocationSpace space);
// Performs garbage collection
static void PerformGarbageCollection(GarbageCollector collector,
// Returns whether there is a chance another major GC could
// collect more garbage.
static bool PerformGarbageCollection(GarbageCollector collector,
GCTracer* tracer);
// Allocate an uninitialized object in map space. The behavior is identical

54
deps/v8/src/ia32/assembler-ia32.cc

@ -298,7 +298,8 @@ static void InitCoverageLog();
// Spare buffer.
byte* Assembler::spare_buffer_ = NULL;
Assembler::Assembler(void* buffer, int buffer_size) {
Assembler::Assembler(void* buffer, int buffer_size)
: positions_recorder_(this) {
if (buffer == NULL) {
// Do our own buffer management.
if (buffer_size <= kMinimalBufferSize) {
@ -339,10 +340,6 @@ Assembler::Assembler(void* buffer, int buffer_size) {
reloc_info_writer.Reposition(buffer_ + buffer_size, pc_);
last_pc_ = NULL;
current_statement_position_ = RelocInfo::kNoPosition;
current_position_ = RelocInfo::kNoPosition;
written_statement_position_ = current_statement_position_;
written_position_ = current_position_;
#ifdef GENERATED_CODE_COVERAGE
InitCoverageLog();
#endif
@ -1581,7 +1578,7 @@ void Assembler::call(const Operand& adr) {
void Assembler::call(Handle<Code> code, RelocInfo::Mode rmode) {
WriteRecordedPositions();
positions_recorder()->WriteRecordedPositions();
EnsureSpace ensure_space(this);
last_pc_ = pc_;
ASSERT(RelocInfo::IsCodeTarget(rmode));
@ -2464,14 +2461,14 @@ void Assembler::Print() {
void Assembler::RecordJSReturn() {
WriteRecordedPositions();
positions_recorder()->WriteRecordedPositions();
EnsureSpace ensure_space(this);
RecordRelocInfo(RelocInfo::JS_RETURN);
}
void Assembler::RecordDebugBreakSlot() {
WriteRecordedPositions();
positions_recorder()->WriteRecordedPositions();
EnsureSpace ensure_space(this);
RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
}
@ -2485,47 +2482,6 @@ void Assembler::RecordComment(const char* msg) {
}
void Assembler::RecordPosition(int pos) {
ASSERT(pos != RelocInfo::kNoPosition);
ASSERT(pos >= 0);
current_position_ = pos;
}
void Assembler::RecordStatementPosition(int pos) {
ASSERT(pos != RelocInfo::kNoPosition);
ASSERT(pos >= 0);
current_statement_position_ = pos;
}
bool Assembler::WriteRecordedPositions() {
bool written = false;
// Write the statement position if it is different from what was written last
// time.
if (current_statement_position_ != written_statement_position_) {
EnsureSpace ensure_space(this);
RecordRelocInfo(RelocInfo::STATEMENT_POSITION, current_statement_position_);
written_statement_position_ = current_statement_position_;
written = true;
}
// Write the position if it is different from what was written last time and
// also different from the written statement position.
if (current_position_ != written_position_ &&
current_position_ != written_statement_position_) {
EnsureSpace ensure_space(this);
RecordRelocInfo(RelocInfo::POSITION, current_position_);
written_position_ = current_position_;
written = true;
}
// Return whether something was written.
return written;
}
void Assembler::GrowBuffer() {
ASSERT(overflow());
if (!own_buffer_) FATAL("external code buffer is too small");

17
deps/v8/src/ia32/assembler-ia32.h

@ -521,7 +521,6 @@ class Assembler : public Malloced {
void push(const Immediate& x);
void push(Register src);
void push(const Operand& src);
void push(Label* label, RelocInfo::Mode relocation_mode);
void pop(Register dst);
void pop(const Operand& dst);
@ -847,17 +846,11 @@ class Assembler : public Malloced {
// Use --debug_code to enable.
void RecordComment(const char* msg);
void RecordPosition(int pos);
void RecordStatementPosition(int pos);
bool WriteRecordedPositions();
// Writes a single word of data in the code stream.
// Used for inline tables, e.g., jump-tables.
void dd(uint32_t data, RelocInfo::Mode reloc_info);
int pc_offset() const { return pc_ - buffer_; }
int current_statement_position() const { return current_statement_position_; }
int current_position() const { return current_position_; }
// Check if there is less than kGap bytes available in the buffer.
// If this is the case, we need to grow the buffer before emitting
@ -869,6 +862,8 @@ class Assembler : public Malloced {
static bool IsNop(Address addr) { return *addr == 0x90; }
PositionsRecorder* positions_recorder() { return &positions_recorder_; }
// Avoid overflows for displacements etc.
static const int kMaximalBufferSize = 512*MB;
static const int kMinimalBufferSize = 4*KB;
@ -947,11 +942,9 @@ class Assembler : public Malloced {
// push-pop elimination
byte* last_pc_;
// source position information
int current_statement_position_;
int current_position_;
int written_statement_position_;
int written_position_;
PositionsRecorder positions_recorder_;
friend class PositionsRecorder;
};

20
deps/v8/src/ia32/code-stubs-ia32.cc

@ -3067,6 +3067,26 @@ 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,

90
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()->WriteRecordedPositions();
masm()->positions_recorder()->WriteRecordedPositions();
if (function_return_is_shadowed_) {
function_return_.Jump(&return_value);
} else {
@ -7292,88 +7292,6 @@ void CodeGenerator::GenerateRegExpConstructResult(ZoneList<Expression*>* args) {
}
void CodeGenerator::GenerateRegExpCloneResult(ZoneList<Expression*>* args) {
ASSERT_EQ(1, args->length());
Load(args->at(0));
Result object_result = frame_->Pop();
object_result.ToRegister(eax);
object_result.Unuse();
{
VirtualFrame::SpilledScope spilled_scope;
Label done;
__ test(eax, Immediate(kSmiTagMask));
__ j(zero, &done);
// Load JSRegExpResult map into edx.
// Arguments to this function should be results of calling RegExp exec,
// which is either an unmodified JSRegExpResult or null. Anything not having
// the unmodified JSRegExpResult map is returned unmodified.
// This also ensures that elements are fast.
__ mov(edx, ContextOperand(esi, Context::GLOBAL_INDEX));
__ mov(edx, FieldOperand(edx, GlobalObject::kGlobalContextOffset));
__ mov(edx, ContextOperand(edx, Context::REGEXP_RESULT_MAP_INDEX));
__ cmp(edx, FieldOperand(eax, HeapObject::kMapOffset));
__ j(not_equal, &done);
if (FLAG_debug_code) {
// Check that object really has empty properties array, as the map
// should guarantee.
__ cmp(FieldOperand(eax, JSObject::kPropertiesOffset),
Immediate(Factory::empty_fixed_array()));
__ Check(equal, "JSRegExpResult: default map but non-empty properties.");
}
DeferredAllocateInNewSpace* allocate_fallback =
new DeferredAllocateInNewSpace(JSRegExpResult::kSize,
ebx,
edx.bit() | eax.bit());
// All set, copy the contents to a new object.
__ AllocateInNewSpace(JSRegExpResult::kSize,
ebx,
ecx,
no_reg,
allocate_fallback->entry_label(),
TAG_OBJECT);
__ bind(allocate_fallback->exit_label());
// Copy all fields from eax to ebx.
STATIC_ASSERT(JSRegExpResult::kSize % (2 * kPointerSize) == 0);
// There is an even number of fields, so unroll the loop once
// for efficiency.
for (int i = 0; i < JSRegExpResult::kSize; i += 2 * kPointerSize) {
STATIC_ASSERT(JSObject::kMapOffset % (2 * kPointerSize) == 0);
if (i != JSObject::kMapOffset) {
// The map was already loaded into edx.
__ mov(edx, FieldOperand(eax, i));
}
__ mov(ecx, FieldOperand(eax, i + kPointerSize));
STATIC_ASSERT(JSObject::kElementsOffset % (2 * kPointerSize) == 0);
if (i == JSObject::kElementsOffset) {
// If the elements array isn't empty, make it copy-on-write
// before copying it.
Label empty;
__ cmp(Operand(edx), Immediate(Factory::empty_fixed_array()));
__ j(equal, &empty);
__ mov(FieldOperand(edx, HeapObject::kMapOffset),
Immediate(Factory::fixed_cow_array_map()));
__ bind(&empty);
}
__ mov(FieldOperand(ebx, i), edx);
__ mov(FieldOperand(ebx, i + kPointerSize), ecx);
}
__ mov(eax, ebx);
__ bind(&done);
}
frame_->Push(eax);
}
class DeferredSearchCache: public DeferredCode {
public:
DeferredSearchCache(Register dst, Register cache, Register key)
@ -8660,9 +8578,11 @@ void CodeGenerator::Int32BinaryOperation(BinaryOperation* node) {
}
right.Unuse();
frame_->Push(&left);
if (!node->to_int32()) {
// If ToInt32 is called on the result of ADD, SUB, or MUL, we don't
if (!node->to_int32() || op == Token::MUL) {
// If ToInt32 is called on the result of ADD, SUB, we don't
// care about overflows.
// Result of MUL can be non-representable precisely in double so
// we have to check for overflow.
unsafe_bailout_->Branch(overflow);
}
break;

5
deps/v8/src/ia32/codegen-ia32.h

@ -697,11 +697,6 @@ class CodeGenerator: public AstVisitor {
// Construct a RegExp exec result with two in-object properties.
void GenerateRegExpConstructResult(ZoneList<Expression*>* args);
// Clone the result of a regexp function.
// Must be an object created by GenerateRegExpConstructResult with
// no extra properties.
void GenerateRegExpCloneResult(ZoneList<Expression*>* args);
// Support for fast native caches.
void GenerateGetFromCache(ZoneList<Expression*>* args);

106
deps/v8/src/ia32/full-codegen-ia32.cc

@ -1996,12 +1996,14 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
// Code common for calls using the IC.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
}
__ Set(ecx, Immediate(name));
}
__ Set(ecx, Immediate(name));
// Record source position of the IC call.
SetSourcePosition(expr->position());
SetSourcePosition(expr->position(), FORCED_POSITION);
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop);
EmitCallIC(ic, mode);
@ -2017,13 +2019,15 @@ void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
// Code common for calls using the IC.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
}
VisitForAccumulatorValue(key);
__ mov(ecx, eax);
}
VisitForAccumulatorValue(key);
__ mov(ecx, eax);
// Record source position of the IC call.
SetSourcePosition(expr->position());
SetSourcePosition(expr->position(), FORCED_POSITION);
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic = CodeGenerator::ComputeKeyedCallInitialize(
arg_count, in_loop);
@ -2038,11 +2042,13 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr) {
// Code common for calls using the call stub.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
}
}
// Record source position for debugger.
SetSourcePosition(expr->position());
SetSourcePosition(expr->position(), FORCED_POSITION);
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
__ CallStub(&stub);
@ -2062,37 +2068,39 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// resolve the function we need to call and the receiver of the
// call. Then we call the resolved function using the given
// arguments.
VisitForStackValue(fun);
__ push(Immediate(Factory::undefined_value())); // Reserved receiver slot.
// Push the arguments.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
}
{ PreserveStatementPositionScope pos_scope(masm()->positions_recorder());
VisitForStackValue(fun);
// Reserved receiver slot.
__ push(Immediate(Factory::undefined_value()));
// Push copy of the function - found below the arguments.
__ push(Operand(esp, (arg_count + 1) * kPointerSize));
// Push the arguments.
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
}
// Push copy of the first argument or undefined if it doesn't exist.
if (arg_count > 0) {
__ push(Operand(esp, arg_count * kPointerSize));
} else {
__ push(Immediate(Factory::undefined_value()));
}
// Push copy of the function - found below the arguments.
__ push(Operand(esp, (arg_count + 1) * kPointerSize));
// Push the receiver of the enclosing function and do runtime call.
__ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize));
__ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
// Push copy of the first argument or undefined if it doesn't exist.
if (arg_count > 0) {
__ push(Operand(esp, arg_count * kPointerSize));
} else {
__ push(Immediate(Factory::undefined_value()));
}
// The runtime call returns a pair of values in eax (function) and
// edx (receiver). Touch up the stack with the right values.
__ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
__ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
// Push the receiver of the enclosing function and do runtime call.
__ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize));
__ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
// The runtime call returns a pair of values in eax (function) and
// edx (receiver). Touch up the stack with the right values.
__ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
__ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
}
// Record source position for debugger.
SetSourcePosition(expr->position());
SetSourcePosition(expr->position(), FORCED_POSITION);
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
__ CallStub(&stub);
@ -2108,12 +2116,14 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// Call to a lookup slot (dynamically introduced variable).
Label slow, done;
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
NOT_INSIDE_TYPEOF,
&slow,
&done);
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
NOT_INSIDE_TYPEOF,
&slow,
&done);
}
__ bind(&slow);
// Call the runtime to find the function to call (returned in eax)
@ -2152,11 +2162,15 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// Call to a keyed property.
// For a synthetic property use keyed load IC followed by function call,
// for a regular property use keyed EmitCallIC.
VisitForStackValue(prop->obj());
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
VisitForStackValue(prop->obj());
}
if (prop->is_synthetic()) {
VisitForAccumulatorValue(prop->key());
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
VisitForAccumulatorValue(prop->key());
}
// Record source code position for IC call.
SetSourcePosition(prop->position());
SetSourcePosition(prop->position(), FORCED_POSITION);
__ pop(edx); // We do not need to keep the receiver.
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
@ -2181,7 +2195,9 @@ void FullCodeGenerator::VisitCall(Call* expr) {
loop_depth() == 0) {
lit->set_try_full_codegen(true);
}
VisitForStackValue(fun);
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
VisitForStackValue(fun);
}
// Load global receiver object.
__ mov(ebx, CodeGenerator::GlobalObject());
__ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));

1
deps/v8/src/ia32/ic-ia32.cc

@ -33,7 +33,6 @@
#include "ic-inl.h"
#include "runtime.h"
#include "stub-cache.h"
#include "utils.h"
namespace v8 {
namespace internal {

2
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);
// Tail call an API function (jump). Allocates HandleScope, extracts
// Calls an API function. Allocates HandleScope, extracts
// returned value from handle and propagates exceptions.
// Clobbers ebx, esi, edi and caller-save registers.
void CallApiFunctionAndReturn(ApiFunction* function, int argc);

178
deps/v8/src/ia32/stub-cache-ia32.cc

@ -413,6 +413,10 @@ static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
}
// Number of pointers to be reserved on stack for fast API call.
static const int kFastApiCallArguments = 3;
// Reserves space for the extra arguments to FastHandleApiCall in the
// caller's frame.
//
@ -423,10 +427,9 @@ static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
// -- esp[4] : last argument in the internal frame of the caller
// -----------------------------------
__ pop(scratch);
__ push(Immediate(Smi::FromInt(0)));
__ push(Immediate(Smi::FromInt(0)));
__ push(Immediate(Smi::FromInt(0)));
__ push(Immediate(Smi::FromInt(0)));
for (int i = 0; i < kFastApiCallArguments; i++) {
__ push(Immediate(Smi::FromInt(0)));
}
__ push(scratch);
}
@ -434,75 +437,81 @@ static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
// Undoes the effects of ReserveSpaceForFastApiCall.
static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
// ----------- S t a t e -------------
// -- esp[0] : return address
// -- esp[4] : last fast api call extra argument
// -- esp[0] : return address.
// -- esp[4] : last fast api call extra argument.
// -- ...
// -- esp[16] : first fast api call extra argument
// -- esp[20] : last argument in the internal frame
// -- esp[kFastApiCallArguments * 4] : first fast api call extra argument.
// -- esp[kFastApiCallArguments * 4 + 4] : last argument in the internal
// frame.
// -----------------------------------
__ pop(scratch);
__ add(Operand(esp), Immediate(kPointerSize * 4));
__ add(Operand(esp), Immediate(kPointerSize * kFastApiCallArguments));
__ push(scratch);
}
// Generates call to FastHandleApiCall builtin.
static void GenerateFastApiCall(MacroAssembler* masm,
static bool GenerateFastApiCall(MacroAssembler* masm,
const CallOptimization& optimization,
int argc) {
int argc,
Failure** failure) {
// ----------- S t a t e -------------
// -- esp[0] : return address
// -- esp[4] : object passing the type check
// (last fast api call extra argument,
// set by CheckPrototypes)
// -- esp[8] : api call data
// -- esp[12] : api callback
// -- esp[16] : api function
// -- esp[8] : api function
// (first fast api call extra argument)
// -- esp[20] : last argument
// -- esp[12] : api call data
// -- esp[16] : last argument
// -- ...
// -- esp[(argc + 5) * 4] : first argument
// -- esp[(argc + 6) * 4] : receiver
// -- esp[(argc + 3) * 4] : first argument
// -- esp[(argc + 4) * 4] : receiver
// -----------------------------------
// Get the function and setup the context.
JSFunction* function = optimization.constant_function();
__ mov(edi, Immediate(Handle<JSFunction>(function)));
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
// Pass the additional arguments FastHandleApiCall expects.
__ mov(Operand(esp, 4 * kPointerSize), edi);
bool info_loaded = false;
Object* callback = optimization.api_call_info()->callback();
if (Heap::InNewSpace(callback)) {
info_loaded = true;
__ mov(ecx, Handle<CallHandlerInfo>(optimization.api_call_info()));
__ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kCallbackOffset));
__ mov(Operand(esp, 3 * kPointerSize), ebx);
} else {
__ mov(Operand(esp, 3 * kPointerSize), Immediate(Handle<Object>(callback)));
}
__ mov(Operand(esp, 2 * kPointerSize), edi);
Object* call_data = optimization.api_call_info()->data();
Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info());
if (Heap::InNewSpace(call_data)) {
if (!info_loaded) {
__ mov(ecx, Handle<CallHandlerInfo>(optimization.api_call_info()));
}
__ mov(ecx, api_call_info_handle);
__ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset));
__ mov(Operand(esp, 2 * kPointerSize), ebx);
__ mov(Operand(esp, 3 * kPointerSize), ebx);
} else {
__ mov(Operand(esp, 2 * kPointerSize),
__ mov(Operand(esp, 3 * kPointerSize),
Immediate(Handle<Object>(call_data)));
}
// Set the number of arguments.
__ mov(eax, Immediate(argc + 4));
// Prepare arguments for ApiCallEntryStub.
__ lea(eax, Operand(esp, 3 * kPointerSize));
__ lea(ebx, Operand(esp, (argc + 3) * kPointerSize));
__ Set(edx, Immediate(argc));
// Jump to the fast api call builtin (tail call).
Handle<Code> code = Handle<Code>(
Builtins::builtin(Builtins::FastHandleApiCall));
ParameterCount expected(0);
__ InvokeCode(code, expected, expected,
RelocInfo::CODE_TARGET, JUMP_FUNCTION);
Object* callback = optimization.api_call_info()->callback();
Address api_function_address = v8::ToCData<Address>(callback);
ApiFunction fun(api_function_address);
ApiCallEntryStub stub(api_call_info_handle, &fun);
__ EnterInternalFrame();
// 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;
}
@ -515,7 +524,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
arguments_(arguments),
name_(name) {}
void Compile(MacroAssembler* masm,
bool Compile(MacroAssembler* masm,
JSObject* object,
JSObject* holder,
String* name,
@ -524,7 +533,8 @@ class CallInterceptorCompiler BASE_EMBEDDED {
Register scratch1,
Register scratch2,
Register scratch3,
Label* miss) {
Label* miss,
Failure** failure) {
ASSERT(holder->HasNamedInterceptor());
ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
@ -535,17 +545,18 @@ class CallInterceptorCompiler BASE_EMBEDDED {
CallOptimization optimization(lookup);
if (optimization.is_constant_call()) {
CompileCacheable(masm,
object,
receiver,
scratch1,
scratch2,
scratch3,
holder,
lookup,
name,
optimization,
miss);
return CompileCacheable(masm,
object,
receiver,
scratch1,
scratch2,
scratch3,
holder,
lookup,
name,
optimization,
miss,
failure);
} else {
CompileRegular(masm,
object,
@ -556,11 +567,12 @@ class CallInterceptorCompiler BASE_EMBEDDED {
name,
holder,
miss);
return true;
}
}
private:
void CompileCacheable(MacroAssembler* masm,
bool CompileCacheable(MacroAssembler* masm,
JSObject* object,
Register receiver,
Register scratch1,
@ -570,7 +582,8 @@ class CallInterceptorCompiler BASE_EMBEDDED {
LookupResult* lookup,
String* name,
const CallOptimization& optimization,
Label* miss_label) {
Label* miss_label,
Failure** failure) {
ASSERT(optimization.is_constant_call());
ASSERT(!lookup->holder()->IsGlobalObject());
@ -632,7 +645,11 @@ class CallInterceptorCompiler BASE_EMBEDDED {
// Invoke function.
if (can_do_fast_api_call) {
GenerateFastApiCall(masm, optimization, arguments_.immediate());
bool success = GenerateFastApiCall(masm, optimization,
arguments_.immediate(), failure);
if (!success) {
return false;
}
} else {
__ InvokeFunction(optimization.constant_function(), arguments_,
JUMP_FUNCTION);
@ -650,6 +667,8 @@ class CallInterceptorCompiler BASE_EMBEDDED {
if (can_do_fast_api_call) {
FreeSpaceForFastApiCall(masm, scratch1);
}
return true;
}
void CompileRegular(MacroAssembler* masm,
@ -905,7 +924,7 @@ Register StubCompiler::CheckPrototypes(JSObject* object,
MaybeObject* maybe_lookup_result = Heap::LookupSymbol(name);
Object* lookup_result = NULL; // Initialization to please compiler.
if (!maybe_lookup_result->ToObject(&lookup_result)) {
set_failure(Failure::cast(lookup_result));
set_failure(Failure::cast(maybe_lookup_result));
return reg;
}
name = String::cast(lookup_result);
@ -1046,8 +1065,7 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object,
__ EnterInternalFrame();
// Push the stack address where the list of arguments ends.
__ mov(scratch2, esp);
__ sub(Operand(scratch2), Immediate(2 * kPointerSize));
__ lea(scratch2, Operand(esp, -2 * kPointerSize));
__ push(scratch2);
__ push(receiver); // receiver
__ push(reg); // holder
@ -1061,12 +1079,11 @@ 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.
__ mov(eax, esp);
__ add(Operand(eax), Immediate(4 * kPointerSize));
STATIC_ASSERT(ApiGetterEntryStub::kStackSpace == 5);
__ lea(eax, Operand(esp, 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);
@ -1077,7 +1094,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(result);
*failure = Failure::cast(try_call_result);
return false;
}
}
@ -2208,7 +2225,11 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
}
if (depth != kInvalidProtoDepth) {
GenerateFastApiCall(masm(), optimization, argc);
Failure* failure;
bool success = GenerateFastApiCall(masm(), optimization, argc, &failure);
if (!success) {
return failure;
}
} else {
__ InvokeFunction(function, arguments(), JUMP_FUNCTION);
}
@ -2253,16 +2274,21 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
__ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
CallInterceptorCompiler compiler(this, arguments(), ecx);
compiler.Compile(masm(),
object,
holder,
name,
&lookup,
edx,
ebx,
edi,
eax,
&miss);
Failure* failure;
bool success = compiler.Compile(masm(),
object,
holder,
name,
&lookup,
edx,
ebx,
edi,
eax,
&miss,
&failure);
if (!success) {
return false;
}
// Restore receiver.
__ mov(edx, Operand(esp, (argc + 1) * kPointerSize));

5
deps/v8/src/jump-target-heavy.cc

@ -414,8 +414,9 @@ void BreakTarget::Branch(Condition cc, Hint hint) {
DeferredCode::DeferredCode()
: masm_(CodeGeneratorScope::Current()->masm()),
statement_position_(masm_->current_statement_position()),
position_(masm_->current_position()),
statement_position_(masm_->positions_recorder()->
current_statement_position()),
position_(masm_->positions_recorder()->current_position()),
frame_state_(CodeGeneratorScope::Current()->frame()) {
ASSERT(statement_position_ != RelocInfo::kNoPosition);
ASSERT(position_ != RelocInfo::kNoPosition);

5
deps/v8/src/jump-target-light.cc

@ -36,8 +36,9 @@ namespace internal {
DeferredCode::DeferredCode()
: masm_(CodeGeneratorScope::Current()->masm()),
statement_position_(masm_->current_statement_position()),
position_(masm_->current_position()),
statement_position_(masm_->positions_recorder()->
current_statement_position()),
position_(masm_->positions_recorder()->current_position()),
frame_state_(*CodeGeneratorScope::Current()->frame()) {
ASSERT(statement_position_ != RelocInfo::kNoPosition);
ASSERT(position_ != RelocInfo::kNoPosition);

5
deps/v8/src/objects-debug.cc

@ -997,6 +997,8 @@ void AccessorInfo::AccessorInfoPrint() {
data()->ShortPrint();
PrintF("\n - flag: ");
flag()->ShortPrint();
PrintF("\n - load_stub_cache: ");
load_stub_cache()->ShortPrint();
}
void AccessCheckInfo::AccessCheckInfoVerify() {
@ -1046,6 +1048,7 @@ void CallHandlerInfo::CallHandlerInfoVerify() {
CHECK(IsCallHandlerInfo());
VerifyPointer(callback());
VerifyPointer(data());
VerifyPointer(call_stub_cache());
}
void CallHandlerInfo::CallHandlerInfoPrint() {
@ -1054,6 +1057,8 @@ void CallHandlerInfo::CallHandlerInfoPrint() {
callback()->ShortPrint();
PrintF("\n - data: ");
data()->ShortPrint();
PrintF("\n - call_stub_cache: ");
call_stub_cache()->ShortPrint();
}
void TemplateInfo::TemplateInfoVerify() {

42
deps/v8/src/objects-inl.h

@ -2557,6 +2557,7 @@ 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)
@ -2671,6 +2672,7 @@ SMI_ACCESSORS(SharedFunctionInfo, this_property_assignments_count,
#else
#define PSEUDO_SMI_ACCESSORS_LO(holder, name, offset) \
STATIC_ASSERT(holder::offset % kPointerSize == 0); \
int holder::name() { \
int value = READ_INT_FIELD(this, offset); \
ASSERT(kHeapObjectTag == 1); \
@ -2686,30 +2688,36 @@ SMI_ACCESSORS(SharedFunctionInfo, this_property_assignments_count,
(value << 1) & ~kHeapObjectTag); \
}
#define PSEUDO_SMI_ACCESSORS_HI(holder, name, offset) \
#define PSEUDO_SMI_ACCESSORS_HI(holder, name, offset) \
STATIC_ASSERT(holder::offset % kPointerSize == kIntSize); \
INT_ACCESSORS(holder, name, offset)
PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, length, kLengthOffset)
PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo, formal_parameter_count,
kFormalParameterCountOffset)
PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo,
formal_parameter_count,
kFormalParameterCountOffset)
PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, expected_nof_properties,
kExpectedNofPropertiesOffset)
PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo,
expected_nof_properties,
kExpectedNofPropertiesOffset)
PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo, num_literals, kNumLiteralsOffset)
PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, start_position_and_type,
kStartPositionAndTypeOffset)
PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo, end_position, kEndPositionOffset)
PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, function_token_position,
kFunctionTokenPositionOffset)
PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo, compiler_hints,
kCompilerHintsOffset)
PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, this_property_assignments_count,
kThisPropertyAssignmentsCountOffset)
PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, end_position, kEndPositionOffset)
PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo,
start_position_and_type,
kStartPositionAndTypeOffset)
PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo,
function_token_position,
kFunctionTokenPositionOffset)
PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo,
compiler_hints,
kCompilerHintsOffset)
PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo,
this_property_assignments_count,
kThisPropertyAssignmentsCountOffset)
#endif

4
deps/v8/src/objects.h

@ -5423,6 +5423,7 @@ 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);
@ -5433,7 +5434,8 @@ class CallHandlerInfo: public Struct {
static const int kCallbackOffset = HeapObject::kHeaderSize;
static const int kDataOffset = kCallbackOffset + kPointerSize;
static const int kSize = kDataOffset + kPointerSize;
static const int kCallStubCacheOffset = kDataOffset + kPointerSize;
static const int kSize = kCallStubCacheOffset + kPointerSize;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(CallHandlerInfo);

1102
deps/v8/src/parser.cc

File diff suppressed because it is too large

238
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,6 +177,125 @@ class ScriptDataImpl : public ScriptData {
};
// Record only functions.
class PartialParserRecorder {
public:
PartialParserRecorder();
void LogFunction(int start, int end, int literals, int properties) {
function_store_.Add(start);
function_store_.Add(end);
function_store_.Add(literals);
function_store_.Add(properties);
}
void LogSymbol(int start, const char* symbol, int length) { }
// Logs an error message and marks the log as containing an error.
// Further logging will be ignored, and ExtractData will return a vector
// representing the error only.
void LogMessage(int start,
int end,
const char* message,
const char* argument_opt) {
Scanner::Location location(start, end);
Vector<const char*> arguments;
if (argument_opt != NULL) {
arguments = Vector<const char*>(&argument_opt, 1);
}
this->LogMessage(location, message, arguments);
}
int function_position() { return function_store_.size(); }
void LogMessage(Scanner::Location loc,
const char* message,
Vector<const char*> args);
Vector<unsigned> ExtractData();
void PauseRecording() {
pause_count_++;
is_recording_ = false;
}
void ResumeRecording() {
ASSERT(pause_count_ > 0);
if (--pause_count_ == 0) is_recording_ = !has_error();
}
int symbol_position() { return 0; }
int symbol_ids() { return 0; }
protected:
bool has_error() {
return static_cast<bool>(preamble_[ScriptDataImpl::kHasErrorOffset]);
}
bool is_recording() {
return is_recording_;
}
void WriteString(Vector<const char> str);
Collector<unsigned> function_store_;
unsigned preamble_[ScriptDataImpl::kHeaderSize];
bool is_recording_;
int pause_count_;
#ifdef DEBUG
int prev_start_;
#endif
};
// Record both functions and symbols.
class CompleteParserRecorder: public PartialParserRecorder {
public:
CompleteParserRecorder();
void LogSymbol(int start, Vector<const char> literal);
void LogSymbol(int start, const char* symbol, int length) {
LogSymbol(start, Vector<const char>(symbol, length));
}
Vector<unsigned> ExtractData();
int symbol_position() { return symbol_store_.size(); }
int symbol_ids() { return symbol_id_; }
private:
static int vector_hash(Vector<const char> string) {
int hash = 0;
for (int i = 0; i < string.length(); i++) {
int c = string[i];
hash += c;
hash += (hash << 10);
hash ^= (hash >> 6);
}
return hash;
}
static bool vector_compare(void* a, void* b) {
Vector<const char>* string1 = reinterpret_cast<Vector<const char>* >(a);
Vector<const char>* string2 = reinterpret_cast<Vector<const char>* >(b);
int length = string1->length();
if (string2->length() != length) return false;
return memcmp(string1->start(), string2->start(), length) == 0;
}
// Write a non-negative number to the symbol store.
void WriteNumber(int number);
Collector<byte> symbol_store_;
Collector<Vector<const char> > symbol_entries_;
HashMap symbol_table_;
int symbol_id_;
};
class ParserApi {
public:
// Parses the source code represented by the compilation info and sets its
@ -196,6 +315,8 @@ class ParserApi {
v8::Extension* extension);
};
// ----------------------------------------------------------------------------
// REGEXP PARSING
// A BuffferedZoneList is an automatically growing list, just like (and backed
// by) a ZoneList, that is optimized for the case of adding and removing
@ -411,51 +532,44 @@ class RegExpParser {
uc32 Next();
FlatStringReader* in() { return in_; }
void ScanForCaptures();
Handle<String>* error_;
ZoneList<RegExpCapture*>* captures_;
FlatStringReader* in_;
uc32 current_;
int next_pos_;
// The capture count is only valid after we have scanned for captures.
int capture_count_;
bool has_more_;
bool multiline_;
int next_pos_;
FlatStringReader* in_;
Handle<String>* error_;
bool simple_;
bool contains_anchor_;
ZoneList<RegExpCapture*>* captures_;
bool is_scanned_for_captures_;
// The capture count is only valid after we have scanned for captures.
int capture_count_;
bool failed_;
};
// ----------------------------------------------------------------------------
// JAVASCRIPT PARSING
class Parser {
public:
Parser(Handle<Script> script, bool allow_natives_syntax,
v8::Extension* extension, ParserMode is_pre_parsing,
ParserFactory* factory, ParserLog* log, ScriptDataImpl* pre_data);
Parser(Handle<Script> script,
bool allow_natives_syntax,
v8::Extension* extension,
ScriptDataImpl* pre_data);
virtual ~Parser() { }
// Pre-parse the program from the character stream; returns true on
// success, false if a stack-overflow happened during parsing.
bool PreParseProgram(Handle<String> source, unibrow::CharacterStream* stream);
void ReportMessage(const char* message, Vector<const char*> args);
virtual void ReportMessageAt(Scanner::Location loc,
const char* message,
Vector<const char*> args) = 0;
// Returns NULL if parsing failed.
FunctionLiteral* ParseProgram(Handle<String> source,
bool in_global_context);
FunctionLiteral* ParseLazy(Handle<SharedFunctionInfo> info);
// The minimum number of contiguous assignment that will
// be treated as an initialization block. Benchmarks show that
// the overhead exceeds the savings below this limit.
static const int kMinInitializationBlock = 3;
void ReportMessageAt(Scanner::Location loc,
const char* message,
Vector<const char*> args);
protected:
enum Mode {
PARSE_LAZILY,
PARSE_EAGERLY
@ -464,28 +578,9 @@ class Parser {
// Report syntax error
void ReportUnexpectedToken(Token::Value token);
void ReportInvalidPreparseData(Handle<String> name, bool* ok);
Handle<Script> script_;
Scanner scanner_;
Scope* top_scope_;
int with_nesting_level_;
TemporaryScope* temp_scope_;
Mode mode_;
Target* target_stack_; // for break, continue statements
bool allow_natives_syntax_;
v8::Extension* extension_;
ParserFactory* factory_;
ParserLog* log_;
bool is_pre_parsing_;
ScriptDataImpl* pre_data_;
FuncNameInferrer* fni_;
void ReportMessage(const char* message, Vector<const char*> args);
bool inside_with() const { return with_nesting_level_ > 0; }
ParserFactory* factory() const { return factory_; }
ParserLog* log() const { return log_; }
Scanner& scanner() { return scanner_; }
Mode mode() const { return mode_; }
ScriptDataImpl* pre_data() const { return pre_data_; }
@ -494,7 +589,7 @@ class Parser {
// which is set to false if parsing failed; it is unchanged otherwise.
// By making the 'exception handling' explicit, we are forced to check
// for failure at the call sites.
void* ParseSourceElements(ZoneListWrapper<Statement>* processor,
void* ParseSourceElements(ZoneList<Statement*>* processor,
int end_token, bool* ok);
Statement* ParseStatement(ZoneStringList* labels, bool* ok);
Statement* ParseFunctionDeclaration(bool* ok);
@ -607,10 +702,10 @@ class Parser {
bool* ok);
// Parser support
virtual VariableProxy* Declare(Handle<String> name, Variable::Mode mode,
FunctionLiteral* fun,
bool resolve,
bool* ok) = 0;
VariableProxy* Declare(Handle<String> name, Variable::Mode mode,
FunctionLiteral* fun,
bool resolve,
bool* ok);
bool TargetStackContainsLabel(Handle<String> label);
BreakableStatement* LookupBreakTarget(Handle<String> label, bool* ok);
@ -618,6 +713,28 @@ class Parser {
void RegisterTargetUse(BreakTarget* target, Target* stop);
// Factory methods.
Statement* EmptyStatement() {
static v8::internal::EmptyStatement empty;
return &empty;
}
Scope* NewScope(Scope* parent, Scope::Type type, bool inside_with);
Handle<String> LookupSymbol(int symbol_id,
Vector<const char> string);
Handle<String> LookupCachedSymbol(int symbol_id,
Vector<const char> string);
Expression* NewCall(Expression* expression,
ZoneList<Expression*>* arguments,
int pos) {
return new Call(expression, arguments, pos);
}
// Create a number literal.
Literal* NewNumberLiteral(double value);
@ -639,6 +756,24 @@ class Parser {
Expression* NewThrowError(Handle<String> constructor,
Handle<String> type,
Vector< Handle<Object> > arguments);
ZoneList<Handle<String> > symbol_cache_;
Handle<Script> script_;
Scanner scanner_;
Scope* top_scope_;
int with_nesting_level_;
TemporaryScope* temp_scope_;
Mode mode_;
Target* target_stack_; // for break, continue statements
bool allow_natives_syntax_;
v8::Extension* extension_;
bool is_pre_parsing_;
ScriptDataImpl* pre_data_;
FuncNameInferrer* fni_;
};
@ -673,6 +808,9 @@ class CompileTimeValue: public AllStatic {
};
// ----------------------------------------------------------------------------
// JSON PARSING
// JSON is a subset of JavaScript, as specified in, e.g., the ECMAScript 5
// specification section 15.12.1 (and appendix A.8).
// The grammar is given section 15.12.1.2 (and appendix A.8.2).

71
deps/v8/src/platform-linux.cc

@ -99,30 +99,12 @@ uint64_t OS::CpuFeaturesImpliedByPlatform() {
#ifdef __arm__
bool OS::ArmCpuHasFeature(CpuFeature feature) {
const char* search_string = NULL;
static bool CPUInfoContainsString(const char * search_string) {
const char* file_name = "/proc/cpuinfo";
// Simple detection of VFP at runtime for Linux.
// It is based on /proc/cpuinfo, which reveals hardware configuration
// to user-space applications. According to ARM (mid 2009), no similar
// facility is universally available on the ARM architectures,
// so it's up to individual OSes to provide such.
//
// This is written as a straight shot one pass parser
// and not using STL string and ifstream because,
// on Linux, it's reading from a (non-mmap-able)
// character special device.
switch (feature) {
case VFP3:
search_string = "vfp";
break;
case ARMv7:
search_string = "ARMv7";
break;
default:
UNREACHABLE();
}
FILE* f = NULL;
const char* what = search_string;
@ -149,6 +131,43 @@ bool OS::ArmCpuHasFeature(CpuFeature feature) {
// Did not find string in the proc file.
return false;
}
bool OS::ArmCpuHasFeature(CpuFeature feature) {
const int max_items = 2;
const char* search_strings[max_items] = { NULL, NULL };
int search_items = 0;
// Simple detection of VFP at runtime for Linux.
// It is based on /proc/cpuinfo, which reveals hardware configuration
// to user-space applications. According to ARM (mid 2009), no similar
// facility is universally available on the ARM architectures,
// so it's up to individual OSes to provide such.
switch (feature) {
case VFP3:
search_strings[0] = "vfpv3";
// Some old kernels will report vfp for A8, not vfpv3, so we check for
// A8 explicitely. The cpuinfo file report the CPU Part which for Cortex
// A8 is 0xc08.
search_strings[1] = "0xc08";
search_items = 2;
ASSERT(search_items <= max_items);
break;
case ARMv7:
search_strings[0] = "ARMv7" ;
search_items = 1;
ASSERT(search_items <= max_items);
break;
default:
UNREACHABLE();
}
for (int i = 0; i < search_items; ++i) {
if (CPUInfoContainsString(search_strings[i])) {
return true;
}
}
return false;
}
#endif // def __arm__
@ -809,8 +828,17 @@ class Sampler::PlatformData : public Malloced {
syscall(SYS_tgkill, vm_tgid_, vm_tid_, SIGPROF);
// Convert ms to us and subtract 100 us to compensate delays
// occuring during signal delivery.
int result = usleep(sampler_->interval_ * 1000 - 100);
ASSERT(result == 0 || errno == EINTR);
const useconds_t interval = sampler_->interval_ * 1000 - 100;
int result = usleep(interval);
#ifdef DEBUG
if (result != 0 && errno != EINTR) {
fprintf(stderr,
"SignalSender usleep error; interval = %u, errno = %d\n",
interval,
errno);
ASSERT(result == 0 || errno == EINTR);
}
#endif
USE(result);
}
}
@ -843,6 +871,7 @@ Sampler::Sampler(int interval, bool profiling)
Sampler::~Sampler() {
ASSERT(!data_->signal_sender_launched_);
delete data_;
}

1414
deps/v8/src/preparser.h

File diff suppressed because it is too large

30
deps/v8/src/profile-generator.cc

@ -1848,22 +1848,6 @@ HeapEntry* HeapSnapshotGenerator::GetEntry(Object* obj) {
}
int HeapSnapshotGenerator::GetGlobalSecurityToken() {
return collection_->token_enumerator()->GetTokenId(
Top::context()->global()->global_context()->security_token());
}
int HeapSnapshotGenerator::GetObjectSecurityToken(HeapObject* obj) {
if (obj->IsGlobalContext()) {
return collection_->token_enumerator()->GetTokenId(
Context::cast(obj)->security_token());
} else {
return TokenEnumerator::kNoSecurityToken;
}
}
class IndexedReferencesExtractor : public ObjectVisitor {
public:
IndexedReferencesExtractor(HeapSnapshotGenerator* generator,
@ -1893,19 +1877,11 @@ class IndexedReferencesExtractor : public ObjectVisitor {
void HeapSnapshotGenerator::ExtractReferences(HeapObject* obj) {
// We need to reference JS global objects from snapshot's root.
// We also need to only include global objects from the current
// security context. And we don't want to add the global proxy,
// as we don't have a special type for it.
// We use JSGlobalProxy because this is what embedder (e.g. browser)
// uses for the global object.
if (obj->IsJSGlobalProxy()) {
int global_security_token = GetGlobalSecurityToken();
JSGlobalProxy* proxy = JSGlobalProxy::cast(obj);
int object_security_token =
collection_->token_enumerator()->GetTokenId(
Context::cast(proxy->context())->security_token());
if (object_security_token == TokenEnumerator::kNoSecurityToken
|| object_security_token == global_security_token) {
SetRootReference(proxy->map()->prototype());
}
SetRootReference(proxy->map()->prototype());
return;
}

2
deps/v8/src/profile-generator.h

@ -948,8 +948,6 @@ class HeapSnapshotGenerator {
private:
HeapEntry* GetEntry(Object* obj);
int GetGlobalSecurityToken();
int GetObjectSecurityToken(HeapObject* obj);
void ExtractReferences(HeapObject* obj);
void ExtractClosureReferences(JSObject* js_obj, HeapEntry* entry);
void ExtractPropertyReferences(JSObject* js_obj, HeapEntry* entry);

115
deps/v8/src/regexp.js

@ -71,9 +71,6 @@ function DoConstructRegExp(object, pattern, flags, isConstructorCall) {
}
}
if (!isConstructorCall) {
regExpCache.type = 'none';
}
%RegExpInitializeObject(object, pattern, global, ignoreCase, multiline);
// Call internal function to compile the pattern.
@ -121,22 +118,6 @@ function DoRegExpExec(regexp, string, index) {
}
function RegExpCache() {
this.type = 'none';
this.regExp = 0;
this.subject = 0;
this.replaceString = 0;
this.answer = 0;
// answerSaved marks whether the contents of answer is valid for a cache
// hit in RegExpExec, StringMatch and StringSplit.
this.answerSaved = false;
this.splitLimit = 0; // Used only when type is "split".
}
var regExpCache = new RegExpCache();
function BuildResultFromMatchInfo(lastMatchInfo, s) {
var numResults = NUMBER_OF_CAPTURES(lastMatchInfo) >> 1;
var result = %_RegExpConstructResult(numResults, lastMatchInfo[CAPTURE0], s);
@ -178,32 +159,6 @@ function RegExpExec(string) {
['RegExp.prototype.exec', this]);
}
var cache = regExpCache;
var saveAnswer = false;
var lastIndex = this.lastIndex;
// Since cache.subject is always a string, a matching input can not
// cause visible side-effects when converted to a string, so we can omit
// the conversion required by the specification.
// Likewise, the regexp.lastIndex and regexp.global properties are value
// properties that are not configurable, so reading them can also not cause
// any side effects (converting lastIndex to a number can, though).
if (%_ObjectEquals(cache.type, 'exec') &&
%_ObjectEquals(0, lastIndex) &&
%_IsRegExpEquivalent(cache.regExp, this) &&
%_ObjectEquals(cache.subject, string)) {
if (cache.answerSaved) {
// The regexp.lastIndex value must be 0 for non-global RegExps, and for
// global RegExps we only cache negative results, which gives a lastIndex
// of zero as well.
this.lastIndex = 0;
return %_RegExpCloneResult(cache.answer);
} else {
saveAnswer = true;
}
}
if (%_ArgumentsLength() === 0) {
var regExpInput = LAST_INPUT(lastMatchInfo);
if (IS_UNDEFINED(regExpInput)) {
@ -217,11 +172,13 @@ function RegExpExec(string) {
} else {
s = ToString(string);
}
var global = this.global;
var lastIndex = this.lastIndex;
// Conversion is required by the ES5 specification (RegExp.prototype.exec
// algorithm, step 5) even if the value is discarded for non-global RegExps.
var i = TO_INTEGER(lastIndex);
var global = this.global;
if (global) {
if (i < 0 || i > s.length) {
this.lastIndex = 0;
@ -237,16 +194,9 @@ 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;
}
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.
return null;
}
// Successful match.
@ -254,17 +204,9 @@ 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;
}
@ -289,33 +231,22 @@ function RegExpTest(string) {
string = regExpInput;
}
var lastIndex = this.lastIndex;
var cache = regExpCache;
if (%_ObjectEquals(cache.type, 'test') &&
%_IsRegExpEquivalent(cache.regExp, this) &&
%_ObjectEquals(cache.subject, string) &&
%_ObjectEquals(0, lastIndex)) {
// The regexp.lastIndex value must be 0 for non-global RegExps, and for
// global RegExps we only cache negative results, which gives a resulting
// lastIndex of zero as well.
if (global) this.lastIndex = 0;
return cache.answer;
}
var s;
if (IS_STRING(string)) {
s = string;
} else {
s = ToString(string);
}
var length = s.length;
var lastIndex = this.lastIndex;
// Conversion is required by the ES5 specification (RegExp.prototype.exec
// algorithm, step 5) even if the value is discarded for non-global RegExps.
var i = TO_INTEGER(lastIndex);
var global = this.global;
if (global) {
if (i < 0 || i > length) {
if (i < 0 || i > s.length) {
this.lastIndex = 0;
return false;
}
@ -323,8 +254,6 @@ 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 '?'
@ -334,7 +263,7 @@ function RegExpTest(string) {
if (!%_ObjectEquals(regexp_key, this)) {
regexp_key = this;
regexp_val = new $RegExp(this.source.substring(2, this.source.length),
(this.global ? 'g' : '')
(global ? 'g' : '')
+ (this.ignoreCase ? 'i' : '')
+ (this.multiline ? 'm' : ''));
}
@ -345,24 +274,13 @@ function RegExpTest(string) {
// matchIndices is either null or the lastMatchInfo array.
var matchIndices = %_RegExpExec(this, s, i, lastMatchInfo);
var result = (matchIndices !== null);
if (result) {
lastMatchInfoOverride = null;
}
if (global) {
if (result) {
this.lastIndex = lastMatchInfo[CAPTURE1];
return true;
} else {
this.lastIndex = 0;
if (lastIndex !== 0) return false;
}
if (matchIndices === null) {
if (global) this.lastIndex = 0;
return false;
}
cache.type = 'test';
cache.regExp = this;
cache.subject = s;
cache.answer = result;
return result;
lastMatchInfoOverride = null;
if (global) this.lastIndex = lastMatchInfo[CAPTURE1];
return true;
}
@ -510,7 +428,6 @@ function SetupRegExp() {
return IS_UNDEFINED(regExpInput) ? "" : regExpInput;
}
function RegExpSetInput(string) {
regExpCache.type = 'none';
LAST_INPUT(lastMatchInfo) = ToString(string);
};

66
deps/v8/src/runtime.cc

@ -1424,66 +1424,6 @@ static MaybeObject* Runtime_RegExpConstructResult(Arguments args) {
}
static MaybeObject* Runtime_RegExpCloneResult(Arguments args) {
ASSERT(args.length() == 1);
Map* regexp_result_map;
{
AssertNoAllocation no_gc;
HandleScope handles;
regexp_result_map = Top::global_context()->regexp_result_map();
}
if (!args[0]->IsJSArray()) return args[0];
JSArray* result = JSArray::cast(args[0]);
// Arguments to RegExpCloneResult should always be fresh RegExp exec call
// results (either a fresh JSRegExpResult or null).
// If the argument is not a JSRegExpResult, or isn't unmodified, just return
// the argument uncloned.
if (result->map() != regexp_result_map) return result;
// Having the original JSRegExpResult map guarantees that we have
// fast elements and no properties except the two in-object properties.
ASSERT(result->HasFastElements());
ASSERT(result->properties() == Heap::empty_fixed_array());
ASSERT_EQ(2, regexp_result_map->inobject_properties());
Object* new_array_alloc;
{ MaybeObject* maybe_new_array_alloc =
Heap::AllocateRaw(JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
if (!maybe_new_array_alloc->ToObject(&new_array_alloc)) {
return maybe_new_array_alloc;
}
}
// Set HeapObject map to JSRegExpResult map.
reinterpret_cast<HeapObject*>(new_array_alloc)->set_map(regexp_result_map);
JSArray* new_array = JSArray::cast(new_array_alloc);
// Copy JSObject properties.
new_array->set_properties(result->properties()); // Empty FixedArray.
// Copy JSObject elements as copy-on-write.
FixedArray* elements = FixedArray::cast(result->elements());
if (elements != Heap::empty_fixed_array()) {
elements->set_map(Heap::fixed_cow_array_map());
}
new_array->set_elements(elements);
// Copy JSArray length.
new_array->set_length(result->length());
// Copy JSRegExpResult in-object property fields input and index.
new_array->FastPropertyAtPut(JSRegExpResult::kIndexIndex,
result->FastPropertyAt(
JSRegExpResult::kIndexIndex));
new_array->FastPropertyAtPut(JSRegExpResult::kInputIndex,
result->FastPropertyAt(
JSRegExpResult::kInputIndex));
return new_array;
}
static MaybeObject* Runtime_RegExpInitializeObject(Arguments args) {
AssertNoAllocation no_alloc;
ASSERT(args.length() == 5);
@ -8891,12 +8831,6 @@ static MaybeObject* Runtime_DebugPrintScopes(Arguments args) {
}
static MaybeObject* Runtime_GetCFrames(Arguments args) {
// See bug 906.
return Heap::undefined_value();
}
static MaybeObject* Runtime_GetThreadCount(Arguments args) {
HandleScope scope;
ASSERT(args.length() == 1);

5
deps/v8/src/runtime.h

@ -162,7 +162,6 @@ namespace internal {
F(RegExpExecMultiple, 4, 1) \
F(RegExpInitializeObject, 5, 1) \
F(RegExpConstructResult, 3, 1) \
F(RegExpCloneResult, 1, 1) \
\
/* JSON */ \
F(ParseJson, 1, 1) \
@ -325,7 +324,6 @@ namespace internal {
F(GetScopeCount, 2, 1) \
F(GetScopeDetails, 3, 1) \
F(DebugPrintScopes, 0, 1) \
F(GetCFrames, 1, 1) \
F(GetThreadCount, 1, 1) \
F(GetThreadDetails, 2, 1) \
F(SetDisableBreak, 1, 1) \
@ -426,7 +424,7 @@ namespace internal {
// ----------------------------------------------------------------------------
// INLINE_AND_RUNTIME_FUNCTION_LIST defines all inlined functions accessed
// with a native call of the form %_name from within JS code that also have
// a corresponding runtime function, that is called for slow cases.
// a corresponding runtime function, that is called for slow cases.
// Entries have the form F(name, number of arguments, number of return values).
#define INLINE_RUNTIME_FUNCTION_LIST(F) \
F(IsConstructCall, 0, 1) \
@ -438,7 +436,6 @@ namespace internal {
F(StringCompare, 2, 1) \
F(RegExpExec, 4, 1) \
F(RegExpConstructResult, 3, 1) \
F(RegExpCloneResult, 1, 1) \
F(GetFromCache, 2, 1) \
F(NumberToString, 1, 1) \
F(SwapElements, 3, 1)

167
deps/v8/src/scanner-base.cc

@ -0,0 +1,167 @@
// 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

165
deps/v8/src/scanner-base.h

@ -0,0 +1,165 @@
// 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_

136
deps/v8/src/scanner.cc

@ -184,142 +184,6 @@ 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

122
deps/v8/src/scanner.h

@ -30,6 +30,7 @@
#include "token.h"
#include "char-predicates-inl.h"
#include "scanner-base.h"
namespace v8 {
namespace internal {
@ -142,127 +143,6 @@ class ExternalStringUTF16Buffer: public UTF16Buffer {
};
class KeywordMatcher {
// Incrementally recognize keywords.
//
// Recognized keywords:
// break case catch const* continue debugger* default delete do else
// finally false for function if in instanceof native* new null
// return switch this throw true try typeof var void while with
//
// *: Actually "future reserved keywords". These are the only ones we
// recognized, the remaining are allowed as identifiers.
public:
KeywordMatcher()
: state_(INITIAL),
token_(Token::IDENTIFIER),
keyword_(NULL),
counter_(0),
keyword_token_(Token::ILLEGAL) {}
Token::Value token() { return token_; }
inline void AddChar(uc32 input) {
if (state_ != UNMATCHABLE) {
Step(input);
}
}
void Fail() {
token_ = Token::IDENTIFIER;
state_ = UNMATCHABLE;
}
private:
enum State {
UNMATCHABLE,
INITIAL,
KEYWORD_PREFIX,
KEYWORD_MATCHED,
C,
CA,
CO,
CON,
D,
DE,
F,
I,
IN,
N,
T,
TH,
TR,
V,
W
};
struct FirstState {
const char* keyword;
State state;
Token::Value token;
};
// Range of possible first characters of a keyword.
static const unsigned int kFirstCharRangeMin = 'b';
static const unsigned int kFirstCharRangeMax = 'w';
static const unsigned int kFirstCharRangeLength =
kFirstCharRangeMax - kFirstCharRangeMin + 1;
// State map for first keyword character range.
static FirstState first_states_[kFirstCharRangeLength];
// If input equals keyword's character at position, continue matching keyword
// from that position.
inline bool MatchKeywordStart(uc32 input,
const char* keyword,
int position,
Token::Value token_if_match) {
if (input == keyword[position]) {
state_ = KEYWORD_PREFIX;
this->keyword_ = keyword;
this->counter_ = position + 1;
this->keyword_token_ = token_if_match;
return true;
}
return false;
}
// If input equals match character, transition to new state and return true.
inline bool MatchState(uc32 input, char match, State new_state) {
if (input == match) {
state_ = new_state;
return true;
}
return false;
}
inline bool MatchKeyword(uc32 input,
char match,
State new_state,
Token::Value keyword_token) {
if (input != match) {
return false;
}
state_ = new_state;
token_ = keyword_token;
return true;
}
void Step(uc32 input);
// Current state.
State state_;
// Token for currently added characters.
Token::Value token_;
// Matching a specific keyword string (there is only one possible valid
// keyword with the current prefix).
const char* keyword_;
int counter_;
Token::Value keyword_token_;
};
enum ParserMode { PARSE, PREPARSE };
enum ParserLanguage { JAVASCRIPT, JSON };

34
deps/v8/src/spaces.cc

@ -270,8 +270,9 @@ void CodeRange::TearDown() {
// -----------------------------------------------------------------------------
// MemoryAllocator
//
intptr_t MemoryAllocator::capacity_ = 0;
intptr_t MemoryAllocator::size_ = 0;
intptr_t MemoryAllocator::capacity_ = 0;
intptr_t MemoryAllocator::capacity_executable_ = 0;
intptr_t MemoryAllocator::size_ = 0;
intptr_t MemoryAllocator::size_executable_ = 0;
List<MemoryAllocator::MemoryAllocationCallbackRegistration>
@ -302,8 +303,10 @@ int MemoryAllocator::Pop() {
}
bool MemoryAllocator::Setup(intptr_t capacity) {
bool MemoryAllocator::Setup(intptr_t capacity, intptr_t capacity_executable) {
capacity_ = RoundUp(capacity, Page::kPageSize);
capacity_executable_ = RoundUp(capacity_executable, Page::kPageSize);
ASSERT_GE(capacity_, capacity_executable_);
// Over-estimate the size of chunks_ array. It assumes the expansion of old
// space is always in the unit of a chunk (kChunkSize) except the last
@ -346,6 +349,7 @@ void MemoryAllocator::TearDown() {
ASSERT(top_ == max_nof_chunks_); // all chunks are free
top_ = 0;
capacity_ = 0;
capacity_executable_ = 0;
size_ = 0;
max_nof_chunks_ = 0;
}
@ -357,16 +361,31 @@ void* MemoryAllocator::AllocateRawMemory(const size_t requested,
if (size_ + static_cast<size_t>(requested) > static_cast<size_t>(capacity_)) {
return NULL;
}
void* mem;
if (executable == EXECUTABLE && CodeRange::exists()) {
mem = CodeRange::AllocateRawMemory(requested, allocated);
if (executable == EXECUTABLE) {
// Check executable memory limit.
if (size_executable_ + requested >
static_cast<size_t>(capacity_executable_)) {
LOG(StringEvent("MemoryAllocator::AllocateRawMemory",
"V8 Executable Allocation capacity exceeded"));
return NULL;
}
// Allocate executable memory either from code range or from the
// OS.
if (CodeRange::exists()) {
mem = CodeRange::AllocateRawMemory(requested, allocated);
} else {
mem = OS::Allocate(requested, allocated, true);
}
// Update executable memory size.
size_executable_ += static_cast<int>(*allocated);
} else {
mem = OS::Allocate(requested, allocated, (executable == EXECUTABLE));
mem = OS::Allocate(requested, allocated, false);
}
int alloced = static_cast<int>(*allocated);
size_ += alloced;
if (executable == EXECUTABLE) size_executable_ += alloced;
#ifdef DEBUG
ZapBlock(reinterpret_cast<Address>(mem), alloced);
#endif
@ -391,6 +410,7 @@ void MemoryAllocator::FreeRawMemory(void* mem,
if (executable == EXECUTABLE) size_executable_ -= static_cast<int>(length);
ASSERT(size_ >= 0);
ASSERT(size_executable_ >= 0);
}

12
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.
static bool Setup(intptr_t max_capacity);
// Max capacity of the total space and executable memory limit.
static bool Setup(intptr_t max_capacity, intptr_t capacity_executable);
// Deletes valid chunks.
static void TearDown();
@ -590,6 +590,12 @@ class MemoryAllocator : public AllStatic {
// Returns allocated spaces in bytes.
static intptr_t Size() { return size_; }
// Returns the maximum available executable bytes of heaps.
static 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_; }
@ -653,6 +659,8 @@ class MemoryAllocator : public AllStatic {
private:
// Maximum space size in bytes.
static intptr_t capacity_;
// Maximum subset of capacity_ that can be executable
static intptr_t capacity_executable_;
// Allocated space size in bytes.
static intptr_t size_;

82
deps/v8/src/string.js

@ -144,16 +144,6 @@ function StringLastIndexOf(searchString /* position */) { // length == 1
}
function CloneDenseArray(array) {
if (array === null) return null;
var clone = new $Array(array.length);
for (var i = 0; i < array.length; i++) {
clone[i] = array[i];
}
return clone;
}
// ECMA-262 section 15.5.4.9
//
// This function is implementation specific. For now, we do not
@ -172,33 +162,12 @@ function StringMatch(regexp) {
var subject = TO_STRING_INLINE(this);
if (IS_REGEXP(regexp)) {
if (!regexp.global) return regexp.exec(subject);
var cache = regExpCache;
var saveAnswer = false;
if (%_ObjectEquals(cache.type, 'match') &&
%_IsRegExpEquivalent(cache.regExp, regexp) &&
%_ObjectEquals(cache.subject, subject)) {
if (cache.answerSaved) {
return CloneDenseArray(cache.answer);
} else {
saveAnswer = true;
}
}
%_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]);
// lastMatchInfo is defined in regexp.js.
var result = %StringMatch(subject, regexp, lastMatchInfo);
cache.type = 'match';
cache.regExp = regexp;
cache.subject = subject;
if (saveAnswer) cache.answer = CloneDenseArray(result);
cache.answerSaved = saveAnswer;
return result;
return %StringMatch(subject, regexp, lastMatchInfo);
}
// Non-regexp argument.
regexp = new $RegExp(regexp);
// Don't check regexp exec cache, since the regexp is new.
// TODO(lrn): Change this if we start caching regexps here.
return RegExpExecNoTests(regexp, subject, 0);
}
@ -231,7 +200,6 @@ function StringReplace(search, replace) {
if (IS_REGEXP(search)) {
%_Log('regexp', 'regexp-replace,%0r,%1S', [search, subject]);
if (IS_FUNCTION(replace)) {
regExpCache.type = 'none';
if (search.global) {
return StringReplaceGlobalRegExpWithFunction(subject, search, replace);
} else {
@ -273,24 +241,10 @@ function StringReplace(search, replace) {
// Helper function for regular expressions in String.prototype.replace.
function StringReplaceRegExp(subject, regexp, replace) {
var cache = regExpCache;
if (%_ObjectEquals(cache.type, 'replace') &&
%_IsRegExpEquivalent(cache.regExp, regexp) &&
%_ObjectEquals(cache.replaceString, replace) &&
%_ObjectEquals(cache.subject, subject)) {
return cache.answer;
}
replace = TO_STRING_INLINE(replace);
var answer = %StringReplaceRegExpWithString(subject,
regexp,
replace,
lastMatchInfo);
cache.subject = subject;
cache.regExp = regexp;
cache.replaceString = replace;
cache.answer = answer;
cache.type = 'replace';
return answer;
return %StringReplaceRegExpWithString(subject,
regexp,
TO_STRING_INLINE(replace),
lastMatchInfo);
}
@ -605,34 +559,12 @@ function StringSplit(separator, limit) {
return result;
}
var cache = regExpCache;
var saveAnswer = false;
if (%_ObjectEquals(cache.type, 'split') &&
%_IsRegExpEquivalent(cache.regExp, separator) &&
%_ObjectEquals(cache.subject, subject) &&
%_ObjectEquals(cache.splitLimit, limit)) {
if (cache.answerSaved) {
return CloneDenseArray(cache.answer);
} else {
saveAnswer = true;
}
}
cache.type = 'split';
cache.regExp = separator;
cache.subject = subject;
cache.splitLimit = limit;
%_Log('regexp', 'regexp-split,%0S,%1r', [subject, separator]);
if (length === 0) {
cache.answerSaved = true;
if (splitMatch(separator, subject, 0, 0) != null) {
cache.answer = [];
if (DoRegExpExec(separator, subject, 0, 0) != null) {
return [];
}
cache.answer = [subject];
return [subject];
}
@ -680,8 +612,6 @@ function StringSplit(separator, limit) {
startIndex = currentIndex = endIndex;
}
if (saveAnswer) cache.answer = CloneDenseArray(result);
cache.answerSaved = saveAnswer;
return result;
}

129
deps/v8/src/strtod.cc

@ -31,6 +31,7 @@
#include "v8.h"
#include "strtod.h"
#include "bignum.h"
#include "cached-powers.h"
#include "double.h"
@ -83,44 +84,12 @@ static const double exact_powers_of_ten[] = {
// 10^22 = 0x21e19e0c9bab2400000 = 0x878678326eac9 * 2^22
10000000000000000000000.0
};
static const int kExactPowersOfTenSize = ARRAY_SIZE(exact_powers_of_ten);
extern "C" double gay_strtod(const char* s00, const char** se);
static double old_strtod(Vector<const char> buffer, int exponent) {
// gay_strtod is broken on Linux,x86. For numbers with few decimal digits
// the computation is done using floating-point operations which (on Linux)
// are prone to double-rounding errors.
// By adding several zeroes to the buffer gay_strtod falls back to a slower
// (but correct) algorithm.
const int kInsertedZeroesCount = 20;
char gay_buffer[1024];
Vector<char> gay_buffer_vector(gay_buffer, sizeof(gay_buffer));
int pos = 0;
for (int i = 0; i < buffer.length(); ++i) {
gay_buffer_vector[pos++] = buffer[i];
}
for (int i = 0; i < kInsertedZeroesCount; ++i) {
gay_buffer_vector[pos++] = '0';
}
exponent -= kInsertedZeroesCount;
gay_buffer_vector[pos++] = 'e';
if (exponent < 0) {
gay_buffer_vector[pos++] = '-';
exponent = -exponent;
}
const int kNumberOfExponentDigits = 5;
for (int i = kNumberOfExponentDigits - 1; i >= 0; i--) {
gay_buffer_vector[pos + i] = exponent % 10 + '0';
exponent /= 10;
}
pos += kNumberOfExponentDigits;
gay_buffer_vector[pos] = '\0';
return gay_strtod(gay_buffer, NULL);
}
// Maximum number of significant digits in the decimal representation.
// In fact the value is 772 (see conversions.cc), but to give us some margin
// we round up to 780.
static const int kMaxSignificantDecimalDigits = 780;
static Vector<const char> TrimLeadingZeros(Vector<const char> buffer) {
for (int i = 0; i < buffer.length(); i++) {
@ -142,6 +111,23 @@ static Vector<const char> TrimTrailingZeros(Vector<const char> buffer) {
}
static void TrimToMaxSignificantDigits(Vector<const char> buffer,
int exponent,
char* significant_buffer,
int* significant_exponent) {
for (int i = 0; i < kMaxSignificantDecimalDigits - 1; ++i) {
significant_buffer[i] = buffer[i];
}
// The input buffer has been trimmed. Therefore the last digit must be
// different from '0'.
ASSERT(buffer[buffer.length() - 1] != '0');
// Set the last digit to be non-zero. This is sufficient to guarantee
// correct rounding.
significant_buffer[kMaxSignificantDecimalDigits - 1] = '1';
*significant_exponent =
exponent + (buffer.length() - kMaxSignificantDecimalDigits);
}
// Reads digits from the buffer and converts them to a uint64.
// Reads in as many digits as fit into a uint64.
// When the string starts with "1844674407370955161" no further digit is read.
@ -374,20 +360,81 @@ static bool DiyFpStrtod(Vector<const char> buffer,
}
// Returns the correct double for the buffer*10^exponent.
// The variable guess should be a close guess that is either the correct double
// or its lower neighbor (the nearest double less than the correct one).
// Preconditions:
// buffer.length() + exponent <= kMaxDecimalPower + 1
// buffer.length() + exponent > kMinDecimalPower
// buffer.length() <= kMaxDecimalSignificantDigits
static double BignumStrtod(Vector<const char> buffer,
int exponent,
double guess) {
if (guess == V8_INFINITY) {
return guess;
}
DiyFp upper_boundary = Double(guess).UpperBoundary();
ASSERT(buffer.length() + exponent <= kMaxDecimalPower + 1);
ASSERT(buffer.length() + exponent > kMinDecimalPower);
ASSERT(buffer.length() <= kMaxSignificantDecimalDigits);
// Make sure that the Bignum will be able to hold all our numbers.
// Our Bignum implementation has a separate field for exponents. Shifts will
// consume at most one bigit (< 64 bits).
// ln(10) == 3.3219...
ASSERT(((kMaxDecimalPower + 1) * 333 / 100) < Bignum::kMaxSignificantBits);
Bignum input;
Bignum boundary;
input.AssignDecimalString(buffer);
boundary.AssignUInt64(upper_boundary.f());
if (exponent >= 0) {
input.MultiplyByPowerOfTen(exponent);
} else {
boundary.MultiplyByPowerOfTen(-exponent);
}
if (upper_boundary.e() > 0) {
boundary.ShiftLeft(upper_boundary.e());
} else {
input.ShiftLeft(-upper_boundary.e());
}
int comparison = Bignum::Compare(input, boundary);
if (comparison < 0) {
return guess;
} else if (comparison > 0) {
return Double(guess).NextDouble();
} else if ((Double(guess).Significand() & 1) == 0) {
// Round towards even.
return guess;
} else {
return Double(guess).NextDouble();
}
}
double Strtod(Vector<const char> buffer, int exponent) {
Vector<const char> left_trimmed = TrimLeadingZeros(buffer);
Vector<const char> trimmed = TrimTrailingZeros(left_trimmed);
exponent += left_trimmed.length() - trimmed.length();
if (trimmed.length() == 0) return 0.0;
if (trimmed.length() > kMaxSignificantDecimalDigits) {
char significant_buffer[kMaxSignificantDecimalDigits];
int significant_exponent;
TrimToMaxSignificantDigits(trimmed, exponent,
significant_buffer, &significant_exponent);
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 result;
if (DoubleStrtod(trimmed, exponent, &result) ||
DiyFpStrtod(trimmed, exponent, &result)) {
return result;
double guess;
if (DoubleStrtod(trimmed, exponent, &guess) ||
DiyFpStrtod(trimmed, exponent, &guess)) {
return guess;
}
return old_strtod(trimmed, exponent);
return BignumStrtod(trimmed, exponent, guess);
}
} } // namespace v8::internal

2
deps/v8/src/token.h

@ -28,6 +28,8 @@
#ifndef V8_TOKEN_H_
#define V8_TOKEN_H_
#include "checks.h"
namespace v8 {
namespace internal {

36
deps/v8/src/utils.cc

@ -37,34 +37,6 @@ namespace v8 {
namespace internal {
// Implementation is from "Hacker's Delight" by Henry S. Warren, Jr.,
// figure 3-3, page 48, where the function is called clp2.
uint32_t RoundUpToPowerOf2(uint32_t x) {
ASSERT(x <= 0x80000000u);
x = x - 1;
x = x | (x >> 1);
x = x | (x >> 2);
x = x | (x >> 4);
x = x | (x >> 8);
x = x | (x >> 16);
return x + 1;
}
// Thomas Wang, Integer Hash Functions.
// http://www.concentric.net/~Ttwang/tech/inthash.htm
uint32_t ComputeIntegerHash(uint32_t key) {
uint32_t hash = key;
hash = ~hash + (hash << 15); // hash = (hash << 15) - hash - 1;
hash = hash ^ (hash >> 12);
hash = hash + (hash << 2);
hash = hash ^ (hash >> 4);
hash = hash * 2057; // hash = (hash + (hash << 3)) + (hash << 11);
hash = hash ^ (hash >> 16);
return hash;
}
void PrintF(const char* format, ...) {
va_list arguments;
va_start(arguments, format);
@ -274,12 +246,4 @@ char* StringBuilder::Finalize() {
}
int TenToThe(int exponent) {
ASSERT(exponent <= 9);
ASSERT(exponent >= 1);
int answer = 10;
for (int i = 1; i < exponent; i++) answer *= 10;
return answer;
}
} } // namespace v8::internal

315
deps/v8/src/utils.h

@ -31,6 +31,8 @@
#include <stdlib.h>
#include <string.h>
#include "checks.h"
namespace v8 {
namespace internal {
@ -142,7 +144,19 @@ static int PointerValueCompare(const T* a, const T* b) {
// Returns the smallest power of two which is >= x. If you pass in a
// number that is already a power of two, it is returned as is.
uint32_t RoundUpToPowerOf2(uint32_t x);
// Implementation is from "Hacker's Delight" by Henry S. Warren, Jr.,
// figure 3-3, page 48, where the function is called clp2.
static inline uint32_t RoundUpToPowerOf2(uint32_t x) {
ASSERT(x <= 0x80000000u);
x = x - 1;
x = x | (x >> 1);
x = x | (x >> 2);
x = x | (x >> 4);
x = x | (x >> 8);
x = x | (x >> 16);
return x + 1;
}
template <typename T>
@ -216,65 +230,18 @@ class BitField {
// ----------------------------------------------------------------------------
// Hash function.
uint32_t ComputeIntegerHash(uint32_t key);
// ----------------------------------------------------------------------------
// I/O support.
#if __GNUC__ >= 4
// On gcc we can ask the compiler to check the types of %d-style format
// specifiers and their associated arguments. TODO(erikcorry) fix this
// so it works on MacOSX.
#if defined(__MACH__) && defined(__APPLE__)
#define PRINTF_CHECKING
#else // MacOsX.
#define PRINTF_CHECKING __attribute__ ((format (printf, 1, 2)))
#endif
#else
#define PRINTF_CHECKING
#endif
// Our version of printf().
void PRINTF_CHECKING PrintF(const char* format, ...);
// Our version of fflush.
void Flush();
// Read a line of characters after printing the prompt to stdout. The resulting
// char* needs to be disposed off with DeleteArray by the caller.
char* ReadLine(const char* prompt);
// Read and return the raw bytes in a file. the size of the buffer is returned
// in size.
// The returned buffer must be freed by the caller.
byte* ReadBytes(const char* filename, int* size, bool verbose = true);
// Write size chars from str to the file given by filename.
// The file is overwritten. Returns the number of chars written.
int WriteChars(const char* filename,
const char* str,
int size,
bool verbose = true);
// Write size bytes to the file given by filename.
// The file is overwritten. Returns the number of bytes written.
int WriteBytes(const char* filename,
const byte* bytes,
int size,
bool verbose = true);
// Write the C code
// const char* <varname> = "<str>";
// const int <varname>_len = <len>;
// to the file given by filename. Only the first len chars are written.
int WriteAsCFile(const char* filename, const char* varname,
const char* str, int size, bool verbose = true);
// Thomas Wang, Integer Hash Functions.
// http://www.concentric.net/~Ttwang/tech/inthash.htm
static inline uint32_t ComputeIntegerHash(uint32_t key) {
uint32_t hash = key;
hash = ~hash + (hash << 15); // hash = (hash << 15) - hash - 1;
hash = hash ^ (hash >> 12);
hash = hash + (hash << 2);
hash = hash ^ (hash >> 4);
hash = hash * 2057; // hash = (hash + (hash << 3)) + (hash << 11);
hash = hash ^ (hash >> 16);
return hash;
}
// ----------------------------------------------------------------------------
@ -416,23 +383,6 @@ class Vector {
};
// A temporary assignment sets a (non-local) variable to a value on
// construction and resets it the value on destruction.
template <typename T>
class TempAssign {
public:
TempAssign(T* var, T value): var_(var), old_value_(*var) {
*var = value;
}
~TempAssign() { *var_ = old_value_; }
private:
T* var_;
T old_value_;
};
template <typename T, int kSize>
class EmbeddedVector : public Vector<T> {
public:
@ -484,13 +434,6 @@ inline Vector<char> MutableCStrVector(char* data, int max) {
return Vector<char>(data, (length < max) ? length : max);
}
template <typename T>
inline Vector< Handle<Object> > HandleVector(v8::internal::Handle<T>* elms,
int length) {
return Vector< Handle<Object> >(
reinterpret_cast<v8::internal::Handle<Object>*>(elms), length);
}
/*
* A class that collects values into a backing store.
@ -699,156 +642,6 @@ class SequenceCollector : public Collector<T, growth_factor, max_growth> {
};
// Simple support to read a file into a 0-terminated C-string.
// The returned buffer must be freed by the caller.
// On return, *exits tells whether the file existed.
Vector<const char> ReadFile(const char* filename,
bool* exists,
bool verbose = true);
// Simple wrapper that allows an ExternalString to refer to a
// Vector<const char>. Doesn't assume ownership of the data.
class AsciiStringAdapter: public v8::String::ExternalAsciiStringResource {
public:
explicit AsciiStringAdapter(Vector<const char> data) : data_(data) {}
virtual const char* data() const { return data_.start(); }
virtual size_t length() const { return data_.length(); }
private:
Vector<const char> data_;
};
// Helper class for building result strings in a character buffer. The
// purpose of the class is to use safe operations that checks the
// buffer bounds on all operations in debug mode.
class StringBuilder {
public:
// Create a string builder with a buffer of the given size. The
// buffer is allocated through NewArray<char> and must be
// deallocated by the caller of Finalize().
explicit StringBuilder(int size);
StringBuilder(char* buffer, int size)
: buffer_(buffer, size), position_(0) { }
~StringBuilder() { if (!is_finalized()) Finalize(); }
int size() const { return buffer_.length(); }
// Get the current position in the builder.
int position() const {
ASSERT(!is_finalized());
return position_;
}
// Reset the position.
void Reset() { position_ = 0; }
// Add a single character to the builder. It is not allowed to add
// 0-characters; use the Finalize() method to terminate the string
// instead.
void AddCharacter(char c) {
ASSERT(c != '\0');
ASSERT(!is_finalized() && position_ < buffer_.length());
buffer_[position_++] = c;
}
// Add an entire string to the builder. Uses strlen() internally to
// compute the length of the input string.
void AddString(const char* s);
// Add the first 'n' characters of the given string 's' to the
// builder. The input string must have enough characters.
void AddSubstring(const char* s, int n);
// Add formatted contents to the builder just like printf().
void AddFormatted(const char* format, ...);
// Add character padding to the builder. If count is non-positive,
// nothing is added to the builder.
void AddPadding(char c, int count);
// Finalize the string by 0-terminating it and returning the buffer.
char* Finalize();
private:
Vector<char> buffer_;
int position_;
bool is_finalized() const { return position_ < 0; }
DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder);
};
// Custom memcpy implementation for platforms where the standard version
// may not be good enough.
// TODO(lrn): Check whether some IA32 platforms should be excluded.
#if defined(V8_TARGET_ARCH_IA32)
// TODO(lrn): Extend to other platforms as needed.
typedef void (*MemCopyFunction)(void* dest, const void* src, size_t size);
// Implemented in codegen-<arch>.cc.
MemCopyFunction CreateMemCopyFunction();
// Copy memory area to disjoint memory area.
static inline void MemCopy(void* dest, const void* src, size_t size) {
static MemCopyFunction memcopy = CreateMemCopyFunction();
(*memcopy)(dest, src, size);
#ifdef DEBUG
CHECK_EQ(0, memcmp(dest, src, size));
#endif
}
// Limit below which the extra overhead of the MemCopy function is likely
// to outweigh the benefits of faster copying.
// TODO(lrn): Try to find a more precise value.
static const int kMinComplexMemCopy = 64;
#else // V8_TARGET_ARCH_IA32
static inline void MemCopy(void* dest, const void* src, size_t size) {
memcpy(dest, src, size);
}
static const int kMinComplexMemCopy = 256;
#endif // V8_TARGET_ARCH_IA32
// Copy from ASCII/16bit chars to ASCII/16bit chars.
template <typename sourcechar, typename sinkchar>
static inline void CopyChars(sinkchar* dest, const sourcechar* src, int chars) {
sinkchar* limit = dest + chars;
#ifdef V8_HOST_CAN_READ_UNALIGNED
if (sizeof(*dest) == sizeof(*src)) {
if (chars >= static_cast<int>(kMinComplexMemCopy / sizeof(*dest))) {
MemCopy(dest, src, chars * sizeof(*dest));
return;
}
// Number of characters in a uintptr_t.
static const int kStepSize = sizeof(uintptr_t) / sizeof(*dest); // NOLINT
while (dest <= limit - kStepSize) {
*reinterpret_cast<uintptr_t*>(dest) =
*reinterpret_cast<const uintptr_t*>(src);
dest += kStepSize;
src += kStepSize;
}
}
#endif
while (dest < limit) {
*dest++ = static_cast<sinkchar>(*src++);
}
}
// Compare ASCII/16bit chars to ASCII/16bit chars.
template <typename lchar, typename rchar>
static inline int CompareChars(const lchar* lhs, const rchar* rhs, int chars) {
@ -877,54 +670,14 @@ static inline int CompareChars(const lchar* lhs, const rchar* rhs, int chars) {
}
template <typename T>
static inline void MemsetPointer(T** dest, T* value, int counter) {
#if defined(V8_HOST_ARCH_IA32)
#define STOS "stosl"
#elif defined(V8_HOST_ARCH_X64)
#define STOS "stosq"
#endif
#if defined(__GNUC__) && defined(STOS)
asm volatile(
"cld;"
"rep ; " STOS
: "+&c" (counter), "+&D" (dest)
: "a" (value)
: "memory", "cc");
#else
for (int i = 0; i < counter; i++) {
dest[i] = value;
}
#endif
#undef STOS
}
// Copies data from |src| to |dst|. The data spans MUST not overlap.
inline void CopyWords(Object** dst, Object** src, int num_words) {
ASSERT(Min(dst, src) + num_words <= Max(dst, src));
ASSERT(num_words > 0);
// Use block copying memcpy if the segment we're copying is
// enough to justify the extra call/setup overhead.
static const int kBlockCopyLimit = 16;
if (num_words >= kBlockCopyLimit) {
memcpy(dst, src, num_words * kPointerSize);
} else {
int remaining = num_words;
do {
remaining--;
*dst++ = *src++;
} while (remaining > 0);
}
}
// Calculate 10^exponent.
int TenToThe(int exponent);
static inline int TenToThe(int exponent) {
ASSERT(exponent <= 9);
ASSERT(exponent >= 1);
int answer = 10;
for (int i = 1; i < exponent; i++) answer *= 10;
return answer;
}
// The type-based aliasing rule allows the compiler to assume that pointers of

2
deps/v8/src/v8.h

@ -56,7 +56,7 @@
#include "globals.h"
#include "checks.h"
#include "allocation.h"
#include "utils.h"
#include "v8utils.h"
#include "flags.h"
// Objects & heap

301
deps/v8/src/v8utils.h

@ -0,0 +1,301 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef V8_V8UTILS_H_
#define V8_V8UTILS_H_
#include "utils.h"
namespace v8 {
namespace internal {
// ----------------------------------------------------------------------------
// I/O support.
#if __GNUC__ >= 4
// On gcc we can ask the compiler to check the types of %d-style format
// specifiers and their associated arguments. TODO(erikcorry) fix this
// so it works on MacOSX.
#if defined(__MACH__) && defined(__APPLE__)
#define PRINTF_CHECKING
#else // MacOsX.
#define PRINTF_CHECKING __attribute__ ((format (printf, 1, 2)))
#endif
#else
#define PRINTF_CHECKING
#endif
// Our version of printf().
void PRINTF_CHECKING PrintF(const char* format, ...);
// Our version of fflush.
void Flush();
// Read a line of characters after printing the prompt to stdout. The resulting
// char* needs to be disposed off with DeleteArray by the caller.
char* ReadLine(const char* prompt);
// Read and return the raw bytes in a file. the size of the buffer is returned
// in size.
// The returned buffer must be freed by the caller.
byte* ReadBytes(const char* filename, int* size, bool verbose = true);
// Write size chars from str to the file given by filename.
// The file is overwritten. Returns the number of chars written.
int WriteChars(const char* filename,
const char* str,
int size,
bool verbose = true);
// Write size bytes to the file given by filename.
// The file is overwritten. Returns the number of bytes written.
int WriteBytes(const char* filename,
const byte* bytes,
int size,
bool verbose = true);
// Write the C code
// const char* <varname> = "<str>";
// const int <varname>_len = <len>;
// to the file given by filename. Only the first len chars are written.
int WriteAsCFile(const char* filename, const char* varname,
const char* str, int size, bool verbose = true);
// Data structures
template <typename T>
inline Vector< Handle<Object> > HandleVector(v8::internal::Handle<T>* elms,
int length) {
return Vector< Handle<Object> >(
reinterpret_cast<v8::internal::Handle<Object>*>(elms), length);
}
// Memory
// Copies data from |src| to |dst|. The data spans MUST not overlap.
inline void CopyWords(Object** dst, Object** src, int num_words) {
ASSERT(Min(dst, src) + num_words <= Max(dst, src));
ASSERT(num_words > 0);
// Use block copying memcpy if the segment we're copying is
// enough to justify the extra call/setup overhead.
static const int kBlockCopyLimit = 16;
if (num_words >= kBlockCopyLimit) {
memcpy(dst, src, num_words * kPointerSize);
} else {
int remaining = num_words;
do {
remaining--;
*dst++ = *src++;
} while (remaining > 0);
}
}
template <typename T>
static inline void MemsetPointer(T** dest, T* value, int counter) {
#if defined(V8_HOST_ARCH_IA32)
#define STOS "stosl"
#elif defined(V8_HOST_ARCH_X64)
#define STOS "stosq"
#endif
#if defined(__GNUC__) && defined(STOS)
asm volatile(
"cld;"
"rep ; " STOS
: "+&c" (counter), "+&D" (dest)
: "a" (value)
: "memory", "cc");
#else
for (int i = 0; i < counter; i++) {
dest[i] = value;
}
#endif
#undef STOS
}
// Simple wrapper that allows an ExternalString to refer to a
// Vector<const char>. Doesn't assume ownership of the data.
class AsciiStringAdapter: public v8::String::ExternalAsciiStringResource {
public:
explicit AsciiStringAdapter(Vector<const char> data) : data_(data) {}
virtual const char* data() const { return data_.start(); }
virtual size_t length() const { return data_.length(); }
private:
Vector<const char> data_;
};
// Simple support to read a file into a 0-terminated C-string.
// The returned buffer must be freed by the caller.
// On return, *exits tells whether the file existed.
Vector<const char> ReadFile(const char* filename,
bool* exists,
bool verbose = true);
// Helper class for building result strings in a character buffer. The
// purpose of the class is to use safe operations that checks the
// buffer bounds on all operations in debug mode.
class StringBuilder {
public:
// Create a string builder with a buffer of the given size. The
// buffer is allocated through NewArray<char> and must be
// deallocated by the caller of Finalize().
explicit StringBuilder(int size);
StringBuilder(char* buffer, int size)
: buffer_(buffer, size), position_(0) { }
~StringBuilder() { if (!is_finalized()) Finalize(); }
int size() const { return buffer_.length(); }
// Get the current position in the builder.
int position() const {
ASSERT(!is_finalized());
return position_;
}
// Reset the position.
void Reset() { position_ = 0; }
// Add a single character to the builder. It is not allowed to add
// 0-characters; use the Finalize() method to terminate the string
// instead.
void AddCharacter(char c) {
ASSERT(c != '\0');
ASSERT(!is_finalized() && position_ < buffer_.length());
buffer_[position_++] = c;
}
// Add an entire string to the builder. Uses strlen() internally to
// compute the length of the input string.
void AddString(const char* s);
// Add the first 'n' characters of the given string 's' to the
// builder. The input string must have enough characters.
void AddSubstring(const char* s, int n);
// Add formatted contents to the builder just like printf().
void AddFormatted(const char* format, ...);
// Add character padding to the builder. If count is non-positive,
// nothing is added to the builder.
void AddPadding(char c, int count);
// Finalize the string by 0-terminating it and returning the buffer.
char* Finalize();
private:
Vector<char> buffer_;
int position_;
bool is_finalized() const { return position_ < 0; }
DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder);
};
// Custom memcpy implementation for platforms where the standard version
// may not be good enough.
#if defined(V8_TARGET_ARCH_IA32)
// The default memcpy on ia32 architectures is generally not as efficient
// as possible. (If any further ia32 platforms are introduced where the
// memcpy function is efficient, exclude them from this branch).
typedef void (*MemCopyFunction)(void* dest, const void* src, size_t size);
// Implemented in codegen-<arch>.cc.
MemCopyFunction CreateMemCopyFunction();
// Copy memory area to disjoint memory area.
static inline void MemCopy(void* dest, const void* src, size_t size) {
static MemCopyFunction memcopy = CreateMemCopyFunction();
(*memcopy)(dest, src, size);
#ifdef DEBUG
CHECK_EQ(0, memcmp(dest, src, size));
#endif
}
// Limit below which the extra overhead of the MemCopy function is likely
// to outweigh the benefits of faster copying.
static const int kMinComplexMemCopy = 64;
#else // V8_TARGET_ARCH_IA32
static inline void MemCopy(void* dest, const void* src, size_t size) {
memcpy(dest, src, size);
}
static const int kMinComplexMemCopy = 256;
#endif // V8_TARGET_ARCH_IA32
// Copy from ASCII/16bit chars to ASCII/16bit chars.
template <typename sourcechar, typename sinkchar>
static inline void CopyChars(sinkchar* dest, const sourcechar* src, int chars) {
sinkchar* limit = dest + chars;
#ifdef V8_HOST_CAN_READ_UNALIGNED
if (sizeof(*dest) == sizeof(*src)) {
if (chars >= static_cast<int>(kMinComplexMemCopy / sizeof(*dest))) {
MemCopy(dest, src, chars * sizeof(*dest));
return;
}
// Number of characters in a uintptr_t.
static const int kStepSize = sizeof(uintptr_t) / sizeof(*dest); // NOLINT
while (dest <= limit - kStepSize) {
*reinterpret_cast<uintptr_t*>(dest) =
*reinterpret_cast<const uintptr_t*>(src);
dest += kStepSize;
src += kStepSize;
}
}
#endif
while (dest < limit) {
*dest++ = static_cast<sinkchar>(*src++);
}
}
} } // namespace v8::internal
#endif // V8_V8UTILS_H_

2
deps/v8/src/version.cc

@ -34,7 +34,7 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 2
#define MINOR_VERSION 5
#define BUILD_NUMBER 3
#define BUILD_NUMBER 6
#define PATCH_LEVEL 0
#define CANDIDATE_VERSION false

54
deps/v8/src/x64/assembler-x64.cc

@ -296,7 +296,7 @@ static void InitCoverageLog();
byte* Assembler::spare_buffer_ = NULL;
Assembler::Assembler(void* buffer, int buffer_size)
: code_targets_(100) {
: code_targets_(100), positions_recorder_(this) {
if (buffer == NULL) {
// Do our own buffer management.
if (buffer_size <= kMinimalBufferSize) {
@ -337,10 +337,7 @@ Assembler::Assembler(void* buffer, int buffer_size)
reloc_info_writer.Reposition(buffer_ + buffer_size, pc_);
last_pc_ = NULL;
current_statement_position_ = RelocInfo::kNoPosition;
current_position_ = RelocInfo::kNoPosition;
written_statement_position_ = current_statement_position_;
written_position_ = current_position_;
#ifdef GENERATED_CODE_COVERAGE
InitCoverageLog();
#endif
@ -845,7 +842,7 @@ void Assembler::call(Label* L) {
void Assembler::call(Handle<Code> target, RelocInfo::Mode rmode) {
WriteRecordedPositions();
positions_recorder()->WriteRecordedPositions();
EnsureSpace ensure_space(this);
last_pc_ = pc_;
// 1110 1000 #32-bit disp.
@ -2935,14 +2932,14 @@ void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
}
void Assembler::RecordJSReturn() {
WriteRecordedPositions();
positions_recorder()->WriteRecordedPositions();
EnsureSpace ensure_space(this);
RecordRelocInfo(RelocInfo::JS_RETURN);
}
void Assembler::RecordDebugBreakSlot() {
WriteRecordedPositions();
positions_recorder()->WriteRecordedPositions();
EnsureSpace ensure_space(this);
RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
}
@ -2956,47 +2953,6 @@ void Assembler::RecordComment(const char* msg) {
}
void Assembler::RecordPosition(int pos) {
ASSERT(pos != RelocInfo::kNoPosition);
ASSERT(pos >= 0);
current_position_ = pos;
}
void Assembler::RecordStatementPosition(int pos) {
ASSERT(pos != RelocInfo::kNoPosition);
ASSERT(pos >= 0);
current_statement_position_ = pos;
}
bool Assembler::WriteRecordedPositions() {
bool written = false;
// Write the statement position if it is different from what was written last
// time.
if (current_statement_position_ != written_statement_position_) {
EnsureSpace ensure_space(this);
RecordRelocInfo(RelocInfo::STATEMENT_POSITION, current_statement_position_);
written_statement_position_ = current_statement_position_;
written = true;
}
// Write the position if it is different from what was written last time and
// also different from the written statement position.
if (current_position_ != written_position_ &&
current_position_ != written_statement_position_) {
EnsureSpace ensure_space(this);
RecordRelocInfo(RelocInfo::POSITION, current_position_);
written_position_ = current_position_;
written = true;
}
// Return whether something was written.
return written;
}
const int RelocInfo::kApplyMask = RelocInfo::kCodeTargetMask |
1 << RelocInfo::INTERNAL_REFERENCE;

15
deps/v8/src/x64/assembler-x64.h

@ -1174,13 +1174,9 @@ class Assembler : public Malloced {
// Use --debug_code to enable.
void RecordComment(const char* msg);
void RecordPosition(int pos);
void RecordStatementPosition(int pos);
bool WriteRecordedPositions();
int pc_offset() const { return static_cast<int>(pc_ - buffer_); }
int current_statement_position() const { return current_statement_position_; }
int current_position() const { return current_position_; }
PositionsRecorder* positions_recorder() { return &positions_recorder_; }
// Check if there is less than kGap bytes available in the buffer.
// If this is the case, we need to grow the buffer before emitting
@ -1404,11 +1400,8 @@ class Assembler : public Malloced {
// push-pop elimination
byte* last_pc_;
// source position information
int current_statement_position_;
int current_position_;
int written_statement_position_;
int written_position_;
PositionsRecorder positions_recorder_;
friend class PositionsRecorder;
};

82
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()->WriteRecordedPositions();
masm()->positions_recorder()->WriteRecordedPositions();
if (function_return_is_shadowed_) {
function_return_.Jump(&return_value);
} else {
@ -6564,86 +6564,6 @@ void CodeGenerator::GenerateRegExpConstructResult(ZoneList<Expression*>* args) {
}
void CodeGenerator::GenerateRegExpCloneResult(ZoneList<Expression*>* args) {
ASSERT_EQ(1, args->length());
Load(args->at(0));
Result object_result = frame_->Pop();
object_result.ToRegister(rax);
object_result.Unuse();
{
VirtualFrame::SpilledScope spilled_scope;
Label done;
__ JumpIfSmi(rax, &done);
// Load JSRegExpResult map into rdx.
// Arguments to this function should be results of calling RegExp exec,
// which is either an unmodified JSRegExpResult or null. Anything not having
// the unmodified JSRegExpResult map is returned unmodified.
// This also ensures that elements are fast.
__ movq(rdx, ContextOperand(rsi, Context::GLOBAL_INDEX));
__ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalContextOffset));
__ movq(rdx, ContextOperand(rdx, Context::REGEXP_RESULT_MAP_INDEX));
__ cmpq(rdx, FieldOperand(rax, HeapObject::kMapOffset));
__ j(not_equal, &done);
if (FLAG_debug_code) {
// Check that object really has empty properties array, as the map
// should guarantee.
__ CompareRoot(FieldOperand(rax, JSObject::kPropertiesOffset),
Heap::kEmptyFixedArrayRootIndex);
__ Check(equal, "JSRegExpResult: default map but non-empty properties.");
}
DeferredAllocateInNewSpace* allocate_fallback =
new DeferredAllocateInNewSpace(JSRegExpResult::kSize,
rbx,
rdx.bit() | rax.bit());
// All set, copy the contents to a new object.
__ AllocateInNewSpace(JSRegExpResult::kSize,
rbx,
no_reg,
no_reg,
allocate_fallback->entry_label(),
TAG_OBJECT);
__ bind(allocate_fallback->exit_label());
STATIC_ASSERT(JSRegExpResult::kSize % (2 * kPointerSize) == 0);
// There is an even number of fields, so unroll the loop once
// for efficiency.
for (int i = 0; i < JSRegExpResult::kSize; i += 2 * kPointerSize) {
STATIC_ASSERT(JSObject::kMapOffset % (2 * kPointerSize) == 0);
if (i != JSObject::kMapOffset) {
// The map was already loaded into edx.
__ movq(rdx, FieldOperand(rax, i));
}
__ movq(rcx, FieldOperand(rax, i + kPointerSize));
STATIC_ASSERT(JSObject::kElementsOffset % (2 * kPointerSize) == 0);
if (i == JSObject::kElementsOffset) {
// If the elements array isn't empty, make it copy-on-write
// before copying it.
Label empty;
__ CompareRoot(rdx, Heap::kEmptyFixedArrayRootIndex);
__ j(equal, &empty);
__ LoadRoot(kScratchRegister, Heap::kFixedCOWArrayMapRootIndex);
__ movq(FieldOperand(rdx, HeapObject::kMapOffset), kScratchRegister);
__ bind(&empty);
}
__ movq(FieldOperand(rbx, i), rdx);
__ movq(FieldOperand(rbx, i + kPointerSize), rcx);
}
__ movq(rax, rbx);
__ bind(&done);
}
frame_->Push(rax);
}
class DeferredSearchCache: public DeferredCode {
public:
DeferredSearchCache(Register dst,

2
deps/v8/src/x64/codegen-x64.h

@ -656,8 +656,6 @@ class CodeGenerator: public AstVisitor {
void GenerateRegExpConstructResult(ZoneList<Expression*>* args);
void GenerateRegExpCloneResult(ZoneList<Expression*>* args);
// Support for fast native caches.
void GenerateGetFromCache(ZoneList<Expression*>* args);

157
deps/v8/src/x64/full-codegen-x64.cc

@ -1717,12 +1717,14 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
// Code common for calls using the IC.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
}
__ Move(rcx, name);
}
__ Move(rcx, name);
// Record source position for debugger.
SetSourcePosition(expr->position());
SetSourcePosition(expr->position(), FORCED_POSITION);
// Call the IC initialization code.
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
@ -1740,13 +1742,15 @@ void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
// Code common for calls using the IC.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
}
VisitForAccumulatorValue(key);
__ movq(rcx, rax);
}
VisitForAccumulatorValue(key);
__ movq(rcx, rax);
// Record source position for debugger.
SetSourcePosition(expr->position());
SetSourcePosition(expr->position(), FORCED_POSITION);
// Call the IC initialization code.
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic = CodeGenerator::ComputeKeyedCallInitialize(arg_count,
@ -1762,11 +1766,13 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr) {
// Code common for calls using the call stub.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
}
}
// Record source position for debugger.
SetSourcePosition(expr->position());
SetSourcePosition(expr->position(), FORCED_POSITION);
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
__ CallStub(&stub);
@ -1787,37 +1793,38 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// resolve the function we need to call and the receiver of the
// call. The we call the resolved function using the given
// arguments.
VisitForStackValue(fun);
__ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot.
// Push the arguments.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
}
{ PreserveStatementPositionScope pos_scope(masm()->positions_recorder());
VisitForStackValue(fun);
__ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot.
// Push copy of the function - found below the arguments.
__ push(Operand(rsp, (arg_count + 1) * kPointerSize));
// Push the arguments.
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
}
// Push copy of the first argument or undefined if it doesn't exist.
if (arg_count > 0) {
__ push(Operand(rsp, arg_count * kPointerSize));
} else {
__ PushRoot(Heap::kUndefinedValueRootIndex);
}
// Push copy of the function - found below the arguments.
__ push(Operand(rsp, (arg_count + 1) * kPointerSize));
// Push the receiver of the enclosing function and do runtime call.
__ push(Operand(rbp, (2 + scope()->num_parameters()) * kPointerSize));
__ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
// Push copy of the first argument or undefined if it doesn't exist.
if (arg_count > 0) {
__ push(Operand(rsp, arg_count * kPointerSize));
} else {
__ PushRoot(Heap::kUndefinedValueRootIndex);
}
// The runtime call returns a pair of values in rax (function) and
// rdx (receiver). Touch up the stack with the right values.
__ movq(Operand(rsp, (arg_count + 0) * kPointerSize), rdx);
__ movq(Operand(rsp, (arg_count + 1) * kPointerSize), rax);
// Push the receiver of the enclosing function and do runtime call.
__ push(Operand(rbp, (2 + scope()->num_parameters()) * kPointerSize));
__ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
// The runtime call returns a pair of values in rax (function) and
// rdx (receiver). Touch up the stack with the right values.
__ movq(Operand(rsp, (arg_count + 0) * kPointerSize), rdx);
__ movq(Operand(rsp, (arg_count + 1) * kPointerSize), rax);
}
// Record source position for debugger.
SetSourcePosition(expr->position());
SetSourcePosition(expr->position(), FORCED_POSITION);
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
__ CallStub(&stub);
@ -1834,35 +1841,37 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// Call to a lookup slot (dynamically introduced variable).
Label slow, done;
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
NOT_INSIDE_TYPEOF,
&slow,
&done);
__ bind(&slow);
// Call the runtime to find the function to call (returned in rax)
// and the object holding it (returned in rdx).
__ push(context_register());
__ Push(var->name());
__ CallRuntime(Runtime::kLoadContextSlot, 2);
__ push(rax); // Function.
__ push(rdx); // Receiver.
// If fast case code has been generated, emit code to push the
// function and receiver and have the slow path jump around this
// code.
if (done.is_linked()) {
NearLabel call;
__ jmp(&call);
__ bind(&done);
// Push function.
__ push(rax);
// Push global receiver.
__ movq(rbx, CodeGenerator::GlobalObject());
__ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
__ bind(&call);
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
NOT_INSIDE_TYPEOF,
&slow,
&done);
__ bind(&slow);
// Call the runtime to find the function to call (returned in rax)
// and the object holding it (returned in rdx).
__ push(context_register());
__ Push(var->name());
__ CallRuntime(Runtime::kLoadContextSlot, 2);
__ push(rax); // Function.
__ push(rdx); // Receiver.
// If fast case code has been generated, emit code to push the
// function and receiver and have the slow path jump around this
// code.
if (done.is_linked()) {
NearLabel call;
__ jmp(&call);
__ bind(&done);
// Push function.
__ push(rax);
// Push global receiver.
__ movq(rbx, CodeGenerator::GlobalObject());
__ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
__ bind(&call);
}
}
EmitCallWithStub(expr);
@ -1873,18 +1882,24 @@ void FullCodeGenerator::VisitCall(Call* expr) {
Literal* key = prop->key()->AsLiteral();
if (key != NULL && key->handle()->IsSymbol()) {
// Call to a named property, use call IC.
VisitForStackValue(prop->obj());
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
VisitForStackValue(prop->obj());
}
EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
} else {
// Call to a keyed property.
// For a synthetic property use keyed load IC followed by function call,
// for a regular property use KeyedCallIC.
VisitForStackValue(prop->obj());
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
VisitForStackValue(prop->obj());
}
if (prop->is_synthetic()) {
VisitForAccumulatorValue(prop->key());
__ movq(rdx, Operand(rsp, 0));
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
VisitForAccumulatorValue(prop->key());
__ movq(rdx, Operand(rsp, 0));
}
// Record source code position for IC call.
SetSourcePosition(prop->position());
SetSourcePosition(prop->position(), FORCED_POSITION);
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
EmitCallIC(ic, RelocInfo::CODE_TARGET);
// Pop receiver.
@ -1909,7 +1924,9 @@ void FullCodeGenerator::VisitCall(Call* expr) {
loop_depth() == 0) {
lit->set_try_full_codegen(true);
}
VisitForStackValue(fun);
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
VisitForStackValue(fun);
}
// Load global receiver object.
__ movq(rbx, CodeGenerator::GlobalObject());
__ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));

1
deps/v8/src/x64/ic-x64.cc

@ -33,7 +33,6 @@
#include "ic-inl.h"
#include "runtime.h"
#include "stub-cache.h"
#include "utils.h"
namespace v8 {
namespace internal {

1
deps/v8/test/cctest/SConscript

@ -41,6 +41,7 @@ SOURCES = {
'test-alloc.cc',
'test-api.cc',
'test-ast.cc',
'test-bignum.cc',
'test-circular-queue.cc',
'test-compiler.cc',
'test-conversions.cc',

68
deps/v8/test/cctest/test-assembler-arm.cc

@ -397,4 +397,72 @@ TEST(6) {
}
}
static void TestRoundingMode(int32_t mode, double value, int expected) {
InitializeVM();
v8::HandleScope scope;
Assembler assm(NULL, 0);
__ vmrs(r1);
// Set custom FPSCR.
__ bic(r2, r1, Operand(((mode ^ 3) << 22) | 0xf));
__ orr(r2, r2, Operand(mode << 22));
__ vmsr(r2);
// Load value, convert, and move back result to r0.
__ vmov(d1, value);
__ vcvt_s32_f64(s0, d1, Assembler::FPSCRRounding, al);
__ vmov(r0, s0);
__ mov(pc, Operand(lr));
CodeDesc desc;
assm.GetCode(&desc);
Object* code = Heap::CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
Handle<Object>(Heap::undefined_value()))->ToObjectChecked();
CHECK(code->IsCode());
#ifdef DEBUG
Code::cast(code)->Print();
#endif
F1 f = FUNCTION_CAST<F1>(Code::cast(code)->entry());
int res = reinterpret_cast<int>(
CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
::printf("res = %d\n", res);
CHECK_EQ(expected, res);
}
TEST(7) {
// Test vfp rounding modes.
// See ARM DDI 0406B Page A2-29.
enum FPSCRRoungingMode {
RN, // Round to Nearest.
RP, // Round towards Plus Infinity.
RM, // Round towards Minus Infinity.
RZ // Round towards zero.
};
if (CpuFeatures::IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
TestRoundingMode(RZ, 0.5, 0);
TestRoundingMode(RZ, -0.5, 0);
TestRoundingMode(RZ, 123.7, 123);
TestRoundingMode(RZ, -123.7, -123);
TestRoundingMode(RZ, 123456.2, 123456);
TestRoundingMode(RZ, -123456.2, -123456);
TestRoundingMode(RM, 0.5, 0);
TestRoundingMode(RM, -0.5, -1);
TestRoundingMode(RM, 123.7, 123);
TestRoundingMode(RM, -123.7, -124);
TestRoundingMode(RM, 123456.2, 123456);
TestRoundingMode(RM, -123456.2, -123457);
}
}
#undef __

1502
deps/v8/test/cctest/test-bignum.cc

File diff suppressed because it is too large

45
deps/v8/test/cctest/test-debug.cc

@ -902,6 +902,7 @@ static void DebugEventBreak(v8::DebugEvent event,
// Debug event handler which re-issues a debug break until a limit has been
// reached.
int max_break_point_hit_count = 0;
bool terminate_after_max_break_point_hit = false;
static void DebugEventBreakMax(v8::DebugEvent event,
v8::Handle<v8::Object> exec_state,
v8::Handle<v8::Object> event_data,
@ -909,12 +910,17 @@ static void DebugEventBreakMax(v8::DebugEvent event,
// When hitting a debug event listener there must be a break set.
CHECK_NE(v8::internal::Debug::break_id(), 0);
if (event == v8::Break && break_point_hit_count < max_break_point_hit_count) {
// Count the number of breaks.
break_point_hit_count++;
if (event == v8::Break) {
if (break_point_hit_count < max_break_point_hit_count) {
// Count the number of breaks.
break_point_hit_count++;
// Set the break flag again to come back here as soon as possible.
v8::Debug::DebugBreak();
// Set the break flag again to come back here as soon as possible.
v8::Debug::DebugBreak();
} else if (terminate_after_max_break_point_hit) {
// Terminate execution after the last break if requested.
v8::V8::TerminateExecution();
}
}
}
@ -6892,4 +6898,33 @@ TEST(DebugEventBreakData) {
CheckDebuggerUnloaded();
}
// Test that setting the terminate execution flag during debug break processing.
TEST(DebugBreakLoop) {
v8::HandleScope scope;
DebugLocalContext env;
// Receive 100 breaks and terminate.
max_break_point_hit_count = 100;
terminate_after_max_break_point_hit = true;
// Register a debug event listener which sets the break flag and counts.
v8::Debug::SetDebugEventListener(DebugEventBreakMax);
// Function with infinite loop.
CompileRun("function f() { while (true) { } }");
// Set the debug break to enter the debugger as soon as possible.
v8::Debug::DebugBreak();
// Call function with infinite loop.
CompileRun("f();");
CHECK_EQ(100, break_point_hit_count);
// Get rid of the debug event listener.
v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
}
#endif // ENABLE_DEBUGGER_SUPPORT

16
deps/v8/test/cctest/test-double.cc

@ -202,3 +202,19 @@ TEST(NormalizedBoundaries) {
CHECK(diy_fp.f() - boundary_minus.f() == boundary_plus.f() - diy_fp.f());
CHECK((1 << 10) == diy_fp.f() - boundary_minus.f()); // NOLINT
}
TEST(NextDouble) {
CHECK_EQ(4e-324, Double(0.0).NextDouble());
CHECK_EQ(0.0, Double(-0.0).NextDouble());
CHECK_EQ(-0.0, Double(-4e-324).NextDouble());
Double d0(-4e-324);
Double d1(d0.NextDouble());
Double d2(d1.NextDouble());
CHECK_EQ(-0.0, d1.value());
CHECK_EQ(0.0, d2.value());
CHECK_EQ(4e-324, d2.NextDouble());
CHECK_EQ(-1.7976931348623157e308, Double(-V8_INFINITY).NextDouble());
CHECK_EQ(V8_INFINITY,
Double(V8_2PART_UINT64_C(0x7fefffff, ffffffff)).NextDouble());
}

35
deps/v8/test/cctest/test-heap-profiler.cc

@ -388,14 +388,10 @@ namespace {
class NamedEntriesDetector {
public:
NamedEntriesDetector()
: has_A1(false), has_B1(false), has_C1(false),
has_A2(false), has_B2(false), has_C2(false) {
: has_A2(false), has_B2(false), has_C2(false) {
}
void Apply(i::HeapEntry** entry_ptr) {
if (IsReachableNodeWithName(*entry_ptr, "A1")) has_A1 = true;
if (IsReachableNodeWithName(*entry_ptr, "B1")) has_B1 = true;
if (IsReachableNodeWithName(*entry_ptr, "C1")) has_C1 = true;
if (IsReachableNodeWithName(*entry_ptr, "A2")) has_A2 = true;
if (IsReachableNodeWithName(*entry_ptr, "B2")) has_B2 = true;
if (IsReachableNodeWithName(*entry_ptr, "C2")) has_C2 = true;
@ -405,9 +401,6 @@ class NamedEntriesDetector {
return strcmp(name, entry->name()) == 0 && entry->painted_reachable();
}
bool has_A1;
bool has_B1;
bool has_C1;
bool has_A2;
bool has_B2;
bool has_C2;
@ -464,21 +457,7 @@ static bool HasString(const v8::HeapGraphNode* node, const char* contents) {
TEST(HeapSnapshot) {
v8::HandleScope scope;
v8::Handle<v8::String> token1 = v8::String::New("token1");
LocalContext env1;
env1->SetSecurityToken(token1);
CompileRun(
"function A1() {}\n"
"function B1(x) { this.x = x; }\n"
"function C1(x) { this.x1 = x; this.x2 = x; }\n"
"var a1 = new A1();\n"
"var b1_1 = new B1(a1), b1_2 = new B1(a1);\n"
"var c1 = new C1(a1);");
v8::Handle<v8::String> token2 = v8::String::New("token2");
LocalContext env2;
env2->SetSecurityToken(token2);
CompileRun(
"function A2() {}\n"
@ -498,14 +477,7 @@ TEST(HeapSnapshot) {
const_cast<i::HeapEntry*>(
reinterpret_cast<const i::HeapEntry*>(global_env2))->PaintAllReachable();
// Verify, that JS global object of env2 doesn't have '..1'
// properties, but has '..2' properties.
CHECK_EQ(NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "a1"));
CHECK_EQ(
NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "b1_1"));
CHECK_EQ(
NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "b1_2"));
CHECK_EQ(NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "c1"));
// Verify, that JS global object of env2 has '..2' properties.
const v8::HeapGraphNode* a2_node =
GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "a2");
CHECK_NE(NULL, a2_node);
@ -518,9 +490,6 @@ TEST(HeapSnapshot) {
// Verify that anything related to '[ABC]1' is not reachable.
NamedEntriesDetector det;
i_snapshot_env2->IterateEntries(&det);
CHECK(!det.has_A1);
CHECK(!det.has_B1);
CHECK(!det.has_C1);
CHECK(det.has_A2);
CHECK(det.has_B2);
CHECK(det.has_C2);

4
deps/v8/test/cctest/test-mark-compact.cc

@ -75,7 +75,7 @@ TEST(Promotion) {
// from new space.
FLAG_gc_global = true;
FLAG_always_compact = true;
Heap::ConfigureHeap(2*256*KB, 4*MB);
Heap::ConfigureHeap(2*256*KB, 4*MB, 4*MB);
InitializeVM();
@ -101,7 +101,7 @@ TEST(Promotion) {
TEST(NoPromotion) {
Heap::ConfigureHeap(2*256*KB, 4*MB);
Heap::ConfigureHeap(2*256*KB, 4*MB, 4*MB);
// Test the situation that some objects in new space are promoted to
// the old space

33
deps/v8/test/cctest/test-parsing.cc

@ -26,6 +26,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdlib.h>
#include <stdio.h>
#include "v8.h"
@ -34,7 +35,8 @@
#include "parser.h"
#include "utils.h"
#include "execution.h"
#include "scanner.h"
#include "preparser.h"
#include "cctest.h"
namespace i = ::v8::internal;
@ -239,3 +241,32 @@ 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());
}
}

6
deps/v8/test/cctest/test-spaces.cc

@ -91,7 +91,7 @@ TEST(Page) {
TEST(MemoryAllocator) {
CHECK(Heap::ConfigureHeapDefault());
CHECK(MemoryAllocator::Setup(Heap::MaxReserved()));
CHECK(MemoryAllocator::Setup(Heap::MaxReserved(), Heap::MaxExecutableSize()));
OldSpace faked_space(Heap::MaxReserved(), OLD_POINTER_SPACE, NOT_EXECUTABLE);
int total_pages = 0;
@ -147,7 +147,7 @@ TEST(MemoryAllocator) {
TEST(NewSpace) {
CHECK(Heap::ConfigureHeapDefault());
CHECK(MemoryAllocator::Setup(Heap::MaxReserved()));
CHECK(MemoryAllocator::Setup(Heap::MaxReserved(), Heap::MaxExecutableSize()));
NewSpace new_space;
@ -172,7 +172,7 @@ TEST(NewSpace) {
TEST(OldSpace) {
CHECK(Heap::ConfigureHeapDefault());
CHECK(MemoryAllocator::Setup(Heap::MaxReserved()));
CHECK(MemoryAllocator::Setup(Heap::MaxReserved(), Heap::MaxExecutableSize()));
OldSpace* s = new OldSpace(Heap::MaxOldGenerationSize(),
OLD_POINTER_SPACE,

164
deps/v8/test/cctest/test-strtod.cc

@ -4,7 +4,10 @@
#include "v8.h"
#include "bignum.h"
#include "cctest.h"
#include "diy-fp.h"
#include "double.h"
#include "strtod.h"
using namespace v8::internal;
@ -202,11 +205,14 @@ TEST(Strtod) {
CHECK_EQ(1.7976931348623158E+308, StrtodChar("17976931348623158", 292));
CHECK_EQ(V8_INFINITY, StrtodChar("17976931348623159", 292));
// The following number is the result of 89255.0/1e-22. Both floating-point
// The following number is the result of 89255.0/1e22. Both floating-point
// numbers can be accurately represented with doubles. However on Linux,x86
// the floating-point stack is set to 80bits and the double-rounding
// introduces an error.
CHECK_EQ(89255e-22, StrtodChar("89255", -22));
// Some random values.
CHECK_EQ(358416272e-33, StrtodChar("358416272", -33));
CHECK_EQ(104110013277974872254e-225,
StrtodChar("104110013277974872254", -225));
@ -252,4 +258,160 @@ 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));
}
}
}

33
deps/v8/test/mjsunit/regress/regress-927.js

@ -0,0 +1,33 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
function a1() {
var a2 = -1756315459;
return ((((a2 & a2) ^ 1) * a2) << -10);
}
assertEquals(a1(), -2147483648);

95
deps/v8/test/mjsunit/regress/regress-conditional-position.js

@ -0,0 +1,95 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --always-full-compiler
var functionToCatch;
var lineNumber;
function catchLineNumber () {
var x = {};
Error.prepareStackTrace = function (error, stackTrace) {
stackTrace.some(function (frame) {
if (frame.getFunction() == functionToCatch) {
lineNumber = frame.getLineNumber();
return true;
}
return false;
});
return lineNumber;
};
Error.captureStackTrace(x);
return x.stack;
}
function log() {
catchLineNumber();
}
function foo() {}
function test1() {
log(foo() == foo()
? 'a'
: 'b');
}
function test2() {
var o = { foo: function () {}}
log(o.foo() == o.foo()
? 'a'
: 'b');
}
function test3() {
var o = { log: log, foo: function() { } };
o.log(o.foo() == o.foo()
? 'a'
: 'b');
}
function test(f, expectedLineNumber) {
functionToCatch = f;
f();
assertEquals(expectedLineNumber, lineNumber);
}
test(test1, 58);
test(test2, 65);
test(test3, 72);
eval(test1.toString() + "//@ sourceUrl=foo");
eval(test2.toString() + "//@ sourceUrl=foo");
eval(test3.toString() + "//@ sourceUrl=foo");
test(test1, 2);
test(test2, 3);
test(test3, 3);

91
deps/v8/test/mjsunit/string-split.js

@ -27,76 +27,45 @@
expected = ["A", undefined, "B", "bold", "/", "B", "and", undefined, "CODE", "coded", "/", "CODE", ""];
result = "A<B>bold</B>and<CODE>coded</CODE>".split(/<(\/)?([^<>]+)>/);
assertArrayEquals(expected, result, 1);
assertArrayEquals(expected, result);
expected = ["a", "b"];
result = "ab".split(/a*?/);
assertArrayEquals(expected, result, 2);
expected = ["", "b"];
result = "ab".split(/a*/);
assertArrayEquals(expected, result, 3);
assertArrayEquals(["a", "b"], "ab".split(/a*?/));
expected = ["a"];
result = "ab".split(/a*?/, 1);
assertArrayEquals(expected, result, 4);
assertArrayEquals(["", "b"], "ab".split(/a*/));
expected = [""];
result = "ab".split(/a*/, 1);
assertArrayEquals(expected, result, 5);
assertArrayEquals(["a"], "ab".split(/a*?/, 1));
expected = ["as","fas","fas","f"];
result = "asdfasdfasdf".split("d");
assertArrayEquals(expected, result, 6);
assertArrayEquals([""], "ab".split(/a*/, 1));
expected = ["as","fas","fas","f"];
result = "asdfasdfasdf".split("d", -1);
assertArrayEquals(expected, result, 7);
assertArrayEquals(["as","fas","fas","f"], "asdfasdfasdf".split("d"));
expected = ["as", "fas"];
result = "asdfasdfasdf".split("d", 2);
assertArrayEquals(expected, result, 8);
assertArrayEquals(["as","fas","fas","f"], "asdfasdfasdf".split("d", -1));
expected = [];
result = "asdfasdfasdf".split("d", 0);
assertArrayEquals(expected, result, 9);
assertArrayEquals(["as", "fas"], "asdfasdfasdf".split("d", 2));
expected = ["as","fas","fas",""];
result = "asdfasdfasd".split("d");
assertArrayEquals(expected, result, 10);
assertArrayEquals([], "asdfasdfasdf".split("d", 0));
expected = [];
result = "".split("");
assertArrayEquals(expected, result, 11);
assertArrayEquals(["as","fas","fas",""], "asdfasdfasd".split("d"));
expected = [""]
result = "".split("a");
assertArrayEquals(expected, result, 12);
assertArrayEquals([], "".split(""));
expected = ["a","b"]
result = "axxb".split(/x*/);
assertArrayEquals(expected, result, 13);
assertArrayEquals([""], "".split("a"));
expected = ["a","b"]
result = "axxb".split(/x+/);
assertArrayEquals(expected, result, 14);
assertArrayEquals(["a","b"], "axxb".split(/x*/));
expected = ["a","","b"]
result = "axxb".split(/x/);
assertArrayEquals(expected, result, 15);
assertArrayEquals(["a","b"], "axxb".split(/x+/));
assertArrayEquals(["a","","b"], "axxb".split(/x/));
// This was http://b/issue?id=1151354
expected = ["div", "#id", ".class"]
result = "div#id.class".split(/(?=[#.])/);
assertArrayEquals(expected, result, 16);
assertArrayEquals(["div", "#id", ".class"], "div#id.class".split(/(?=[#.])/));
expected = ["div", "#i", "d", ".class"]
result = "div#id.class".split(/(?=[d#.])/);
assertArrayEquals(expected, result, 17);
assertArrayEquals(["div", "#i", "d", ".class"], "div#id.class".split(/(?=[d#.])/));
assertArrayEquals(["a", "b", "c"], "abc".split(/(?=.)/));
expected = ["a", "b", "c"]
result = "abc".split(/(?=.)/);
assertArrayEquals(expected, result, 18);
/* "ab".split(/((?=.))/)
*
@ -108,19 +77,23 @@ assertArrayEquals(expected, result, 18);
*
* Opera seems to have this right. The others make no sense.
*/
expected = ["a", "", "b"]
result = "ab".split(/((?=.))/);
assertArrayEquals(expected, result, 19);
assertArrayEquals(["a", "", "b"], "ab".split(/((?=.))/));
/* "ab".split(/(?=)/)
*
* KJS: a,b
* SM: ab
* IE: a,b
* Opera: a,b
* Opera: a,bb
* V8: a,b
*/
expected = ["a", "b"]
result = "ab".split(/(?=)/);
assertArrayEquals(expected, result, 20);
assertArrayEquals(["a", "b"], "ab".split(/(?=)/));
// For issue http://code.google.com/p/v8/issues/detail?id=924
// Splitting the empty string is a special case.
assertEquals([""], ''.split());
assertEquals([""], ''.split(/./));
assertEquals([], ''.split(/.?/));
assertEquals([], ''.split(/.??/));
assertEquals([], ''.split(/()()/));

4
deps/v8/tools/gyp/v8.gyp

@ -280,6 +280,8 @@
'../../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',
@ -426,6 +428,8 @@
'../../src/rewriter.h',
'../../src/runtime.cc',
'../../src/runtime.h',
'../../src/scanner-base.cc',
'../../src/scanner-base.h',
'../../src/scanner.cc',
'../../src/scanner.h',
'../../src/scopeinfo.cc',

2
deps/v8/tools/presubmit.py

@ -195,7 +195,7 @@ class CppLintProcessor(SourceFileProcessor):
or (name in CppLintProcessor.IGNORE_LINT))
def GetPathsToSearch(self):
return ['src', 'public', 'samples', join('test', 'cctest')]
return ['src', 'include', 'samples', join('test', 'cctest')]
def ProcessFiles(self, files, path):
good_files_cache = FileContentsCache('.cpplint-cache')

8
deps/v8/tools/v8.xcodeproj/project.pbxproj

@ -115,6 +115,7 @@
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 */; };
@ -177,6 +178,7 @@
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 */; };
@ -481,6 +483,8 @@
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>"; };
@ -943,6 +947,8 @@
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 */,
@ -1348,6 +1354,7 @@
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 */,
@ -1472,6 +1479,7 @@
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 */,

40
deps/v8/tools/visual_studio/v8_base.vcproj

@ -144,6 +144,22 @@
/>
</FileConfiguration>
</File>
<File
RelativePath="..\..\src\bignum.cc"
>
</File>
<File
RelativePath="..\..\src\bignum.h"
>
</File>
<File
RelativePath="..\..\src\bignum-dtoa.cc"
>
</File>
<File
RelativePath="..\..\src\bignum-dtoa.h"
>
</File>
<File
RelativePath="..\..\src\dtoa.cc"
>
@ -240,6 +256,22 @@
RelativePath="..\..\src\ast.h"
>
</File>
<File
RelativePath="..\..\src\bignum.cc"
>
</File>
<File
RelativePath="..\..\src\bignum.h"
>
</File>
<File
RelativePath="..\..\src\bignum-dtoa.cc"
>
</File>
<File
RelativePath="..\..\src\bignum-dtoa.h"
>
</File>
<File
RelativePath="..\..\src\bootstrapper.cc"
>
@ -881,6 +913,14 @@
RelativePath="..\..\src\runtime.h"
>
</File>
<File
RelativePath="..\..\src\scanner-base.cc"
>
</File>
<File
RelativePath="..\..\src\scanner-base.h"
>
</File>
<File
RelativePath="..\..\src\scanner.cc"
>

Loading…
Cancel
Save