Browse Source

Upgrade V8 to 2.5.7

v0.7.4-release
Ryan Dahl 14 years ago
parent
commit
cbdcc1d5f3
  1. 1
      deps/v8/AUTHORS
  2. 47
      deps/v8/ChangeLog
  3. 58
      deps/v8/include/v8.h
  4. 53
      deps/v8/include/v8stdint.h
  5. 5
      deps/v8/src/SConscript
  6. 6
      deps/v8/src/accessors.cc
  7. 18
      deps/v8/src/allocation.cc
  8. 4
      deps/v8/src/allocation.h
  9. 20
      deps/v8/src/api.cc
  10. 114
      deps/v8/src/arm/assembler-arm.cc
  11. 46
      deps/v8/src/arm/assembler-arm.h
  12. 114
      deps/v8/src/arm/codegen-arm.cc
  13. 14
      deps/v8/src/arm/codegen-arm.h
  14. 7
      deps/v8/src/arm/constants-arm.h
  15. 19
      deps/v8/src/arm/disasm-arm.cc
  16. 87
      deps/v8/src/arm/full-codegen-arm.cc
  17. 4
      deps/v8/src/arm/ic-arm.cc
  18. 26
      deps/v8/src/arm/macro-assembler-arm.cc
  19. 10
      deps/v8/src/arm/macro-assembler-arm.h
  20. 88
      deps/v8/src/arm/simulator-arm.cc
  21. 3
      deps/v8/src/arm/simulator-arm.h
  22. 139
      deps/v8/src/arm/stub-cache-arm.cc
  23. 7
      deps/v8/src/arm/virtual-frame-arm.cc
  24. 49
      deps/v8/src/assembler.cc
  25. 61
      deps/v8/src/assembler.h
  26. 655
      deps/v8/src/bignum-dtoa.cc
  27. 81
      deps/v8/src/bignum-dtoa.h
  28. 767
      deps/v8/src/bignum.cc
  29. 140
      deps/v8/src/bignum.h
  30. 4
      deps/v8/src/bootstrapper.cc
  31. 9
      deps/v8/src/checks.cc
  32. 19
      deps/v8/src/checks.h
  33. 10
      deps/v8/src/code-stubs.cc
  34. 32
      deps/v8/src/code-stubs.h
  35. 62
      deps/v8/src/codegen.cc
  36. 2
      deps/v8/src/codegen.h
  37. 1
      deps/v8/src/compiler.cc
  38. 89
      deps/v8/src/conversions.cc
  39. 17
      deps/v8/src/dateparser.h
  40. 32
      deps/v8/src/debug-debugger.js
  41. 1
      deps/v8/src/debug.cc
  42. 32
      deps/v8/src/double.h
  43. 39
      deps/v8/src/dtoa.cc
  44. 14
      deps/v8/src/dtoa.h
  45. 131
      deps/v8/src/execution.cc
  46. 26
      deps/v8/src/execution.h
  47. 141
      deps/v8/src/extensions/externalize-string-extension.cc
  48. 50
      deps/v8/src/extensions/externalize-string-extension.h
  49. 54
      deps/v8/src/extensions/gc-extension.cc
  50. 49
      deps/v8/src/extensions/gc-extension.h
  51. 1
      deps/v8/src/flag-definitions.h
  52. 17
      deps/v8/src/full-codegen.cc
  53. 7
      deps/v8/src/full-codegen.h
  54. 6
      deps/v8/src/global-handles.cc
  55. 3
      deps/v8/src/global-handles.h
  56. 432
      deps/v8/src/globals.h
  57. 4
      deps/v8/src/handles.cc
  58. 7
      deps/v8/src/heap-inl.h
  59. 4
      deps/v8/src/heap-profiler.cc
  60. 196
      deps/v8/src/heap.cc
  61. 55
      deps/v8/src/heap.h
  62. 54
      deps/v8/src/ia32/assembler-ia32.cc
  63. 17
      deps/v8/src/ia32/assembler-ia32.h
  64. 9
      deps/v8/src/ia32/code-stubs-ia32.cc
  65. 123
      deps/v8/src/ia32/codegen-ia32.cc
  66. 17
      deps/v8/src/ia32/codegen-ia32.h
  67. 78
      deps/v8/src/ia32/full-codegen-ia32.cc
  68. 1
      deps/v8/src/ia32/ic-ia32.cc
  69. 88
      deps/v8/src/ia32/macro-assembler-ia32.cc
  70. 46
      deps/v8/src/ia32/macro-assembler-ia32.h
  71. 203
      deps/v8/src/ia32/stub-cache-ia32.cc
  72. 5
      deps/v8/src/ia32/virtual-frame-ia32.cc
  73. 5
      deps/v8/src/jump-target-heavy.cc
  74. 5
      deps/v8/src/jump-target-light.cc
  75. 8
      deps/v8/src/list.h
  76. 16
      deps/v8/src/mark-compact.cc
  77. 3
      deps/v8/src/mark-compact.h
  78. 2
      deps/v8/src/objects-debug.cc
  79. 24
      deps/v8/src/objects-inl.h
  80. 8
      deps/v8/src/objects.cc
  81. 4
      deps/v8/src/objects.h
  82. 878
      deps/v8/src/parser.cc
  83. 236
      deps/v8/src/parser.h
  84. 69
      deps/v8/src/platform-linux.cc
  85. 3
      deps/v8/src/platform-win32.cc
  86. 1419
      deps/v8/src/preparser.h
  87. 1098
      deps/v8/src/prescanner.h
  88. 28
      deps/v8/src/profile-generator.cc
  89. 2
      deps/v8/src/profile-generator.h
  90. 142
      deps/v8/src/regexp.js
  91. 66
      deps/v8/src/runtime.cc
  92. 3
      deps/v8/src/runtime.h
  93. 195
      deps/v8/src/scanner-base.cc
  94. 206
      deps/v8/src/scanner-base.h
  95. 323
      deps/v8/src/scanner.cc
  96. 215
      deps/v8/src/scanner.h
  97. 4
      deps/v8/src/serialize.cc
  98. 60
      deps/v8/src/spaces.cc
  99. 32
      deps/v8/src/spaces.h
  100. 78
      deps/v8/src/string.js

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>

47
deps/v8/ChangeLog

@ -1,3 +1,50 @@
2010-11-18: Version 2.5.7
Fixed obscure evaluation order bug (issue 931).
Split the random number state between JavaScript and the private API.
Fixed performance bug causing GCs when generating stack traces on
code from very large scripts.
Fixed bug in parser that allowed (foo):42 as a labelled statement
(issue 918).
Provide more accurate results about used heap size via
GetHeapStatistics.
Allow build-time customization of the max semispace size.
Made String.prototype.split honor limit when separator is empty
(issue 929).
Added missing failure check after expecting an identifier in
preparser (Chromium issue 62639).
2010-11-10: Version 2.5.6
Added support for VFP rounding modes to the ARM simulator.
Fixed multiplication overflow bug (issue 927).
Added a limit for the amount of executable memory (issue 925).
2010-11-08: Version 2.5.5
Added more aggressive GC of external objects in near out-of-memory
situations.
Fixed a bug that gave the incorrect result for String.split called
on the empty string (issue 924).
2010-11-03: Version 2.5.4
Improved V8 VFPv3 runtime detection to address issue 914.
2010-11-01: Version 2.5.3
Fixed a bug that prevents constants from overwriting function values

58
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;
}
@ -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,7 +3251,7 @@ class V8EXPORT Locker {
/**
* An interface for exporting data from V8, using "push" model.
*/
class V8EXPORT OutputStream {
class V8EXPORT OutputStream { // NOLINT
public:
enum OutputEncoding {
kAscii = 0 // 7-bit ASCII.
@ -3291,6 +3282,8 @@ public:
namespace internal {
static const int kApiPointerSize = sizeof(void*); // NOLINT
static const int kApiIntSize = sizeof(int); // NOLINT
// Tag information for HeapObject.
const int kHeapObjectTag = 1;
@ -3326,19 +3319,19 @@ template <> struct SmiConstants<8> {
}
};
const int kSmiShiftSize = SmiConstants<sizeof(void*)>::kSmiShiftSize;
const int kSmiValueSize = SmiConstants<sizeof(void*)>::kSmiValueSize;
const int kSmiShiftSize = SmiConstants<kApiPointerSize>::kSmiShiftSize;
const int kSmiValueSize = SmiConstants<kApiPointerSize>::kSmiValueSize;
template <size_t ptr_size> struct InternalConstants;
// Internal constants for 32-bit systems.
template <> struct InternalConstants<4> {
static const int kStringResourceOffset = 3 * sizeof(void*);
static const int kStringResourceOffset = 3 * kApiPointerSize;
};
// Internal constants for 64-bit systems.
template <> struct InternalConstants<8> {
static const int kStringResourceOffset = 3 * sizeof(void*);
static const int kStringResourceOffset = 3 * kApiPointerSize;
};
/**
@ -3352,12 +3345,12 @@ class Internals {
// These values match non-compiler-dependent values defined within
// the implementation of v8.
static const int kHeapObjectMapOffset = 0;
static const int kMapInstanceTypeOffset = sizeof(void*) + sizeof(int);
static const int kMapInstanceTypeOffset = kApiPointerSize + kApiIntSize;
static const int kStringResourceOffset =
InternalConstants<sizeof(void*)>::kStringResourceOffset;
InternalConstants<kApiPointerSize>::kStringResourceOffset;
static const int kProxyProxyOffset = sizeof(void*);
static const int kJSObjectHeaderSize = 3 * sizeof(void*);
static const int kProxyProxyOffset = kApiPointerSize;
static const int kJSObjectHeaderSize = 3 * kApiPointerSize;
static const int kFullStringRepresentationMask = 0x07;
static const int kExternalTwoByteRepresentationTag = 0x02;
@ -3375,7 +3368,7 @@ class Internals {
}
static inline int SmiValue(internal::Object* value) {
return SmiConstants<sizeof(void*)>::SmiToInt(value);
return SmiConstants<kApiPointerSize>::SmiToInt(value);
}
static inline int GetInstanceType(internal::Object* obj) {
@ -3404,10 +3397,9 @@ class Internals {
uint8_t* addr = reinterpret_cast<uint8_t*>(ptr) + offset - kHeapObjectTag;
return *reinterpret_cast<T*>(addr);
}
};
}
} // namespace internal
template <class T>
@ -3567,7 +3559,7 @@ Local<Value> Object::UncheckedGetInternalField(int index) {
// If the object is a plain JSObject, which is the common case,
// we know where to find the internal fields and can return the
// value directly.
int offset = I::kJSObjectHeaderSize + (sizeof(void*) * index);
int offset = I::kJSObjectHeaderSize + (internal::kApiPointerSize * index);
O* value = I::ReadField<O*>(obj, offset);
O** result = HandleScope::CreateHandle(value);
return Local<Value>(reinterpret_cast<Value*>(result));
@ -3603,7 +3595,7 @@ void* Object::GetPointerFromInternalField(int index) {
// If the object is a plain JSObject, which is the common case,
// we know where to find the internal fields and can return the
// value directly.
int offset = I::kJSObjectHeaderSize + (sizeof(void*) * index);
int offset = I::kJSObjectHeaderSize + (internal::kApiPointerSize * index);
O* value = I::ReadField<O*>(obj, offset);
return I::GetExternalPointer(value);
}

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_

5
deps/v8/src/SConscript

@ -40,6 +40,8 @@ SOURCES = {
api.cc
assembler.cc
ast.cc
bignum.cc
bignum-dtoa.cc
bootstrapper.cc
builtins.cc
cached-powers.cc
@ -95,6 +97,7 @@ SOURCES = {
register-allocator.cc
rewriter.cc
runtime.cc
scanner-base.cc
scanner.cc
scopeinfo.cc
scopes.cc
@ -117,6 +120,8 @@ SOURCES = {
version.cc
virtual-frame.cc
zone.cc
extensions/gc-extension.cc
extensions/externalize-string-extension.cc
"""),
'arch:arm': Split("""
jump-target-light.cc

6
deps/v8/src/accessors.cc

@ -316,8 +316,10 @@ MaybeObject* Accessors::ScriptGetLineEnds(Object* object, void*) {
InitScriptLineEnds(script);
ASSERT(script->line_ends()->IsFixedArray());
Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
Handle<FixedArray> copy = Factory::CopyFixedArray(line_ends);
Handle<JSArray> js_array = Factory::NewJSArrayWithElements(copy);
// We do not want anyone to modify this array from JS.
ASSERT(*line_ends == Heap::empty_fixed_array() ||
line_ends->map() == Heap::fixed_cow_array_map());
Handle<JSArray> js_array = Factory::NewJSArrayWithElements(line_ends);
return *js_array;
}

18
deps/v8/src/allocation.cc

@ -27,16 +27,21 @@
#include <stdlib.h>
#include "v8.h"
#include "../include/v8stdint.h"
#include "globals.h"
#include "checks.h"
#include "allocation.h"
#include "utils.h"
namespace v8 {
namespace internal {
void* Malloced::New(size_t size) {
ASSERT(NativeAllocationChecker::allocation_allowed());
void* result = malloc(size);
if (result == NULL) V8::FatalProcessOutOfMemory("Malloced operator new");
if (result == NULL) {
v8::internal::FatalProcessOutOfMemory("Malloced operator new");
}
return result;
}
@ -47,7 +52,7 @@ void Malloced::Delete(void* p) {
void Malloced::FatalProcessOutOfMemory() {
V8::FatalProcessOutOfMemory("Out of memory");
v8::internal::FatalProcessOutOfMemory("Out of memory");
}
@ -82,7 +87,7 @@ void AllStatic::operator delete(void* p) {
char* StrDup(const char* str) {
int length = StrLength(str);
char* result = NewArray<char>(length + 1);
memcpy(result, str, length * kCharSize);
memcpy(result, str, length);
result[length] = '\0';
return result;
}
@ -92,7 +97,7 @@ char* StrNDup(const char* str, int n) {
int length = StrLength(str);
if (n < length) length = n;
char* result = NewArray<char>(length + 1);
memcpy(result, str, length * kCharSize);
memcpy(result, str, length);
result[length] = '\0';
return result;
}
@ -124,6 +129,7 @@ void* PreallocatedStorage::New(size_t size) {
}
ASSERT(free_list_.next_ != &free_list_);
ASSERT(free_list_.previous_ != &free_list_);
size = (size + kPointerSize - 1) & ~(kPointerSize - 1);
// Search for exact fit.
for (PreallocatedStorage* storage = free_list_.next_;

4
deps/v8/src/allocation.h

@ -31,6 +31,10 @@
namespace v8 {
namespace internal {
// Called when allocation routines fail to allocate.
// This function should not return, but should terminate the current
// processing.
void FatalProcessOutOfMemory(const char* message);
// A class that controls whether allocation is allowed. This is for
// the C++ heap only!

20
deps/v8/src/api.cc

@ -43,7 +43,6 @@
#include "serialize.h"
#include "snapshot.h"
#include "top.h"
#include "utils.h"
#include "v8threads.h"
#include "version.h"
@ -116,7 +115,6 @@ static void DefaultFatalErrorHandler(const char* location,
}
static FatalErrorCallback& GetFatalErrorHandler() {
if (exception_behavior == NULL) {
exception_behavior = DefaultFatalErrorHandler;
@ -125,6 +123,10 @@ static FatalErrorCallback& GetFatalErrorHandler() {
}
void i::FatalProcessOutOfMemory(const char* location) {
i::V8::FatalProcessOutOfMemory(location, false);
}
// When V8 cannot allocated memory FatalProcessOutOfMemory is called.
// The default fatal error handler is called and execution is stopped.
@ -394,14 +396,18 @@ v8::Handle<Boolean> False() {
ResourceConstraints::ResourceConstraints()
: max_young_space_size_(0),
max_old_space_size_(0),
max_executable_size_(0),
stack_limit_(NULL) { }
bool SetResourceConstraints(ResourceConstraints* constraints) {
int young_space_size = constraints->max_young_space_size();
int old_gen_size = constraints->max_old_space_size();
if (young_space_size != 0 || old_gen_size != 0) {
bool result = i::Heap::ConfigureHeap(young_space_size / 2, old_gen_size);
int max_executable_size = constraints->max_executable_size();
if (young_space_size != 0 || old_gen_size != 0 || max_executable_size != 0) {
bool result = i::Heap::ConfigureHeap(young_space_size / 2,
old_gen_size,
max_executable_size);
if (!result) return false;
}
if (constraints->stack_limit() != NULL) {
@ -3260,11 +3266,15 @@ bool v8::V8::Dispose() {
}
HeapStatistics::HeapStatistics(): total_heap_size_(0), used_heap_size_(0) { }
HeapStatistics::HeapStatistics(): total_heap_size_(0),
total_heap_size_executable_(0),
used_heap_size_(0) { }
void v8::V8::GetHeapStatistics(HeapStatistics* heap_statistics) {
heap_statistics->set_total_heap_size(i::Heap::CommittedMemory());
heap_statistics->set_total_heap_size_executable(
i::Heap::CommittedMemoryExecutable());
heap_statistics->set_used_heap_size(i::Heap::SizeOfObjects());
}

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");

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

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

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

@ -43,6 +43,7 @@
#include "register-allocator-inl.h"
#include "runtime.h"
#include "scopes.h"
#include "stub-cache.h"
#include "virtual-frame-inl.h"
#include "virtual-frame-arm-inl.h"
@ -557,7 +558,7 @@ void CodeGenerator::Load(Expression* expr) {
void CodeGenerator::LoadGlobal() {
Register reg = frame_->GetTOSRegister();
__ ldr(reg, GlobalObject());
__ ldr(reg, GlobalObjectOperand());
frame_->EmitPush(reg);
}
@ -1891,18 +1892,15 @@ void CodeGenerator::CheckStack() {
frame_->SpillAll();
Comment cmnt(masm_, "[ check stack");
__ LoadRoot(ip, Heap::kStackLimitRootIndex);
// Put the lr setup instruction in the delay slot. kInstrSize is added to
// the implicit 8 byte offset that always applies to operations with pc and
// gives a return address 12 bytes down.
masm_->add(lr, pc, Operand(Assembler::kInstrSize));
masm_->cmp(sp, Operand(ip));
StackCheckStub stub;
// Call the stub if lower.
masm_->mov(pc,
masm_->mov(ip,
Operand(reinterpret_cast<intptr_t>(stub.GetCode().location()),
RelocInfo::CODE_TARGET),
LeaveCC,
lo);
masm_->Call(ip, lo);
}
@ -4232,7 +4230,7 @@ void CodeGenerator::VisitCall(Call* node) {
// Setup the name register and call the IC initialization code.
__ mov(r2, Operand(var->name()));
InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> stub = ComputeCallInitialize(arg_count, in_loop);
Handle<Code> stub = StubCache::ComputeCallInitialize(arg_count, in_loop);
CodeForSourcePosition(node->position());
frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET_CONTEXT,
arg_count + 1);
@ -4326,7 +4324,8 @@ void CodeGenerator::VisitCall(Call* node) {
// Set the name register and call the IC initialization code.
__ mov(r2, Operand(name));
InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> stub = ComputeCallInitialize(arg_count, in_loop);
Handle<Code> stub =
StubCache::ComputeCallInitialize(arg_count, in_loop);
CodeForSourcePosition(node->position());
frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1);
__ ldr(cp, frame_->Context());
@ -4337,9 +4336,12 @@ void CodeGenerator::VisitCall(Call* node) {
// -------------------------------------------
// JavaScript example: 'array[index](1, 2, 3)'
// -------------------------------------------
// Load the receiver and name of the function.
Load(property->obj());
if (property->is_synthetic()) {
Load(property->key());
if (property->is_synthetic()) {
EmitKeyedLoad();
// Put the function below the receiver.
// Use the global receiver.
@ -4349,21 +4351,28 @@ void CodeGenerator::VisitCall(Call* node) {
CallWithArguments(args, RECEIVER_MIGHT_BE_VALUE, node->position());
frame_->EmitPush(r0);
} else {
// Swap the name of the function and the receiver on the stack to follow
// the calling convention for call ICs.
Register key = frame_->PopToRegister();
Register receiver = frame_->PopToRegister(key);
frame_->EmitPush(key);
frame_->EmitPush(receiver);
// Load the arguments.
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
Load(args->at(i));
}
// Set the name register and call the IC initialization code.
Load(property->key());
frame_->SpillAll();
frame_->EmitPop(r2); // Function name.
// Load the key into r2 and call the IC initialization code.
InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> stub = ComputeKeyedCallInitialize(arg_count, in_loop);
Handle<Code> stub =
StubCache::ComputeKeyedCallInitialize(arg_count, in_loop);
CodeForSourcePosition(node->position());
frame_->SpillAll();
__ ldr(r2, frame_->ElementAt(arg_count + 1));
frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1);
frame_->Drop(); // Drop the key still on the stack.
__ ldr(cp, frame_->Context());
frame_->EmitPush(r0);
}
@ -5135,11 +5144,11 @@ class DeferredIsStringWrapperSafeForDefaultValueOf : public DeferredCode {
__ b(eq, &false_result);
__ ldr(scratch1_, FieldMemOperand(scratch1_, HeapObject::kMapOffset));
__ ldr(scratch2_,
CodeGenerator::ContextOperand(cp, Context::GLOBAL_INDEX));
ContextOperand(cp, Context::GLOBAL_INDEX));
__ ldr(scratch2_,
FieldMemOperand(scratch2_, GlobalObject::kGlobalContextOffset));
__ ldr(scratch2_,
CodeGenerator::ContextOperand(
ContextOperand(
scratch2_, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
__ cmp(scratch1_, scratch2_);
__ b(ne, &false_result);
@ -5496,73 +5505,6 @@ void CodeGenerator::GenerateRegExpConstructResult(ZoneList<Expression*>* args) {
}
void CodeGenerator::GenerateRegExpCloneResult(ZoneList<Expression*>* args) {
ASSERT_EQ(1, args->length());
Load(args->at(0));
frame_->PopToR0();
{
VirtualFrame::SpilledScope spilled_scope(frame_);
Label done;
Label call_runtime;
__ BranchOnSmi(r0, &done);
// Load JSRegExp map into r1. Check that argument object has this map.
// Arguments to this function should be results of calling RegExp exec,
// which is either an unmodified JSRegExpResult or null. Anything not having
// the unmodified JSRegExpResult map is returned unmodified.
// This also ensures that elements are fast.
__ ldr(r1, ContextOperand(cp, Context::GLOBAL_INDEX));
__ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalContextOffset));
__ ldr(r1, ContextOperand(r1, Context::REGEXP_RESULT_MAP_INDEX));
__ ldr(ip, FieldMemOperand(r0, HeapObject::kMapOffset));
__ cmp(r1, Operand(ip));
__ b(ne, &done);
if (FLAG_debug_code) {
__ LoadRoot(r2, Heap::kEmptyFixedArrayRootIndex);
__ ldr(ip, FieldMemOperand(r0, JSObject::kPropertiesOffset));
__ cmp(ip, r2);
__ Check(eq, "JSRegExpResult: default map but non-empty properties.");
}
// All set, copy the contents to a new object.
__ AllocateInNewSpace(JSRegExpResult::kSize,
r2,
r3,
r4,
&call_runtime,
NO_ALLOCATION_FLAGS);
// Store RegExpResult map as map of allocated object.
ASSERT(JSRegExpResult::kSize == 6 * kPointerSize);
// Copy all fields (map is already in r1) from (untagged) r0 to r2.
// Change map of elements array (ends up in r4) to be a FixedCOWArray.
__ bic(r0, r0, Operand(kHeapObjectTagMask));
__ ldm(ib, r0, r3.bit() | r4.bit() | r5.bit() | r6.bit() | r7.bit());
__ stm(ia, r2,
r1.bit() | r3.bit() | r4.bit() | r5.bit() | r6.bit() | r7.bit());
ASSERT(JSRegExp::kElementsOffset == 2 * kPointerSize);
// Check whether elements array is empty fixed array, and otherwise make
// it copy-on-write (it never should be empty unless someone is messing
// with the arguments to the runtime function).
__ LoadRoot(ip, Heap::kEmptyFixedArrayRootIndex);
__ add(r0, r2, Operand(kHeapObjectTag)); // Tag result and move it to r0.
__ cmp(r4, ip);
__ b(eq, &done);
__ LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex);
__ str(ip, FieldMemOperand(r4, HeapObject::kMapOffset));
__ b(&done);
__ bind(&call_runtime);
__ push(r0);
__ CallRuntime(Runtime::kRegExpCloneResult, 1);
__ bind(&done);
}
frame_->EmitPush(r0);
}
class DeferredSearchCache: public DeferredCode {
public:
DeferredSearchCache(Register dst, Register cache, Register key)
@ -5892,7 +5834,7 @@ void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
// Prepare stack for calling JS runtime function.
// Push the builtins object found in the current global object.
Register scratch = VirtualFrame::scratch0();
__ ldr(scratch, GlobalObject());
__ ldr(scratch, GlobalObjectOperand());
Register builtins = frame_->GetTOSRegister();
__ ldr(builtins, FieldMemOperand(scratch, GlobalObject::kBuiltinsOffset));
frame_->EmitPush(builtins);
@ -5910,7 +5852,7 @@ void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
// Call the JS runtime function.
__ mov(r2, Operand(node->name()));
InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> stub = ComputeCallInitialize(arg_count, in_loop);
Handle<Code> stub = StubCache::ComputeCallInitialize(arg_count, in_loop);
frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1);
__ ldr(cp, frame_->Context());
frame_->EmitPush(r0);

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

@ -279,10 +279,6 @@ class CodeGenerator: public AstVisitor {
return inlined_write_barrier_size_ + 4;
}
static MemOperand ContextOperand(Register context, int index) {
return MemOperand(context, Context::SlotOffset(index));
}
private:
// Type of a member function that generates inline code for a native function.
typedef void (CodeGenerator::*InlineFunctionGenerator)
@ -349,10 +345,6 @@ class CodeGenerator: public AstVisitor {
JumpTarget* slow);
// Expressions
static MemOperand GlobalObject() {
return ContextOperand(cp, Context::GLOBAL_INDEX);
}
void LoadCondition(Expression* x,
JumpTarget* true_target,
JumpTarget* false_target,
@ -452,10 +444,6 @@ class CodeGenerator: public AstVisitor {
static Handle<Code> ComputeLazyCompile(int argc);
void ProcessDeclarations(ZoneList<Declaration*>* declarations);
static Handle<Code> ComputeCallInitialize(int argc, InLoopFlag in_loop);
static Handle<Code> ComputeKeyedCallInitialize(int argc, InLoopFlag in_loop);
// Declare global variables and functions in the given array of
// name/value pairs.
void DeclareGlobals(Handle<FixedArray> pairs);
@ -518,8 +506,6 @@ class CodeGenerator: public AstVisitor {
void GenerateRegExpConstructResult(ZoneList<Expression*>* args);
void GenerateRegExpCloneResult(ZoneList<Expression*>* args);
// Support for fast native caches.
void GenerateGetFromCache(ZoneList<Expression*>* args);

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;

19
deps/v8/src/arm/disasm-arm.cc

@ -1046,6 +1046,7 @@ int Decoder::DecodeType7(Instr* instr) {
// Dd = vdiv(Dn, Dm)
// vcmp(Dd, Dm)
// vmrs
// vmsr
// Dd = vsqrt(Dm)
void Decoder::DecodeTypeVFP(Instr* instr) {
ASSERT((instr->TypeField() == 7) && (instr->Bit(24) == 0x0) );
@ -1111,16 +1112,22 @@ void Decoder::DecodeTypeVFP(Instr* instr) {
if ((instr->VCField() == 0x0) &&
(instr->VAField() == 0x0)) {
DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(instr);
} else if ((instr->VLField() == 0x1) &&
(instr->VCField() == 0x0) &&
} else if ((instr->VCField() == 0x0) &&
(instr->VAField() == 0x7) &&
(instr->Bits(19, 16) == 0x1)) {
if (instr->Bits(15, 12) == 0xF)
if (instr->VLField() == 0) {
if (instr->Bits(15, 12) == 0xF) {
Format(instr, "vmsr'cond FPSCR, APSR");
} else {
Format(instr, "vmsr'cond FPSCR, 'rt");
}
} else {
if (instr->Bits(15, 12) == 0xF) {
Format(instr, "vmrs'cond APSR, FPSCR");
else
Unknown(instr); // Not used by V8.
} else {
Unknown(instr); // Not used by V8.
Format(instr, "vmrs'cond 'rt, FPSCR");
}
}
}
}
}

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

@ -36,6 +36,7 @@
#include "full-codegen.h"
#include "parser.h"
#include "scopes.h"
#include "stub-cache.h"
namespace v8 {
namespace internal {
@ -171,19 +172,16 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
}
// Check the stack for overflow or break request.
// Put the lr setup instruction in the delay slot. The kInstrSize is
// added to the implicit 8 byte offset that always applies to operations
// with pc and gives a return address 12 bytes down.
{ Comment cmnt(masm_, "[ Stack check");
__ LoadRoot(r2, Heap::kStackLimitRootIndex);
__ add(lr, pc, Operand(Assembler::kInstrSize));
__ cmp(sp, Operand(r2));
StackCheckStub stub;
__ mov(pc,
__ mov(ip,
Operand(reinterpret_cast<intptr_t>(stub.GetCode().location()),
RelocInfo::CODE_TARGET),
LeaveCC,
lo);
__ Call(ip, lo);
}
if (FLAG_trace) {
@ -1019,7 +1017,7 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
__ bind(&fast);
}
__ ldr(r0, CodeGenerator::GlobalObject());
__ ldr(r0, GlobalObjectOperand());
__ mov(r2, Operand(slot->var()->name()));
RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
? RelocInfo::CODE_TARGET
@ -1040,7 +1038,7 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var) {
Comment cmnt(masm_, "Global variable");
// Use inline caching. Variable name is passed in r2 and the global
// object (receiver) in r0.
__ ldr(r0, CodeGenerator::GlobalObject());
__ ldr(r0, GlobalObjectOperand());
__ mov(r2, Operand(var->name()));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
@ -1514,7 +1512,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
// assignment. Right-hand-side value is passed in r0, variable name in
// r2, and the global object in r1.
__ mov(r2, Operand(var->name()));
__ ldr(r1, CodeGenerator::GlobalObject());
__ ldr(r1, GlobalObjectOperand());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
EmitCallIC(ic, RelocInfo::CODE_TARGET);
@ -1688,15 +1686,17 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
// Code common for calls using the IC.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
}
__ mov(r2, Operand(name));
}
// Record source position for debugger.
SetSourcePosition(expr->position());
SetSourcePosition(expr->position(), FORCED_POSITION);
// Call the IC initialization code.
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop);
Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, in_loop);
EmitCallIC(ic, mode);
// Restore context register.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
@ -1707,24 +1707,33 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
Expression* key,
RelocInfo::Mode mode) {
// Load the key.
VisitForAccumulatorValue(key);
// Swap the name of the function and the receiver on the stack to follow
// the calling convention for call ICs.
__ pop(r1);
__ push(r0);
__ push(r1);
// Code common for calls using the IC.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
}
VisitForAccumulatorValue(key);
__ mov(r2, r0);
}
// Record source position for debugger.
SetSourcePosition(expr->position());
SetSourcePosition(expr->position(), FORCED_POSITION);
// Call the IC initialization code.
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic = CodeGenerator::ComputeKeyedCallInitialize(arg_count,
in_loop);
Handle<Code> ic = StubCache::ComputeKeyedCallInitialize(arg_count, in_loop);
__ ldr(r2, MemOperand(sp, (arg_count + 1) * kPointerSize)); // Key.
EmitCallIC(ic, mode);
// Restore context register.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
context()->Plug(r0);
context()->DropAndPlug(1, r0); // Drop the key still on the stack.
}
@ -1732,11 +1741,13 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr) {
// Code common for calls using the call stub.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
{ 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,13 +1767,15 @@ 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.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
{ PreserveStatementPositionScope pos_scope(masm()->positions_recorder());
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));
}
@ -1780,7 +1793,8 @@ void FullCodeGenerator::VisitCall(Call* expr) {
}
// Push the receiver of the enclosing function and do runtime call.
__ ldr(r1, MemOperand(fp, (2 + scope()->num_parameters()) * kPointerSize));
__ ldr(r1,
MemOperand(fp, (2 + scope()->num_parameters()) * kPointerSize));
__ push(r1);
__ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
@ -1788,9 +1802,10 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// r1 (receiver). Touch up the stack with the right values.
__ str(r0, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ str(r1, MemOperand(sp, arg_count * kPointerSize));
}
// Record source position for debugger.
SetSourcePosition(expr->position());
SetSourcePosition(expr->position(), FORCED_POSITION);
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
__ CallStub(&stub);
@ -1799,7 +1814,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
context()->DropAndPlug(1, r0);
} else if (var != NULL && !var->is_this() && var->is_global()) {
// Push global object as receiver for the call IC.
__ ldr(r0, CodeGenerator::GlobalObject());
__ ldr(r0, GlobalObjectOperand());
__ push(r0);
EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
} else if (var != NULL && var->AsSlot() != NULL &&
@ -1807,12 +1822,14 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// Call to a lookup slot (dynamically introduced variable).
Label slow, done;
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
NOT_INSIDE_TYPEOF,
&slow,
&done);
}
__ bind(&slow);
// Call the runtime to find the function to call (returned in r0)
@ -1833,7 +1850,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// Push function.
__ push(r0);
// Push global receiver.
__ ldr(r1, CodeGenerator::GlobalObject());
__ ldr(r1, GlobalObjectOperand());
__ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
__ push(r1);
__ bind(&call);
@ -1846,22 +1863,28 @@ void FullCodeGenerator::VisitCall(Call* expr) {
Literal* key = prop->key()->AsLiteral();
if (key != NULL && key->handle()->IsSymbol()) {
// Call to a named property, use call IC.
{ 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.
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
VisitForStackValue(prop->obj());
}
if (prop->is_synthetic()) {
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
VisitForAccumulatorValue(prop->key());
}
// Record source code position for IC call.
SetSourcePosition(prop->position());
SetSourcePosition(prop->position(), FORCED_POSITION);
__ pop(r1); // We do not need to keep the receiver.
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
EmitCallIC(ic, RelocInfo::CODE_TARGET);
__ ldr(r1, CodeGenerator::GlobalObject());
__ ldr(r1, GlobalObjectOperand());
__ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
__ Push(r0, r1); // Function, receiver.
EmitCallWithStub(expr);
@ -1879,9 +1902,12 @@ void FullCodeGenerator::VisitCall(Call* expr) {
loop_depth() == 0) {
lit->set_try_full_codegen(true);
}
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
VisitForStackValue(fun);
}
// Load global receiver object.
__ ldr(r1, CodeGenerator::GlobalObject());
__ ldr(r1, GlobalObjectOperand());
__ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
__ push(r1);
// Emit function call.
@ -2759,7 +2785,7 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
if (expr->is_jsruntime()) {
// Prepare for calling JS runtime function.
__ ldr(r0, CodeGenerator::GlobalObject());
__ ldr(r0, GlobalObjectOperand());
__ ldr(r0, FieldMemOperand(r0, GlobalObject::kBuiltinsOffset));
__ push(r0);
}
@ -2773,8 +2799,7 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
if (expr->is_jsruntime()) {
// Call the JS runtime function.
__ mov(r2, Operand(expr->name()));
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
NOT_IN_LOOP);
Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, NOT_IN_LOOP);
EmitCallIC(ic, RelocInfo::CODE_TARGET);
// Restore context register.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
@ -2811,7 +2836,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
VisitForStackValue(prop->obj());
VisitForStackValue(prop->key());
} else if (var->is_global()) {
__ ldr(r1, CodeGenerator::GlobalObject());
__ ldr(r1, GlobalObjectOperand());
__ mov(r0, Operand(var->name()));
__ Push(r1, r0);
} else {
@ -3077,7 +3102,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
VariableProxy* proxy = expr->AsVariableProxy();
if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) {
Comment cmnt(masm_, "Global variable");
__ ldr(r0, CodeGenerator::GlobalObject());
__ ldr(r0, GlobalObjectOperand());
__ mov(r2, Operand(proxy->name()));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
// Use a regular load, not a contextual load, to avoid a reference

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,21 +220,21 @@ 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);
}
}
void MacroAssembler::Ubfx(Register dst, Register src1, int lsb, int width,

10
deps/v8/src/arm/macro-assembler-arm.h

@ -727,6 +727,16 @@ class CodePatcher {
// -----------------------------------------------------------------------------
// Static helper functions.
static MemOperand ContextOperand(Register context, int index) {
return MemOperand(context, Context::SlotOffset(index));
}
static inline MemOperand GlobalObjectOperand() {
return ContextOperand(cp, Context::GLOBAL_INDEX);
}
#ifdef GENERATED_CODE_COVERAGE
#define CODE_COVERAGE_STRINGIFY(x) #x
#define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)

88
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,17 +2641,51 @@ 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);
inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val);
int sint = unsigned_integer ? static_cast<uint32_t>(val) :
static_cast<int32_t>(val);
sint = sint > val ? sint - 1 : sint;
set_s_register_from_sinteger(dst, sint);
} else {
float val = get_float_from_s_register(src);
inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val);
int sint = unsigned_integer ? static_cast<uint32_t>(val) :
static_cast<int32_t>(val);
sint = sint > val ? sint - 1 : sint;
set_s_register_from_sinteger(dst, sint);
}
break;
case RZ:
if (src_precision == kDoublePrecision) {
double val = get_double_from_d_register(src);
inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val);
int sint = unsigned_integer ? static_cast<uint32_t>(val) :
static_cast<int32_t>(val);
@ -2623,11 +2693,19 @@ void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr) {
} 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_;

139
deps/v8/src/arm/stub-cache-arm.cc

@ -1676,8 +1676,143 @@ MaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object,
JSGlobalPropertyCell* cell,
JSFunction* function,
String* name) {
// TODO(872): implement this.
return Heap::undefined_value();
// ----------- S t a t e -------------
// -- r2 : function name
// -- lr : return address
// -- sp[(argc - n - 1) * 4] : arg[n] (zero-based)
// -- ...
// -- sp[argc * 4] : receiver
// -----------------------------------
if (!CpuFeatures::IsSupported(VFP3)) return Heap::undefined_value();
CpuFeatures::Scope scope_vfp3(VFP3);
const int argc = arguments().immediate();
// If the object is not a JSObject or we got an unexpected number of
// arguments, bail out to the regular call.
if (!object->IsJSObject() || argc != 1) return Heap::undefined_value();
Label miss, slow;
GenerateNameCheck(name, &miss);
if (cell == NULL) {
__ ldr(r1, MemOperand(sp, 1 * kPointerSize));
STATIC_ASSERT(kSmiTag == 0);
__ BranchOnSmi(r1, &miss);
CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, r4, name,
&miss);
} else {
ASSERT(cell->value() == function);
GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
GenerateLoadFunctionFromCell(cell, function, &miss);
}
// Load the (only) argument into r0.
__ ldr(r0, MemOperand(sp, 0 * kPointerSize));
// If the argument is a smi, just return.
STATIC_ASSERT(kSmiTag == 0);
__ tst(r0, Operand(kSmiTagMask));
__ Drop(argc + 1, eq);
__ Ret(eq);
__ CheckMap(r0, r1, Heap::kHeapNumberMapRootIndex, &slow, true);
Label wont_fit_smi, no_vfp_exception, restore_fpscr_and_return;
// If vfp3 is enabled, we use the fpu rounding with the RM (round towards
// minus infinity) mode.
// Load the HeapNumber value.
// We will need access to the value in the core registers, so we load it
// with ldrd and move it to the fpu. It also spares a sub instruction for
// updating the HeapNumber value address, as vldr expects a multiple
// of 4 offset.
__ Ldrd(r4, r5, FieldMemOperand(r0, HeapNumber::kValueOffset));
__ vmov(d1, r4, r5);
// Backup FPSCR.
__ vmrs(r3);
// Set custom FPCSR:
// - Set rounding mode to "Round towards Minus Infinity"
// (ie bits [23:22] = 0b10).
// - Clear vfp cumulative exception flags (bits [3:0]).
// - Make sure Flush-to-zero mode control bit is unset (bit 22).
__ bic(r9, r3,
Operand(kVFPExceptionMask | kVFPRoundingModeMask | kVFPFlushToZeroMask));
__ orr(r9, r9, Operand(kVFPRoundToMinusInfinityBits));
__ vmsr(r9);
// Convert the argument to an integer.
__ vcvt_s32_f64(s0, d1, Assembler::FPSCRRounding, al);
// Use vcvt latency to start checking for special cases.
// Get the argument exponent and clear the sign bit.
__ bic(r6, r5, Operand(HeapNumber::kSignMask));
__ mov(r6, Operand(r6, LSR, HeapNumber::kMantissaBitsInTopWord));
// Retrieve FPSCR and check for vfp exceptions.
__ vmrs(r9);
__ tst(r9, Operand(kVFPExceptionMask));
__ b(&no_vfp_exception, eq);
// Check for NaN, Infinity, and -Infinity.
// They are invariant through a Math.Floor call, so just
// return the original argument.
__ sub(r7, r6, Operand(HeapNumber::kExponentMask
>> HeapNumber::kMantissaBitsInTopWord), SetCC);
__ b(&restore_fpscr_and_return, eq);
// We had an overflow or underflow in the conversion. Check if we
// have a big exponent.
__ cmp(r7, Operand(HeapNumber::kMantissaBits));
// If greater or equal, the argument is already round and in r0.
__ b(&restore_fpscr_and_return, ge);
__ b(&slow);
__ bind(&no_vfp_exception);
// Move the result back to general purpose register r0.
__ vmov(r0, s0);
// Check if the result fits into a smi.
__ add(r1, r0, Operand(0x40000000), SetCC);
__ b(&wont_fit_smi, mi);
// Tag the result.
STATIC_ASSERT(kSmiTag == 0);
__ mov(r0, Operand(r0, LSL, kSmiTagSize));
// Check for -0.
__ cmp(r0, Operand(0));
__ b(&restore_fpscr_and_return, ne);
// r5 already holds the HeapNumber exponent.
__ tst(r5, Operand(HeapNumber::kSignMask));
// If our HeapNumber is negative it was -0, so load its address and return.
// Else r0 is loaded with 0, so we can also just return.
__ ldr(r0, MemOperand(sp, 0 * kPointerSize), ne);
__ bind(&restore_fpscr_and_return);
// Restore FPSCR and return.
__ vmsr(r3);
__ Drop(argc + 1);
__ Ret();
__ bind(&wont_fit_smi);
__ bind(&slow);
// Restore FPCSR and fall to slow case.
__ vmsr(r3);
// Tail call the full function. We do not have to patch the receiver
// because the function makes no use of it.
__ InvokeFunction(function, arguments(), JUMP_FUNCTION);
__ bind(&miss);
// r2: function name.
MaybeObject* obj = GenerateMissBranch();
if (obj->IsFailure()) return obj;
// Return the generated code.
return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name);
}

7
deps/v8/src/arm/virtual-frame-arm.cc

@ -245,18 +245,15 @@ void VirtualFrame::AllocateStackSlots() {
__ LoadRoot(r2, Heap::kStackLimitRootIndex);
}
// Check the stack for overflow or a break request.
// Put the lr setup instruction in the delay slot. The kInstrSize is added
// to the implicit 8 byte offset that always applies to operations with pc
// and gives a return address 12 bytes down.
masm()->add(lr, pc, Operand(Assembler::kInstrSize));
masm()->cmp(sp, Operand(r2));
StackCheckStub stub;
// Call the stub if lower.
masm()->mov(pc,
masm()->mov(ip,
Operand(reinterpret_cast<intptr_t>(stub.GetCode().location()),
RelocInfo::CODE_TARGET),
LeaveCC,
lo);
masm()->Call(ip, lo);
}

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

655
deps/v8/src/bignum-dtoa.cc

@ -0,0 +1,655 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <math.h>
#include "v8.h"
#include "bignum-dtoa.h"
#include "bignum.h"
#include "double.h"
namespace v8 {
namespace internal {
static int NormalizedExponent(uint64_t significand, int exponent) {
ASSERT(significand != 0);
while ((significand & Double::kHiddenBit) == 0) {
significand = significand << 1;
exponent = exponent - 1;
}
return exponent;
}
// Forward declarations:
// Returns an estimation of k such that 10^(k-1) <= v < 10^k.
static int EstimatePower(int exponent);
// Computes v / 10^estimated_power exactly, as a ratio of two bignums, numerator
// and denominator.
static void InitialScaledStartValues(double v,
int estimated_power,
bool need_boundary_deltas,
Bignum* numerator,
Bignum* denominator,
Bignum* delta_minus,
Bignum* delta_plus);
// Multiplies numerator/denominator so that its values lies in the range 1-10.
// Returns decimal_point s.t.
// v = numerator'/denominator' * 10^(decimal_point-1)
// where numerator' and denominator' are the values of numerator and
// denominator after the call to this function.
static void FixupMultiply10(int estimated_power, bool is_even,
int* decimal_point,
Bignum* numerator, Bignum* denominator,
Bignum* delta_minus, Bignum* delta_plus);
// Generates digits from the left to the right and stops when the generated
// digits yield the shortest decimal representation of v.
static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator,
Bignum* delta_minus, Bignum* delta_plus,
bool is_even,
Vector<char> buffer, int* length);
// Generates 'requested_digits' after the decimal point.
static void BignumToFixed(int requested_digits, int* decimal_point,
Bignum* numerator, Bignum* denominator,
Vector<char>(buffer), int* length);
// Generates 'count' digits of numerator/denominator.
// Once 'count' digits have been produced rounds the result depending on the
// remainder (remainders of exactly .5 round upwards). Might update the
// decimal_point when rounding up (for example for 0.9999).
static void GenerateCountedDigits(int count, int* decimal_point,
Bignum* numerator, Bignum* denominator,
Vector<char>(buffer), int* length);
void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits,
Vector<char> buffer, int* length, int* decimal_point) {
ASSERT(v > 0);
ASSERT(!Double(v).IsSpecial());
uint64_t significand = Double(v).Significand();
bool is_even = (significand & 1) == 0;
int exponent = Double(v).Exponent();
int normalized_exponent = NormalizedExponent(significand, exponent);
// estimated_power might be too low by 1.
int estimated_power = EstimatePower(normalized_exponent);
// Shortcut for Fixed.
// The requested digits correspond to the digits after the point. If the
// number is much too small, then there is no need in trying to get any
// digits.
if (mode == BIGNUM_DTOA_FIXED && -estimated_power - 1 > requested_digits) {
buffer[0] = '\0';
*length = 0;
// Set decimal-point to -requested_digits. This is what Gay does.
// Note that it should not have any effect anyways since the string is
// empty.
*decimal_point = -requested_digits;
return;
}
Bignum numerator;
Bignum denominator;
Bignum delta_minus;
Bignum delta_plus;
// Make sure the bignum can grow large enough. The smallest double equals
// 4e-324. In this case the denominator needs fewer than 324*4 binary digits.
// The maximum double is 1.7976931348623157e308 which needs fewer than
// 308*4 binary digits.
ASSERT(Bignum::kMaxSignificantBits >= 324*4);
bool need_boundary_deltas = (mode == BIGNUM_DTOA_SHORTEST);
InitialScaledStartValues(v, estimated_power, need_boundary_deltas,
&numerator, &denominator,
&delta_minus, &delta_plus);
// We now have v = (numerator / denominator) * 10^estimated_power.
FixupMultiply10(estimated_power, is_even, decimal_point,
&numerator, &denominator,
&delta_minus, &delta_plus);
// We now have v = (numerator / denominator) * 10^(decimal_point-1), and
// 1 <= (numerator + delta_plus) / denominator < 10
switch (mode) {
case BIGNUM_DTOA_SHORTEST:
GenerateShortestDigits(&numerator, &denominator,
&delta_minus, &delta_plus,
is_even, buffer, length);
break;
case BIGNUM_DTOA_FIXED:
BignumToFixed(requested_digits, decimal_point,
&numerator, &denominator,
buffer, length);
break;
case BIGNUM_DTOA_PRECISION:
GenerateCountedDigits(requested_digits, decimal_point,
&numerator, &denominator,
buffer, length);
break;
default:
UNREACHABLE();
}
buffer[*length] = '\0';
}
// The procedure starts generating digits from the left to the right and stops
// when the generated digits yield the shortest decimal representation of v. A
// decimal representation of v is a number lying closer to v than to any other
// double, so it converts to v when read.
//
// This is true if d, the decimal representation, is between m- and m+, the
// upper and lower boundaries. d must be strictly between them if !is_even.
// m- := (numerator - delta_minus) / denominator
// m+ := (numerator + delta_plus) / denominator
//
// Precondition: 0 <= (numerator+delta_plus) / denominator < 10.
// If 1 <= (numerator+delta_plus) / denominator < 10 then no leading 0 digit
// will be produced. This should be the standard precondition.
static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator,
Bignum* delta_minus, Bignum* delta_plus,
bool is_even,
Vector<char> buffer, int* length) {
// Small optimization: if delta_minus and delta_plus are the same just reuse
// one of the two bignums.
if (Bignum::Equal(*delta_minus, *delta_plus)) {
delta_plus = delta_minus;
}
*length = 0;
while (true) {
uint16_t digit;
digit = numerator->DivideModuloIntBignum(*denominator);
ASSERT(digit <= 9); // digit is a uint16_t and therefore always positive.
// digit = numerator / denominator (integer division).
// numerator = numerator % denominator.
buffer[(*length)++] = digit + '0';
// Can we stop already?
// If the remainder of the division is less than the distance to the lower
// boundary we can stop. In this case we simply round down (discarding the
// remainder).
// Similarly we test if we can round up (using the upper boundary).
bool in_delta_room_minus;
bool in_delta_room_plus;
if (is_even) {
in_delta_room_minus = Bignum::LessEqual(*numerator, *delta_minus);
} else {
in_delta_room_minus = Bignum::Less(*numerator, *delta_minus);
}
if (is_even) {
in_delta_room_plus =
Bignum::PlusCompare(*numerator, *delta_plus, *denominator) >= 0;
} else {
in_delta_room_plus =
Bignum::PlusCompare(*numerator, *delta_plus, *denominator) > 0;
}
if (!in_delta_room_minus && !in_delta_room_plus) {
// Prepare for next iteration.
numerator->Times10();
delta_minus->Times10();
// We optimized delta_plus to be equal to delta_minus (if they share the
// same value). So don't multiply delta_plus if they point to the same
// object.
if (delta_minus != delta_plus) {
delta_plus->Times10();
}
} else if (in_delta_room_minus && in_delta_room_plus) {
// Let's see if 2*numerator < denominator.
// If yes, then the next digit would be < 5 and we can round down.
int compare = Bignum::PlusCompare(*numerator, *numerator, *denominator);
if (compare < 0) {
// Remaining digits are less than .5. -> Round down (== do nothing).
} else if (compare > 0) {
// Remaining digits are more than .5 of denominator. -> Round up.
// Note that the last digit could not be a '9' as otherwise the whole
// loop would have stopped earlier.
// We still have an assert here in case the preconditions were not
// satisfied.
ASSERT(buffer[(*length) - 1] != '9');
buffer[(*length) - 1]++;
} else {
// Halfway case.
// TODO(floitsch): need a way to solve half-way cases.
// For now let's round towards even (since this is what Gay seems to
// do).
if ((buffer[(*length) - 1] - '0') % 2 == 0) {
// Round down => Do nothing.
} else {
ASSERT(buffer[(*length) - 1] != '9');
buffer[(*length) - 1]++;
}
}
return;
} else if (in_delta_room_minus) {
// Round down (== do nothing).
return;
} else { // in_delta_room_plus
// Round up.
// Note again that the last digit could not be '9' since this would have
// stopped the loop earlier.
// We still have an ASSERT here, in case the preconditions were not
// satisfied.
ASSERT(buffer[(*length) -1] != '9');
buffer[(*length) - 1]++;
return;
}
}
}
// Let v = numerator / denominator < 10.
// Then we generate 'count' digits of d = x.xxxxx... (without the decimal point)
// from left to right. Once 'count' digits have been produced we decide wether
// to round up or down. Remainders of exactly .5 round upwards. Numbers such
// as 9.999999 propagate a carry all the way, and change the
// exponent (decimal_point), when rounding upwards.
static void GenerateCountedDigits(int count, int* decimal_point,
Bignum* numerator, Bignum* denominator,
Vector<char>(buffer), int* length) {
ASSERT(count >= 0);
for (int i = 0; i < count - 1; ++i) {
uint16_t digit;
digit = numerator->DivideModuloIntBignum(*denominator);
ASSERT(digit <= 9); // digit is a uint16_t and therefore always positive.
// digit = numerator / denominator (integer division).
// numerator = numerator % denominator.
buffer[i] = digit + '0';
// Prepare for next iteration.
numerator->Times10();
}
// Generate the last digit.
uint16_t digit;
digit = numerator->DivideModuloIntBignum(*denominator);
if (Bignum::PlusCompare(*numerator, *numerator, *denominator) >= 0) {
digit++;
}
buffer[count - 1] = digit + '0';
// Correct bad digits (in case we had a sequence of '9's). Propagate the
// carry until we hat a non-'9' or til we reach the first digit.
for (int i = count - 1; i > 0; --i) {
if (buffer[i] != '0' + 10) break;
buffer[i] = '0';
buffer[i - 1]++;
}
if (buffer[0] == '0' + 10) {
// Propagate a carry past the top place.
buffer[0] = '1';
(*decimal_point)++;
}
*length = count;
}
// Generates 'requested_digits' after the decimal point. It might omit
// trailing '0's. If the input number is too small then no digits at all are
// generated (ex.: 2 fixed digits for 0.00001).
//
// Input verifies: 1 <= (numerator + delta) / denominator < 10.
static void BignumToFixed(int requested_digits, int* decimal_point,
Bignum* numerator, Bignum* denominator,
Vector<char>(buffer), int* length) {
// Note that we have to look at more than just the requested_digits, since
// a number could be rounded up. Example: v=0.5 with requested_digits=0.
// Even though the power of v equals 0 we can't just stop here.
if (-(*decimal_point) > requested_digits) {
// The number is definitively too small.
// Ex: 0.001 with requested_digits == 1.
// Set decimal-point to -requested_digits. This is what Gay does.
// Note that it should not have any effect anyways since the string is
// empty.
*decimal_point = -requested_digits;
*length = 0;
return;
} else if (-(*decimal_point) == requested_digits) {
// We only need to verify if the number rounds down or up.
// Ex: 0.04 and 0.06 with requested_digits == 1.
ASSERT(*decimal_point == -requested_digits);
// Initially the fraction lies in range (1, 10]. Multiply the denominator
// by 10 so that we can compare more easily.
denominator->Times10();
if (Bignum::PlusCompare(*numerator, *numerator, *denominator) >= 0) {
// If the fraction is >= 0.5 then we have to include the rounded
// digit.
buffer[0] = '1';
*length = 1;
(*decimal_point)++;
} else {
// Note that we caught most of similar cases earlier.
*length = 0;
}
return;
} else {
// The requested digits correspond to the digits after the point.
// The variable 'needed_digits' includes the digits before the point.
int needed_digits = (*decimal_point) + requested_digits;
GenerateCountedDigits(needed_digits, decimal_point,
numerator, denominator,
buffer, length);
}
}
// Returns an estimation of k such that 10^(k-1) <= v < 10^k where
// v = f * 2^exponent and 2^52 <= f < 2^53.
// v is hence a normalized double with the given exponent. The output is an
// approximation for the exponent of the decimal approimation .digits * 10^k.
//
// The result might undershoot by 1 in which case 10^k <= v < 10^k+1.
// Note: this property holds for v's upper boundary m+ too.
// 10^k <= m+ < 10^k+1.
// (see explanation below).
//
// Examples:
// EstimatePower(0) => 16
// EstimatePower(-52) => 0
//
// Note: e >= 0 => EstimatedPower(e) > 0. No similar claim can be made for e<0.
static int EstimatePower(int exponent) {
// This function estimates log10 of v where v = f*2^e (with e == exponent).
// Note that 10^floor(log10(v)) <= v, but v <= 10^ceil(log10(v)).
// Note that f is bounded by its container size. Let p = 53 (the double's
// significand size). Then 2^(p-1) <= f < 2^p.
//
// Given that log10(v) == log2(v)/log2(10) and e+(len(f)-1) is quite close
// to log2(v) the function is simplified to (e+(len(f)-1)/log2(10)).
// The computed number undershoots by less than 0.631 (when we compute log3
// and not log10).
//
// Optimization: since we only need an approximated result this computation
// can be performed on 64 bit integers. On x86/x64 architecture the speedup is
// not really measurable, though.
//
// Since we want to avoid overshooting we decrement by 1e10 so that
// floating-point imprecisions don't affect us.
//
// Explanation for v's boundary m+: the computation takes advantage of
// the fact that 2^(p-1) <= f < 2^p. Boundaries still satisfy this requirement
// (even for denormals where the delta can be much more important).
const double k1Log10 = 0.30102999566398114; // 1/lg(10)
// For doubles len(f) == 53 (don't forget the hidden bit).
const int kSignificandSize = 53;
double estimate = ceil((exponent + kSignificandSize - 1) * k1Log10 - 1e-10);
return static_cast<int>(estimate);
}
// See comments for InitialScaledStartValues.
static void InitialScaledStartValuesPositiveExponent(
double v, int estimated_power, bool need_boundary_deltas,
Bignum* numerator, Bignum* denominator,
Bignum* delta_minus, Bignum* delta_plus) {
// A positive exponent implies a positive power.
ASSERT(estimated_power >= 0);
// Since the estimated_power is positive we simply multiply the denominator
// by 10^estimated_power.
// numerator = v.
numerator->AssignUInt64(Double(v).Significand());
numerator->ShiftLeft(Double(v).Exponent());
// denominator = 10^estimated_power.
denominator->AssignPowerUInt16(10, estimated_power);
if (need_boundary_deltas) {
// Introduce a common denominator so that the deltas to the boundaries are
// integers.
denominator->ShiftLeft(1);
numerator->ShiftLeft(1);
// Let v = f * 2^e, then m+ - v = 1/2 * 2^e; With the common
// denominator (of 2) delta_plus equals 2^e.
delta_plus->AssignUInt16(1);
delta_plus->ShiftLeft(Double(v).Exponent());
// Same for delta_minus (with adjustments below if f == 2^p-1).
delta_minus->AssignUInt16(1);
delta_minus->ShiftLeft(Double(v).Exponent());
// If the significand (without the hidden bit) is 0, then the lower
// boundary is closer than just half a ulp (unit in the last place).
// There is only one exception: if the next lower number is a denormal then
// the distance is 1 ulp. This cannot be the case for exponent >= 0 (but we
// have to test it in the other function where exponent < 0).
uint64_t v_bits = Double(v).AsUint64();
if ((v_bits & Double::kSignificandMask) == 0) {
// The lower boundary is closer at half the distance of "normal" numbers.
// Increase the common denominator and adapt all but the delta_minus.
denominator->ShiftLeft(1); // *2
numerator->ShiftLeft(1); // *2
delta_plus->ShiftLeft(1); // *2
}
}
}
// See comments for InitialScaledStartValues
static void InitialScaledStartValuesNegativeExponentPositivePower(
double v, int estimated_power, bool need_boundary_deltas,
Bignum* numerator, Bignum* denominator,
Bignum* delta_minus, Bignum* delta_plus) {
uint64_t significand = Double(v).Significand();
int exponent = Double(v).Exponent();
// v = f * 2^e with e < 0, and with estimated_power >= 0.
// This means that e is close to 0 (have a look at how estimated_power is
// computed).
// numerator = significand
// since v = significand * 2^exponent this is equivalent to
// numerator = v * / 2^-exponent
numerator->AssignUInt64(significand);
// denominator = 10^estimated_power * 2^-exponent (with exponent < 0)
denominator->AssignPowerUInt16(10, estimated_power);
denominator->ShiftLeft(-exponent);
if (need_boundary_deltas) {
// Introduce a common denominator so that the deltas to the boundaries are
// integers.
denominator->ShiftLeft(1);
numerator->ShiftLeft(1);
// Let v = f * 2^e, then m+ - v = 1/2 * 2^e; With the common
// denominator (of 2) delta_plus equals 2^e.
// Given that the denominator already includes v's exponent the distance
// to the boundaries is simply 1.
delta_plus->AssignUInt16(1);
// Same for delta_minus (with adjustments below if f == 2^p-1).
delta_minus->AssignUInt16(1);
// If the significand (without the hidden bit) is 0, then the lower
// boundary is closer than just one ulp (unit in the last place).
// There is only one exception: if the next lower number is a denormal
// then the distance is 1 ulp. Since the exponent is close to zero
// (otherwise estimated_power would have been negative) this cannot happen
// here either.
uint64_t v_bits = Double(v).AsUint64();
if ((v_bits & Double::kSignificandMask) == 0) {
// The lower boundary is closer at half the distance of "normal" numbers.
// Increase the denominator and adapt all but the delta_minus.
denominator->ShiftLeft(1); // *2
numerator->ShiftLeft(1); // *2
delta_plus->ShiftLeft(1); // *2
}
}
}
// See comments for InitialScaledStartValues
static void InitialScaledStartValuesNegativeExponentNegativePower(
double v, int estimated_power, bool need_boundary_deltas,
Bignum* numerator, Bignum* denominator,
Bignum* delta_minus, Bignum* delta_plus) {
const uint64_t kMinimalNormalizedExponent =
V8_2PART_UINT64_C(0x00100000, 00000000);
uint64_t significand = Double(v).Significand();
int exponent = Double(v).Exponent();
// Instead of multiplying the denominator with 10^estimated_power we
// multiply all values (numerator and deltas) by 10^-estimated_power.
// Use numerator as temporary container for power_ten.
Bignum* power_ten = numerator;
power_ten->AssignPowerUInt16(10, -estimated_power);
if (need_boundary_deltas) {
// Since power_ten == numerator we must make a copy of 10^estimated_power
// before we complete the computation of the numerator.
// delta_plus = delta_minus = 10^estimated_power
delta_plus->AssignBignum(*power_ten);
delta_minus->AssignBignum(*power_ten);
}
// numerator = significand * 2 * 10^-estimated_power
// since v = significand * 2^exponent this is equivalent to
// numerator = v * 10^-estimated_power * 2 * 2^-exponent.
// Remember: numerator has been abused as power_ten. So no need to assign it
// to itself.
ASSERT(numerator == power_ten);
numerator->MultiplyByUInt64(significand);
// denominator = 2 * 2^-exponent with exponent < 0.
denominator->AssignUInt16(1);
denominator->ShiftLeft(-exponent);
if (need_boundary_deltas) {
// Introduce a common denominator so that the deltas to the boundaries are
// integers.
numerator->ShiftLeft(1);
denominator->ShiftLeft(1);
// With this shift the boundaries have their correct value, since
// delta_plus = 10^-estimated_power, and
// delta_minus = 10^-estimated_power.
// These assignments have been done earlier.
// The special case where the lower boundary is twice as close.
// This time we have to look out for the exception too.
uint64_t v_bits = Double(v).AsUint64();
if ((v_bits & Double::kSignificandMask) == 0 &&
// The only exception where a significand == 0 has its boundaries at
// "normal" distances:
(v_bits & Double::kExponentMask) != kMinimalNormalizedExponent) {
numerator->ShiftLeft(1); // *2
denominator->ShiftLeft(1); // *2
delta_plus->ShiftLeft(1); // *2
}
}
}
// Let v = significand * 2^exponent.
// Computes v / 10^estimated_power exactly, as a ratio of two bignums, numerator
// and denominator. The functions GenerateShortestDigits and
// GenerateCountedDigits will then convert this ratio to its decimal
// representation d, with the required accuracy.
// Then d * 10^estimated_power is the representation of v.
// (Note: the fraction and the estimated_power might get adjusted before
// generating the decimal representation.)
//
// The initial start values consist of:
// - a scaled numerator: s.t. numerator/denominator == v / 10^estimated_power.
// - a scaled (common) denominator.
// optionally (used by GenerateShortestDigits to decide if it has the shortest
// decimal converting back to v):
// - v - m-: the distance to the lower boundary.
// - m+ - v: the distance to the upper boundary.
//
// v, m+, m-, and therefore v - m- and m+ - v all share the same denominator.
//
// Let ep == estimated_power, then the returned values will satisfy:
// v / 10^ep = numerator / denominator.
// v's boundarys m- and m+:
// m- / 10^ep == v / 10^ep - delta_minus / denominator
// m+ / 10^ep == v / 10^ep + delta_plus / denominator
// Or in other words:
// m- == v - delta_minus * 10^ep / denominator;
// m+ == v + delta_plus * 10^ep / denominator;
//
// Since 10^(k-1) <= v < 10^k (with k == estimated_power)
// or 10^k <= v < 10^(k+1)
// we then have 0.1 <= numerator/denominator < 1
// or 1 <= numerator/denominator < 10
//
// It is then easy to kickstart the digit-generation routine.
//
// The boundary-deltas are only filled if need_boundary_deltas is set.
static void InitialScaledStartValues(double v,
int estimated_power,
bool need_boundary_deltas,
Bignum* numerator,
Bignum* denominator,
Bignum* delta_minus,
Bignum* delta_plus) {
if (Double(v).Exponent() >= 0) {
InitialScaledStartValuesPositiveExponent(
v, estimated_power, need_boundary_deltas,
numerator, denominator, delta_minus, delta_plus);
} else if (estimated_power >= 0) {
InitialScaledStartValuesNegativeExponentPositivePower(
v, estimated_power, need_boundary_deltas,
numerator, denominator, delta_minus, delta_plus);
} else {
InitialScaledStartValuesNegativeExponentNegativePower(
v, estimated_power, need_boundary_deltas,
numerator, denominator, delta_minus, delta_plus);
}
}
// This routine multiplies numerator/denominator so that its values lies in the
// range 1-10. That is after a call to this function we have:
// 1 <= (numerator + delta_plus) /denominator < 10.
// Let numerator the input before modification and numerator' the argument
// after modification, then the output-parameter decimal_point is such that
// numerator / denominator * 10^estimated_power ==
// numerator' / denominator' * 10^(decimal_point - 1)
// In some cases estimated_power was too low, and this is already the case. We
// then simply adjust the power so that 10^(k-1) <= v < 10^k (with k ==
// estimated_power) but do not touch the numerator or denominator.
// Otherwise the routine multiplies the numerator and the deltas by 10.
static void FixupMultiply10(int estimated_power, bool is_even,
int* decimal_point,
Bignum* numerator, Bignum* denominator,
Bignum* delta_minus, Bignum* delta_plus) {
bool in_range;
if (is_even) {
// For IEEE doubles half-way cases (in decimal system numbers ending with 5)
// are rounded to the closest floating-point number with even significand.
in_range = Bignum::PlusCompare(*numerator, *delta_plus, *denominator) >= 0;
} else {
in_range = Bignum::PlusCompare(*numerator, *delta_plus, *denominator) > 0;
}
if (in_range) {
// Since numerator + delta_plus >= denominator we already have
// 1 <= numerator/denominator < 10. Simply update the estimated_power.
*decimal_point = estimated_power + 1;
} else {
*decimal_point = estimated_power;
numerator->Times10();
if (Bignum::Equal(*delta_minus, *delta_plus)) {
delta_minus->Times10();
delta_plus->AssignBignum(*delta_minus);
} else {
delta_minus->Times10();
delta_plus->Times10();
}
}
}
} } // namespace v8::internal

81
deps/v8/src/bignum-dtoa.h

@ -0,0 +1,81 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef V8_BIGNUM_DTOA_H_
#define V8_BIGNUM_DTOA_H_
namespace v8 {
namespace internal {
enum BignumDtoaMode {
// Return the shortest correct representation.
// For example the output of 0.299999999999999988897 is (the less accurate but
// correct) 0.3.
BIGNUM_DTOA_SHORTEST,
// Return a fixed number of digits after the decimal point.
// For instance fixed(0.1, 4) becomes 0.1000
// If the input number is big, the output will be big.
BIGNUM_DTOA_FIXED,
// Return a fixed number of digits, no matter what the exponent is.
BIGNUM_DTOA_PRECISION
};
// Converts the given double 'v' to ascii.
// The result should be interpreted as buffer * 10^(point-length).
// The buffer will be null-terminated.
//
// The input v must be > 0 and different from NaN, and Infinity.
//
// The output depends on the given mode:
// - SHORTEST: produce the least amount of digits for which the internal
// identity requirement is still satisfied. If the digits are printed
// (together with the correct exponent) then reading this number will give
// 'v' again. The buffer will choose the representation that is closest to
// 'v'. If there are two at the same distance, than the number is round up.
// In this mode the 'requested_digits' parameter is ignored.
// - FIXED: produces digits necessary to print a given number with
// 'requested_digits' digits after the decimal point. The produced digits
// might be too short in which case the caller has to fill the gaps with '0's.
// Example: toFixed(0.001, 5) is allowed to return buffer="1", point=-2.
// Halfway cases are rounded up. The call toFixed(0.15, 2) thus returns
// buffer="2", point=0.
// Note: the length of the returned buffer has no meaning wrt the significance
// of its digits. That is, just because it contains '0's does not mean that
// any other digit would not satisfy the internal identity requirement.
// - PRECISION: produces 'requested_digits' where the first digit is not '0'.
// Even though the length of produced digits usually equals
// 'requested_digits', the function is allowed to return fewer digits, in
// which case the caller has to fill the missing digits with '0's.
// Halfway cases are again rounded up.
// 'BignumDtoa' expects the given buffer to be big enough to hold all digits
// and a terminating null-character.
void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits,
Vector<char> buffer, int* length, int* point);
} } // namespace v8::internal
#endif // V8_BIGNUM_DTOA_H_

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_

4
deps/v8/src/bootstrapper.cc

@ -39,6 +39,8 @@
#include "objects-visiting.h"
#include "snapshot.h"
#include "stub-cache.h"
#include "extensions/externalize-string-extension.h"
#include "extensions/gc-extension.h"
namespace v8 {
namespace internal {
@ -137,6 +139,8 @@ Handle<String> Bootstrapper::NativesSourceLookup(int index) {
void Bootstrapper::Initialize(bool create_heap_objects) {
extensions_cache.Initialize(create_heap_objects);
GCExtension::Register();
ExternalizeStringExtension::Register();
}

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

10
deps/v8/src/code-stubs.cc

@ -37,7 +37,6 @@ namespace v8 {
namespace internal {
bool CodeStub::FindCodeInCache(Code** code_out) {
if (has_custom_cache()) return GetCustomCache(code_out);
int index = Heap::code_stubs()->FindEntry(GetKey());
if (index != NumberDictionary::kNotFound) {
*code_out = Code::cast(Heap::code_stubs()->ValueAt(index));
@ -105,9 +104,6 @@ Handle<Code> CodeStub::GetCode() {
Handle<Code> new_object = Factory::NewCode(desc, flags, masm.CodeObject());
RecordCodeGeneration(*new_object, &masm);
if (has_custom_cache()) {
SetCustomCache(*new_object);
} else {
// Update the dictionary and the root in Heap.
Handle<NumberDictionary> dict =
Factory::DictionaryAtNumberPut(
@ -115,7 +111,7 @@ Handle<Code> CodeStub::GetCode() {
GetKey(),
new_object);
Heap::public_set_code_stubs(*dict);
}
code = *new_object;
}
@ -147,9 +143,6 @@ MaybeObject* CodeStub::TryGetCode() {
code = Code::cast(new_object);
RecordCodeGeneration(code, &masm);
if (has_custom_cache()) {
SetCustomCache(code);
} else {
// Try to update the code cache but do not fail if unable.
MaybeObject* maybe_new_object =
Heap::code_stubs()->AtNumberPut(GetKey(), code);
@ -157,7 +150,6 @@ MaybeObject* CodeStub::TryGetCode() {
Heap::public_set_code_stubs(NumberDictionary::cast(new_object));
}
}
}
return code;
}

32
deps/v8/src/code-stubs.h

@ -124,12 +124,6 @@ class CodeStub BASE_EMBEDDED {
virtual ~CodeStub() {}
// Override these methods to provide a custom caching mechanism for
// an individual type of code stub.
virtual bool GetCustomCache(Code** code_out) { return false; }
virtual void SetCustomCache(Code* value) { }
virtual bool has_custom_cache() { return false; }
protected:
static const int kMajorBits = 5;
static const int kMinorBits = kBitsPerInt - kSmiTagSize - kMajorBits;
@ -524,32 +518,6 @@ class CEntryStub : public CodeStub {
};
class ApiGetterEntryStub : public CodeStub {
public:
ApiGetterEntryStub(Handle<AccessorInfo> info,
ApiFunction* fun)
: info_(info),
fun_(fun) { }
void Generate(MacroAssembler* masm);
virtual bool has_custom_cache() { return true; }
virtual bool GetCustomCache(Code** code_out);
virtual void SetCustomCache(Code* value);
static const int kStackSpace = 5;
static const int kArgc = 2;
private:
Handle<AccessorInfo> info() { return info_; }
ApiFunction* fun() { return fun_; }
Major MajorKey() { return NoCache; }
int MinorKey() { return 0; }
const char* GetName() { return "ApiEntryStub"; }
// The accessor info associated with the function.
Handle<AccessorInfo> info_;
// The function to be called.
ApiFunction* fun_;
};
class JSEntryStub : public CodeStub {
public:
JSEntryStub() { }

62
deps/v8/src/codegen.cc

@ -70,9 +70,10 @@ void CodeGenerator::ProcessDeferred() {
DeferredCode* code = deferred_.RemoveLast();
ASSERT(masm_ == code->masm());
// Record position of deferred code stub.
masm_->RecordStatementPosition(code->statement_position());
masm_->positions_recorder()->RecordStatementPosition(
code->statement_position());
if (code->position() != RelocInfo::kNoPosition) {
masm_->RecordPosition(code->position());
masm_->positions_recorder()->RecordPosition(code->position());
}
// Generate the code.
Comment cmnt(masm_, code->comment());
@ -251,39 +252,6 @@ bool CodeGenerator::ShouldGenerateLog(Expression* type) {
#endif
Handle<Code> CodeGenerator::ComputeCallInitialize(
int argc,
InLoopFlag in_loop) {
if (in_loop == IN_LOOP) {
// Force the creation of the corresponding stub outside loops,
// because it may be used when clearing the ICs later - it is
// possible for a series of IC transitions to lose the in-loop
// information, and the IC clearing code can't generate a stub
// that it needs so we need to ensure it is generated already.
ComputeCallInitialize(argc, NOT_IN_LOOP);
}
CALL_HEAP_FUNCTION(
StubCache::ComputeCallInitialize(argc, in_loop, Code::CALL_IC),
Code);
}
Handle<Code> CodeGenerator::ComputeKeyedCallInitialize(
int argc,
InLoopFlag in_loop) {
if (in_loop == IN_LOOP) {
// Force the creation of the corresponding stub outside loops,
// because it may be used when clearing the ICs later - it is
// possible for a series of IC transitions to lose the in-loop
// information, and the IC clearing code can't generate a stub
// that it needs so we need to ensure it is generated already.
ComputeKeyedCallInitialize(argc, NOT_IN_LOOP);
}
CALL_HEAP_FUNCTION(
StubCache::ComputeCallInitialize(argc, in_loop, Code::KEYED_CALL_IC),
Code);
}
void CodeGenerator::ProcessDeclarations(ZoneList<Declaration*>* declarations) {
int length = declarations->length();
int globals = 0;
@ -402,10 +370,10 @@ bool CodeGenerator::RecordPositions(MacroAssembler* masm,
int pos,
bool right_here) {
if (pos != RelocInfo::kNoPosition) {
masm->RecordStatementPosition(pos);
masm->RecordPosition(pos);
masm->positions_recorder()->RecordStatementPosition(pos);
masm->positions_recorder()->RecordPosition(pos);
if (right_here) {
return masm->WriteRecordedPositions();
return masm->positions_recorder()->WriteRecordedPositions();
}
}
return false;
@ -435,7 +403,7 @@ void CodeGenerator::CodeForDoWhileConditionPosition(DoWhileStatement* stmt) {
void CodeGenerator::CodeForSourcePosition(int pos) {
if (FLAG_debug_info && pos != RelocInfo::kNoPosition) {
masm()->RecordPosition(pos);
masm()->positions_recorder()->RecordPosition(pos);
}
}
@ -481,20 +449,4 @@ int CEntryStub::MinorKey() {
}
bool ApiGetterEntryStub::GetCustomCache(Code** code_out) {
Object* cache = info()->load_stub_cache();
if (cache->IsUndefined()) {
return false;
} else {
*code_out = Code::cast(cache);
return true;
}
}
void ApiGetterEntryStub::SetCustomCache(Code* value) {
info()->set_load_stub_cache(value);
}
} } // namespace v8::internal

2
deps/v8/src/codegen.h

@ -58,8 +58,6 @@
// Generate
// ComputeLazyCompile
// BuildFunctionInfo
// ComputeCallInitialize
// ComputeCallInitializeInLoop
// ProcessDeclarations
// DeclareGlobals
// CheckForInlineRuntimeCall

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);
}

89
deps/v8/src/conversions.cc

@ -33,7 +33,7 @@
#include "conversions-inl.h"
#include "dtoa.h"
#include "factory.h"
#include "scanner.h"
#include "scanner-base.h"
#include "strtod.h"
namespace v8 {
@ -121,7 +121,7 @@ static const double JUNK_STRING_VALUE = OS::nan_value();
template <class Iterator, class EndMark>
static inline bool AdvanceToNonspace(Iterator* current, EndMark end) {
while (*current != end) {
if (!Scanner::kIsWhiteSpace.get(**current)) return true;
if (!ScannerConstants::kIsWhiteSpace.get(**current)) return true;
++*current;
}
return false;
@ -711,11 +711,6 @@ double StringToDouble(Vector<const char> str,
}
extern "C" char* dtoa(double d, int mode, int ndigits,
int* decpt, int* sign, char** rve);
extern "C" void freedtoa(char* s);
const char* DoubleToCString(double v, Vector<char> buffer) {
StringBuilder builder(buffer.start(), buffer.length());
@ -739,21 +734,13 @@ const char* DoubleToCString(double v, Vector<char> buffer) {
default: {
int decimal_point;
int sign;
char* decimal_rep;
bool used_gay_dtoa = false;
const int kV8DtoaBufferCapacity = kBase10MaximalLength + 1;
char v8_dtoa_buffer[kV8DtoaBufferCapacity];
char decimal_rep[kV8DtoaBufferCapacity];
int length;
if (DoubleToAscii(v, DTOA_SHORTEST, 0,
Vector<char>(v8_dtoa_buffer, kV8DtoaBufferCapacity),
&sign, &length, &decimal_point)) {
decimal_rep = v8_dtoa_buffer;
} else {
decimal_rep = dtoa(v, 0, 0, &decimal_point, &sign, NULL);
used_gay_dtoa = true;
length = StrLength(decimal_rep);
}
DoubleToAscii(v, DTOA_SHORTEST, 0,
Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
&sign, &length, &decimal_point);
if (sign) builder.AddCharacter('-');
@ -787,8 +774,6 @@ const char* DoubleToCString(double v, Vector<char> buffer) {
if (exponent < 0) exponent = -exponent;
builder.AddFormatted("%d", exponent);
}
if (used_gay_dtoa) freedtoa(decimal_rep);
}
}
return builder.Finalize();
@ -816,7 +801,7 @@ const char* IntToCString(int n, Vector<char> buffer) {
char* DoubleToFixedCString(double value, int f) {
const int kMaxDigitsBeforePoint = 20;
const int kMaxDigitsBeforePoint = 21;
const double kFirstNonFixed = 1e21;
const int kMaxDigitsAfterPoint = 20;
ASSERT(f >= 0);
@ -840,16 +825,14 @@ char* DoubleToFixedCString(double value, int f) {
// Find a sufficiently precise decimal representation of n.
int decimal_point;
int sign;
// Add space for the '.' and the '\0' byte.
// Add space for the '\0' byte.
const int kDecimalRepCapacity =
kMaxDigitsBeforePoint + kMaxDigitsAfterPoint + 2;
kMaxDigitsBeforePoint + kMaxDigitsAfterPoint + 1;
char decimal_rep[kDecimalRepCapacity];
int decimal_rep_length;
bool status = DoubleToAscii(value, DTOA_FIXED, f,
DoubleToAscii(value, DTOA_FIXED, f,
Vector<char>(decimal_rep, kDecimalRepCapacity),
&sign, &decimal_rep_length, &decimal_point);
USE(status);
ASSERT(status);
// Create a representation that is padded with zeros if needed.
int zero_prefix_length = 0;
@ -935,8 +918,6 @@ char* DoubleToExponentialCString(double value, int f) {
// Find a sufficiently precise decimal representation of n.
int decimal_point;
int sign;
char* decimal_rep = NULL;
bool used_gay_dtoa = false;
// f corresponds to the digits after the point. There is always one digit
// before the point. The number of requested_digits equals hence f + 1.
// And we have to add one character for the null-terminator.
@ -944,31 +925,18 @@ char* DoubleToExponentialCString(double value, int f) {
// Make sure that the buffer is big enough, even if we fall back to the
// shortest representation (which happens when f equals -1).
ASSERT(kBase10MaximalLength <= kMaxDigitsAfterPoint + 1);
char v8_dtoa_buffer[kV8DtoaBufferCapacity];
char decimal_rep[kV8DtoaBufferCapacity];
int decimal_rep_length;
if (f == -1) {
if (DoubleToAscii(value, DTOA_SHORTEST, 0,
Vector<char>(v8_dtoa_buffer, kV8DtoaBufferCapacity),
&sign, &decimal_rep_length, &decimal_point)) {
f = decimal_rep_length - 1;
decimal_rep = v8_dtoa_buffer;
} else {
decimal_rep = dtoa(value, 0, 0, &decimal_point, &sign, NULL);
decimal_rep_length = StrLength(decimal_rep);
DoubleToAscii(value, DTOA_SHORTEST, 0,
Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
&sign, &decimal_rep_length, &decimal_point);
f = decimal_rep_length - 1;
used_gay_dtoa = true;
}
} else {
if (DoubleToAscii(value, DTOA_PRECISION, f + 1,
Vector<char>(v8_dtoa_buffer, kV8DtoaBufferCapacity),
&sign, &decimal_rep_length, &decimal_point)) {
decimal_rep = v8_dtoa_buffer;
} else {
decimal_rep = dtoa(value, 2, f + 1, &decimal_point, &sign, NULL);
decimal_rep_length = StrLength(decimal_rep);
used_gay_dtoa = true;
}
DoubleToAscii(value, DTOA_PRECISION, f + 1,
Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
&sign, &decimal_rep_length, &decimal_point);
}
ASSERT(decimal_rep_length > 0);
ASSERT(decimal_rep_length <= f + 1);
@ -977,10 +945,6 @@ char* DoubleToExponentialCString(double value, int f) {
char* result =
CreateExponentialRepresentation(decimal_rep, exponent, negative, f+1);
if (used_gay_dtoa) {
freedtoa(decimal_rep);
}
return result;
}
@ -1000,22 +964,14 @@ char* DoubleToPrecisionCString(double value, int p) {
// Find a sufficiently precise decimal representation of n.
int decimal_point;
int sign;
char* decimal_rep = NULL;
bool used_gay_dtoa = false;
// Add one for the terminating null character.
const int kV8DtoaBufferCapacity = kMaximalDigits + 1;
char v8_dtoa_buffer[kV8DtoaBufferCapacity];
char decimal_rep[kV8DtoaBufferCapacity];
int decimal_rep_length;
if (DoubleToAscii(value, DTOA_PRECISION, p,
Vector<char>(v8_dtoa_buffer, kV8DtoaBufferCapacity),
&sign, &decimal_rep_length, &decimal_point)) {
decimal_rep = v8_dtoa_buffer;
} else {
decimal_rep = dtoa(value, 2, p, &decimal_point, &sign, NULL);
decimal_rep_length = StrLength(decimal_rep);
used_gay_dtoa = true;
}
DoubleToAscii(value, DTOA_PRECISION, p,
Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
&sign, &decimal_rep_length, &decimal_point);
ASSERT(decimal_rep_length <= p);
int exponent = decimal_point - 1;
@ -1059,9 +1015,6 @@ char* DoubleToPrecisionCString(double value, int p) {
result = builder.Finalize();
}
if (used_gay_dtoa) {
freedtoa(decimal_rep);
}
return result;
}

17
deps/v8/src/dateparser.h

@ -28,7 +28,8 @@
#ifndef V8_DATEPARSER_H_
#define V8_DATEPARSER_H_
#include "scanner.h"
#include "char-predicates-inl.h"
#include "scanner-base.h"
namespace v8 {
namespace internal {
@ -99,10 +100,20 @@ class DateParser : public AllStatic {
}
// The skip methods return whether they actually skipped something.
bool Skip(uint32_t c) { return ch_ == c ? (Next(), true) : false; }
bool Skip(uint32_t c) {
if (ch_ == c) {
Next();
return true;
}
return false;
}
bool SkipWhiteSpace() {
return Scanner::kIsWhiteSpace.get(ch_) ? (Next(), true) : false;
if (ScannerConstants::kIsWhiteSpace.get(ch_)) {
Next();
return true;
}
return false;
}
bool SkipParentheses() {

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));

39
deps/v8/src/dtoa.cc

@ -30,6 +30,7 @@
#include "v8.h"
#include "dtoa.h"
#include "bignum-dtoa.h"
#include "double.h"
#include "fast-dtoa.h"
#include "fixed-dtoa.h"
@ -37,7 +38,19 @@
namespace v8 {
namespace internal {
bool DoubleToAscii(double v, DtoaMode mode, int requested_digits,
static BignumDtoaMode DtoaToBignumDtoaMode(DtoaMode dtoa_mode) {
switch (dtoa_mode) {
case DTOA_SHORTEST: return BIGNUM_DTOA_SHORTEST;
case DTOA_FIXED: return BIGNUM_DTOA_FIXED;
case DTOA_PRECISION: return BIGNUM_DTOA_PRECISION;
default:
UNREACHABLE();
return BIGNUM_DTOA_SHORTEST; // To silence compiler.
}
}
void DoubleToAscii(double v, DtoaMode mode, int requested_digits,
Vector<char> buffer, int* sign, int* length, int* point) {
ASSERT(!Double(v).IsSpecial());
ASSERT(mode == DTOA_SHORTEST || requested_digits >= 0);
@ -54,25 +67,37 @@ bool DoubleToAscii(double v, DtoaMode mode, int requested_digits,
buffer[1] = '\0';
*length = 1;
*point = 1;
return true;
return;
}
if (mode == DTOA_PRECISION && requested_digits == 0) {
buffer[0] = '\0';
*length = 0;
return true;
return;
}
bool fast_worked;
switch (mode) {
case DTOA_SHORTEST:
return FastDtoa(v, FAST_DTOA_SHORTEST, 0, buffer, length, point);
fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST, 0, buffer, length, point);
break;
case DTOA_FIXED:
return FastFixedDtoa(v, requested_digits, buffer, length, point);
fast_worked = FastFixedDtoa(v, requested_digits, buffer, length, point);
break;
case DTOA_PRECISION:
return FastDtoa(v, FAST_DTOA_PRECISION, requested_digits,
fast_worked = FastDtoa(v, FAST_DTOA_PRECISION, requested_digits,
buffer, length, point);
break;
default:
UNREACHABLE();
fast_worked = false;
}
return false;
if (fast_worked) return;
// If the fast dtoa didn't succeed use the slower bignum version.
BignumDtoaMode bignum_mode = DtoaToBignumDtoaMode(mode);
BignumDtoa(v, bignum_mode, requested_digits, buffer, length, point);
buffer[*length] = '\0';
}
} } // namespace v8::internal

14
deps/v8/src/dtoa.h

@ -32,13 +32,15 @@ namespace v8 {
namespace internal {
enum DtoaMode {
// 0.9999999999999999 becomes 0.1
// Return the shortest correct representation.
// For example the output of 0.299999999999999988897 is (the less accurate but
// correct) 0.3.
DTOA_SHORTEST,
// Fixed number of digits after the decimal point.
// Return a fixed number of digits after the decimal point.
// For instance fixed(0.1, 4) becomes 0.1000
// If the input number is big, the output will be big.
DTOA_FIXED,
// Fixed number of digits (independent of the decimal point).
// Return a fixed number of digits, no matter what the exponent is.
DTOA_PRECISION
};
@ -72,8 +74,10 @@ static const int kBase10MaximalLength = 17;
// which case the caller has to fill the missing digits with '0's.
// Halfway cases are again rounded away from 0.
// 'DoubleToAscii' expects the given buffer to be big enough to hold all digits
// and a terminating null-character.
bool DoubleToAscii(double v, DtoaMode mode, int requested_digits,
// and a terminating null-character. In SHORTEST-mode it expects a buffer of
// at least kBase10MaximalLength + 1. Otherwise, the size of the output is
// limited to requested_digits digits plus the null terminator.
void DoubleToAscii(double v, DtoaMode mode, int requested_digits,
Vector<char> buffer, int* sign, int* length, int* point);
} } // namespace v8::internal

131
deps/v8/src/execution.cc

@ -700,135 +700,4 @@ MaybeObject* Execution::HandleStackGuardInterrupt() {
return Heap::undefined_value();
}
// --- G C E x t e n s i o n ---
const char* const GCExtension::kSource = "native function gc();";
v8::Handle<v8::FunctionTemplate> GCExtension::GetNativeFunction(
v8::Handle<v8::String> str) {
return v8::FunctionTemplate::New(GCExtension::GC);
}
v8::Handle<v8::Value> GCExtension::GC(const v8::Arguments& args) {
// All allocation spaces other than NEW_SPACE have the same effect.
Heap::CollectAllGarbage(false);
return v8::Undefined();
}
static GCExtension gc_extension;
static v8::DeclareExtension gc_extension_declaration(&gc_extension);
// --- E x t e r n a l i z e S t r i n g E x t e n s i o n ---
template <typename Char, typename Base>
class SimpleStringResource : public Base {
public:
// Takes ownership of |data|.
SimpleStringResource(Char* data, size_t length)
: data_(data),
length_(length) {}
virtual ~SimpleStringResource() { delete[] data_; }
virtual const Char* data() const { return data_; }
virtual size_t length() const { return length_; }
private:
Char* const data_;
const size_t length_;
};
typedef SimpleStringResource<char, v8::String::ExternalAsciiStringResource>
SimpleAsciiStringResource;
typedef SimpleStringResource<uc16, v8::String::ExternalStringResource>
SimpleTwoByteStringResource;
const char* const ExternalizeStringExtension::kSource =
"native function externalizeString();"
"native function isAsciiString();";
v8::Handle<v8::FunctionTemplate> ExternalizeStringExtension::GetNativeFunction(
v8::Handle<v8::String> str) {
if (strcmp(*v8::String::AsciiValue(str), "externalizeString") == 0) {
return v8::FunctionTemplate::New(ExternalizeStringExtension::Externalize);
} else {
ASSERT(strcmp(*v8::String::AsciiValue(str), "isAsciiString") == 0);
return v8::FunctionTemplate::New(ExternalizeStringExtension::IsAscii);
}
}
v8::Handle<v8::Value> ExternalizeStringExtension::Externalize(
const v8::Arguments& args) {
if (args.Length() < 1 || !args[0]->IsString()) {
return v8::ThrowException(v8::String::New(
"First parameter to externalizeString() must be a string."));
}
bool force_two_byte = false;
if (args.Length() >= 2) {
if (args[1]->IsBoolean()) {
force_two_byte = args[1]->BooleanValue();
} else {
return v8::ThrowException(v8::String::New(
"Second parameter to externalizeString() must be a boolean."));
}
}
bool result = false;
Handle<String> string = Utils::OpenHandle(*args[0].As<v8::String>());
if (string->IsExternalString()) {
return v8::ThrowException(v8::String::New(
"externalizeString() can't externalize twice."));
}
if (string->IsAsciiRepresentation() && !force_two_byte) {
char* data = new char[string->length()];
String::WriteToFlat(*string, data, 0, string->length());
SimpleAsciiStringResource* resource = new SimpleAsciiStringResource(
data, string->length());
result = string->MakeExternal(resource);
if (result && !string->IsSymbol()) {
i::ExternalStringTable::AddString(*string);
}
if (!result) delete resource;
} else {
uc16* data = new uc16[string->length()];
String::WriteToFlat(*string, data, 0, string->length());
SimpleTwoByteStringResource* resource = new SimpleTwoByteStringResource(
data, string->length());
result = string->MakeExternal(resource);
if (result && !string->IsSymbol()) {
i::ExternalStringTable::AddString(*string);
}
if (!result) delete resource;
}
if (!result) {
return v8::ThrowException(v8::String::New("externalizeString() failed."));
}
return v8::Undefined();
}
v8::Handle<v8::Value> ExternalizeStringExtension::IsAscii(
const v8::Arguments& args) {
if (args.Length() != 1 || !args[0]->IsString()) {
return v8::ThrowException(v8::String::New(
"isAsciiString() requires a single string argument."));
}
return Utils::OpenHandle(*args[0].As<v8::String>())->IsAsciiRepresentation() ?
v8::True() : v8::False();
}
static ExternalizeStringExtension externalize_extension;
static v8::DeclareExtension externalize_extension_declaration(
&externalize_extension);
} } // namespace v8::internal

26
deps/v8/src/execution.h

@ -189,6 +189,9 @@ class StackGuard : public AllStatic {
static uintptr_t climit() {
return thread_local_.climit_;
}
static uintptr_t real_climit() {
return thread_local_.real_climit_;
}
static uintptr_t jslimit() {
return thread_local_.jslimit_;
}
@ -313,29 +316,6 @@ class PostponeInterruptsScope BASE_EMBEDDED {
}
};
class GCExtension : public v8::Extension {
public:
GCExtension() : v8::Extension("v8/gc", kSource) {}
virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
v8::Handle<v8::String> name);
static v8::Handle<v8::Value> GC(const v8::Arguments& args);
private:
static const char* const kSource;
};
class ExternalizeStringExtension : public v8::Extension {
public:
ExternalizeStringExtension() : v8::Extension("v8/externalize", kSource) {}
virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
v8::Handle<v8::String> name);
static v8::Handle<v8::Value> Externalize(const v8::Arguments& args);
static v8::Handle<v8::Value> IsAscii(const v8::Arguments& args);
private:
static const char* const kSource;
};
} } // namespace v8::internal
#endif // V8_EXECUTION_H_

141
deps/v8/src/extensions/externalize-string-extension.cc

@ -0,0 +1,141 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "externalize-string-extension.h"
namespace v8 {
namespace internal {
template <typename Char, typename Base>
class SimpleStringResource : public Base {
public:
// Takes ownership of |data|.
SimpleStringResource(Char* data, size_t length)
: data_(data),
length_(length) {}
virtual ~SimpleStringResource() { delete[] data_; }
virtual const Char* data() const { return data_; }
virtual size_t length() const { return length_; }
private:
Char* const data_;
const size_t length_;
};
typedef SimpleStringResource<char, v8::String::ExternalAsciiStringResource>
SimpleAsciiStringResource;
typedef SimpleStringResource<uc16, v8::String::ExternalStringResource>
SimpleTwoByteStringResource;
const char* const ExternalizeStringExtension::kSource =
"native function externalizeString();"
"native function isAsciiString();";
v8::Handle<v8::FunctionTemplate> ExternalizeStringExtension::GetNativeFunction(
v8::Handle<v8::String> str) {
if (strcmp(*v8::String::AsciiValue(str), "externalizeString") == 0) {
return v8::FunctionTemplate::New(ExternalizeStringExtension::Externalize);
} else {
ASSERT(strcmp(*v8::String::AsciiValue(str), "isAsciiString") == 0);
return v8::FunctionTemplate::New(ExternalizeStringExtension::IsAscii);
}
}
v8::Handle<v8::Value> ExternalizeStringExtension::Externalize(
const v8::Arguments& args) {
if (args.Length() < 1 || !args[0]->IsString()) {
return v8::ThrowException(v8::String::New(
"First parameter to externalizeString() must be a string."));
}
bool force_two_byte = false;
if (args.Length() >= 2) {
if (args[1]->IsBoolean()) {
force_two_byte = args[1]->BooleanValue();
} else {
return v8::ThrowException(v8::String::New(
"Second parameter to externalizeString() must be a boolean."));
}
}
bool result = false;
Handle<String> string = Utils::OpenHandle(*args[0].As<v8::String>());
if (string->IsExternalString()) {
return v8::ThrowException(v8::String::New(
"externalizeString() can't externalize twice."));
}
if (string->IsAsciiRepresentation() && !force_two_byte) {
char* data = new char[string->length()];
String::WriteToFlat(*string, data, 0, string->length());
SimpleAsciiStringResource* resource = new SimpleAsciiStringResource(
data, string->length());
result = string->MakeExternal(resource);
if (result && !string->IsSymbol()) {
i::ExternalStringTable::AddString(*string);
}
if (!result) delete resource;
} else {
uc16* data = new uc16[string->length()];
String::WriteToFlat(*string, data, 0, string->length());
SimpleTwoByteStringResource* resource = new SimpleTwoByteStringResource(
data, string->length());
result = string->MakeExternal(resource);
if (result && !string->IsSymbol()) {
i::ExternalStringTable::AddString(*string);
}
if (!result) delete resource;
}
if (!result) {
return v8::ThrowException(v8::String::New("externalizeString() failed."));
}
return v8::Undefined();
}
v8::Handle<v8::Value> ExternalizeStringExtension::IsAscii(
const v8::Arguments& args) {
if (args.Length() != 1 || !args[0]->IsString()) {
return v8::ThrowException(v8::String::New(
"isAsciiString() requires a single string argument."));
}
return Utils::OpenHandle(*args[0].As<v8::String>())->IsAsciiRepresentation() ?
v8::True() : v8::False();
}
void ExternalizeStringExtension::Register() {
static ExternalizeStringExtension externalize_extension;
static v8::DeclareExtension externalize_extension_declaration(
&externalize_extension);
}
} } // namespace v8::internal

50
deps/v8/src/extensions/externalize-string-extension.h

@ -0,0 +1,50 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef V8_EXTENSIONS_EXTERNALIZE_STRING_EXTENSION_H_
#define V8_EXTENSIONS_EXTERNALIZE_STRING_EXTENSION_H_
#include "v8.h"
namespace v8 {
namespace internal {
class ExternalizeStringExtension : public v8::Extension {
public:
ExternalizeStringExtension() : v8::Extension("v8/externalize", kSource) {}
virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
v8::Handle<v8::String> name);
static v8::Handle<v8::Value> Externalize(const v8::Arguments& args);
static v8::Handle<v8::Value> IsAscii(const v8::Arguments& args);
static void Register();
private:
static const char* const kSource;
};
} } // namespace v8::internal
#endif // V8_EXTENSIONS_EXTERNALIZE_STRING_EXTENSION_H_

54
deps/v8/src/extensions/gc-extension.cc

@ -0,0 +1,54 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "gc-extension.h"
namespace v8 {
namespace internal {
const char* const GCExtension::kSource = "native function gc();";
v8::Handle<v8::FunctionTemplate> GCExtension::GetNativeFunction(
v8::Handle<v8::String> str) {
return v8::FunctionTemplate::New(GCExtension::GC);
}
v8::Handle<v8::Value> GCExtension::GC(const v8::Arguments& args) {
// All allocation spaces other than NEW_SPACE have the same effect.
Heap::CollectAllGarbage(false);
return v8::Undefined();
}
void GCExtension::Register() {
static GCExtension gc_extension;
static v8::DeclareExtension gc_extension_declaration(&gc_extension);
}
} } // namespace v8::internal

49
deps/v8/src/extensions/gc-extension.h

@ -0,0 +1,49 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef V8_EXTENSIONS_GC_EXTENSION_H_
#define V8_EXTENSIONS_GC_EXTENSION_H_
#include "v8.h"
namespace v8 {
namespace internal {
class GCExtension : public v8::Extension {
public:
GCExtension() : v8::Extension("v8/gc", kSource) {}
virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
v8::Handle<v8::String> name);
static v8::Handle<v8::Value> GC(const v8::Arguments& args);
static void Register();
private:
static const char* const kSource;
};
} } // namespace v8::internal
#endif // V8_EXTENSIONS_GC_EXTENSION_H_

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,

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

@ -301,11 +301,6 @@ bool FullCodeGenerator::MakeCode(CompilationInfo* info) {
}
MemOperand FullCodeGenerator::ContextOperand(Register context, int index) {
return CodeGenerator::ContextOperand(context, index);
}
int FullCodeGenerator::SlotOffset(Slot* slot) {
ASSERT(slot != NULL);
// Offset is negative because higher indexes are at lower addresses.
@ -563,9 +558,10 @@ void FullCodeGenerator::SetStatementPosition(int pos) {
}
void FullCodeGenerator::SetSourcePosition(int pos) {
void FullCodeGenerator::SetSourcePosition(
int pos, PositionRecordingType recording_type) {
if (FLAG_debug_info && pos != RelocInfo::kNoPosition) {
masm_->RecordPosition(pos);
masm_->positions_recorder()->RecordPosition(pos, recording_type);
}
}
@ -1225,13 +1221,6 @@ int FullCodeGenerator::TryCatch::Exit(int stack_depth) {
}
void FullCodeGenerator::EmitRegExpCloneResult(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
VisitForStackValue(args->at(0));
__ CallRuntime(Runtime::kRegExpCloneResult, 1);
context()->Plug(result_register());
}
#undef __

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

@ -423,7 +423,9 @@ class FullCodeGenerator: public AstVisitor {
void SetStatementPosition(Statement* stmt);
void SetExpressionPosition(Expression* expr, int pos);
void SetStatementPosition(int pos);
void SetSourcePosition(int pos);
void SetSourcePosition(
int pos,
PositionRecordingType recording_type = NORMAL_POSITION);
// Non-local control flow support.
void EnterFinallyBlock();
@ -462,9 +464,6 @@ class FullCodeGenerator: public AstVisitor {
// in v8::internal::Context.
void LoadContextField(Register dst, int context_index);
// Create an operand for a context field.
MemOperand ContextOperand(Register context, int context_index);
// AST node visit functions.
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
AST_NODE_LIST(DECLARE_VISIT)

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);

432
deps/v8/src/globals.h

@ -1,4 +1,4 @@
// Copyright 2006-2009 the V8 project authors. All rights reserved.
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@ -195,8 +195,8 @@ const int kCharSize = sizeof(char); // NOLINT
const int kShortSize = sizeof(short); // NOLINT
const int kIntSize = sizeof(int); // NOLINT
const int kDoubleSize = sizeof(double); // NOLINT
const int kPointerSize = sizeof(void*); // NOLINT
const int kIntptrSize = sizeof(intptr_t); // NOLINT
const int kPointerSize = sizeof(void*); // NOLINT
#if V8_HOST_ARCH_64_BIT
const int kPointerSizeLog2 = 3;
@ -208,38 +208,6 @@ const intptr_t kIntptrSignBit = 0x80000000;
const uintptr_t kUintptrAllBitsSet = 0xFFFFFFFFu;
#endif
// Mask for the sign bit in a smi.
const intptr_t kSmiSignMask = kIntptrSignBit;
const int kObjectAlignmentBits = kPointerSizeLog2;
const intptr_t kObjectAlignment = 1 << kObjectAlignmentBits;
const intptr_t kObjectAlignmentMask = kObjectAlignment - 1;
// Desired alignment for pointers.
const intptr_t kPointerAlignment = (1 << kPointerSizeLog2);
const intptr_t kPointerAlignmentMask = kPointerAlignment - 1;
// Desired alignment for maps.
#if V8_HOST_ARCH_64_BIT
const intptr_t kMapAlignmentBits = kObjectAlignmentBits;
#else
const intptr_t kMapAlignmentBits = kObjectAlignmentBits + 3;
#endif
const intptr_t kMapAlignment = (1 << kMapAlignmentBits);
const intptr_t kMapAlignmentMask = kMapAlignment - 1;
// Desired alignment for generated code is 32 bytes (to improve cache line
// utilization).
const int kCodeAlignmentBits = 5;
const intptr_t kCodeAlignment = 1 << kCodeAlignmentBits;
const intptr_t kCodeAlignmentMask = kCodeAlignment - 1;
// Tag information for Failure.
const int kFailureTag = 3;
const int kFailureTagSize = 2;
const intptr_t kFailureTagMask = (1 << kFailureTagSize) - 1;
const int kBitsPerByte = 8;
const int kBitsPerByteLog2 = 3;
const int kBitsPerPointer = kPointerSize * kBitsPerByte;
@ -255,364 +223,6 @@ const int kBinary32MinExponent = 0x01;
const int kBinary32MantissaBits = 23;
const int kBinary32ExponentShift = 23;
// Zap-value: The value used for zapping dead objects.
// Should be a recognizable hex value tagged as a heap object pointer.
#ifdef V8_HOST_ARCH_64_BIT
const Address kZapValue =
reinterpret_cast<Address>(V8_UINT64_C(0xdeadbeedbeadbeed));
const Address kHandleZapValue =
reinterpret_cast<Address>(V8_UINT64_C(0x1baddead0baddead));
const Address kFromSpaceZapValue =
reinterpret_cast<Address>(V8_UINT64_C(0x1beefdad0beefdad));
const uint64_t kDebugZapValue = 0xbadbaddbbadbaddb;
#else
const Address kZapValue = reinterpret_cast<Address>(0xdeadbeed);
const Address kHandleZapValue = reinterpret_cast<Address>(0xbaddead);
const Address kFromSpaceZapValue = reinterpret_cast<Address>(0xbeefdad);
const uint32_t kDebugZapValue = 0xbadbaddb;
#endif
// Number of bits to represent the page size for paged spaces. The value of 13
// gives 8K bytes per page.
const int kPageSizeBits = 13;
// On Intel architecture, cache line size is 64 bytes.
// On ARM it may be less (32 bytes), but as far this constant is
// used for aligning data, it doesn't hurt to align on a greater value.
const int kProcessorCacheLineSize = 64;
// Constants relevant to double precision floating point numbers.
// Quiet NaNs have bits 51 to 62 set, possibly the sign bit, and no
// other bits set.
const uint64_t kQuietNaNMask = static_cast<uint64_t>(0xfff) << 51;
// If looking only at the top 32 bits, the QNaN mask is bits 19 to 30.
const uint32_t kQuietNaNHighBitsMask = 0xfff << (51 - 32);
// -----------------------------------------------------------------------------
// Forward declarations for frequently used classes
// (sorted alphabetically)
class AccessorInfo;
class Allocation;
class Arguments;
class Assembler;
class AssertNoAllocation;
class BreakableStatement;
class Code;
class CodeGenerator;
class CodeStub;
class Context;
class Debug;
class Debugger;
class DebugInfo;
class Descriptor;
class DescriptorArray;
class Expression;
class ExternalReference;
class FixedArray;
class FunctionEntry;
class FunctionLiteral;
class FunctionTemplateInfo;
class NumberDictionary;
class StringDictionary;
class FreeStoreAllocationPolicy;
template <typename T> class Handle;
class Heap;
class HeapObject;
class IC;
class InterceptorInfo;
class IterationStatement;
class JSArray;
class JSFunction;
class JSObject;
class LargeObjectSpace;
template <typename T, class P = FreeStoreAllocationPolicy> class List;
class LookupResult;
class MacroAssembler;
class Map;
class MapSpace;
class MarkCompactCollector;
class NewSpace;
class NodeVisitor;
class Object;
class MaybeObject;
class OldSpace;
class Property;
class Proxy;
class RegExpNode;
struct RegExpCompileData;
class RegExpTree;
class RegExpCompiler;
class RegExpVisitor;
class Scope;
template<class Allocator = FreeStoreAllocationPolicy> class ScopeInfo;
class SerializedScopeInfo;
class Script;
class Slot;
class Smi;
template <typename Config, class Allocator = FreeStoreAllocationPolicy>
class SplayTree;
class Statement;
class String;
class Struct;
class SwitchStatement;
class AstVisitor;
class Variable;
class VariableProxy;
class RelocInfo;
class Deserializer;
class MessageLocation;
class ObjectGroup;
class TickSample;
class VirtualMemory;
class Mutex;
typedef bool (*WeakSlotCallback)(Object** pointer);
// -----------------------------------------------------------------------------
// Miscellaneous
// NOTE: SpaceIterator depends on AllocationSpace enumeration values being
// consecutive.
enum AllocationSpace {
NEW_SPACE, // Semispaces collected with copying collector.
OLD_POINTER_SPACE, // May contain pointers to new space.
OLD_DATA_SPACE, // Must not have pointers to new space.
CODE_SPACE, // No pointers to new space, marked executable.
MAP_SPACE, // Only and all map objects.
CELL_SPACE, // Only and all cell objects.
LO_SPACE, // Promoted large objects.
FIRST_SPACE = NEW_SPACE,
LAST_SPACE = LO_SPACE,
FIRST_PAGED_SPACE = OLD_POINTER_SPACE,
LAST_PAGED_SPACE = CELL_SPACE
};
const int kSpaceTagSize = 3;
const int kSpaceTagMask = (1 << kSpaceTagSize) - 1;
// A flag that indicates whether objects should be pretenured when
// allocated (allocated directly into the old generation) or not
// (allocated in the young generation if the object size and type
// allows).
enum PretenureFlag { NOT_TENURED, TENURED };
enum GarbageCollector { SCAVENGER, MARK_COMPACTOR };
enum Executability { NOT_EXECUTABLE, EXECUTABLE };
enum VisitMode { VISIT_ALL, VISIT_ALL_IN_SCAVENGE, VISIT_ONLY_STRONG };
// Flag indicating whether code is built into the VM (one of the natives files).
enum NativesFlag { NOT_NATIVES_CODE, NATIVES_CODE };
// A CodeDesc describes a buffer holding instructions and relocation
// information. The instructions start at the beginning of the buffer
// and grow forward, the relocation information starts at the end of
// the buffer and grows backward.
//
// |<--------------- buffer_size ---------------->|
// |<-- instr_size -->| |<-- reloc_size -->|
// +==================+========+==================+
// | instructions | free | reloc info |
// +==================+========+==================+
// ^
// |
// buffer
struct CodeDesc {
byte* buffer;
int buffer_size;
int instr_size;
int reloc_size;
Assembler* origin;
};
// Callback function on object slots, used for iterating heap object slots in
// HeapObjects, global pointers to heap objects, etc. The callback allows the
// callback function to change the value of the slot.
typedef void (*ObjectSlotCallback)(HeapObject** pointer);
// Callback function used for iterating objects in heap spaces,
// for example, scanning heap objects.
typedef int (*HeapObjectCallback)(HeapObject* obj);
// Callback function used for checking constraints when copying/relocating
// objects. Returns true if an object can be copied/relocated from its
// old_addr to a new_addr.
typedef bool (*ConstraintCallback)(Address new_addr, Address old_addr);
// Callback function on inline caches, used for iterating over inline caches
// in compiled code.
typedef void (*InlineCacheCallback)(Code* code, Address ic);
// State for inline cache call sites. Aliased as IC::State.
enum InlineCacheState {
// Has never been executed.
UNINITIALIZED,
// Has been executed but monomorhic state has been delayed.
PREMONOMORPHIC,
// Has been executed and only one receiver type has been seen.
MONOMORPHIC,
// Like MONOMORPHIC but check failed due to prototype.
MONOMORPHIC_PROTOTYPE_FAILURE,
// Multiple receiver types have been seen.
MEGAMORPHIC,
// Special states for debug break or step in prepare stubs.
DEBUG_BREAK,
DEBUG_PREPARE_STEP_IN
};
enum InLoopFlag {
NOT_IN_LOOP,
IN_LOOP
};
enum CallFunctionFlags {
NO_CALL_FUNCTION_FLAGS = 0,
RECEIVER_MIGHT_BE_VALUE = 1 << 0 // Receiver might not be a JSObject.
};
enum InlineCacheHolderFlag {
OWN_MAP, // For fast properties objects.
PROTOTYPE_MAP // For slow properties objects (except GlobalObjects).
};
// Type of properties.
// Order of properties is significant.
// Must fit in the BitField PropertyDetails::TypeField.
// A copy of this is in mirror-debugger.js.
enum PropertyType {
NORMAL = 0, // only in slow mode
FIELD = 1, // only in fast mode
CONSTANT_FUNCTION = 2, // only in fast mode
CALLBACKS = 3,
INTERCEPTOR = 4, // only in lookup results, not in descriptors.
MAP_TRANSITION = 5, // only in fast mode
CONSTANT_TRANSITION = 6, // only in fast mode
NULL_DESCRIPTOR = 7, // only in fast mode
// All properties before MAP_TRANSITION are real.
FIRST_PHANTOM_PROPERTY_TYPE = MAP_TRANSITION,
// There are no IC stubs for NULL_DESCRIPTORS. Therefore,
// NULL_DESCRIPTOR can be used as the type flag for IC stubs for
// nonexistent properties.
NONEXISTENT = NULL_DESCRIPTOR
};
// Whether to remove map transitions and constant transitions from a
// DescriptorArray.
enum TransitionFlag {
REMOVE_TRANSITIONS,
KEEP_TRANSITIONS
};
// Union used for fast testing of specific double values.
union DoubleRepresentation {
double value;
int64_t bits;
DoubleRepresentation(double x) { value = x; }
};
// Union used for customized checking of the IEEE double types
// inlined within v8 runtime, rather than going to the underlying
// platform headers and libraries
union IeeeDoubleLittleEndianArchType {
double d;
struct {
unsigned int man_low :32;
unsigned int man_high :20;
unsigned int exp :11;
unsigned int sign :1;
} bits;
};
union IeeeDoubleBigEndianArchType {
double d;
struct {
unsigned int sign :1;
unsigned int exp :11;
unsigned int man_high :20;
unsigned int man_low :32;
} bits;
};
// AccessorCallback
struct AccessorDescriptor {
MaybeObject* (*getter)(Object* object, void* data);
MaybeObject* (*setter)(JSObject* object, Object* value, void* data);
void* data;
};
// Logging and profiling.
// A StateTag represents a possible state of the VM. When compiled with
// ENABLE_VMSTATE_TRACKING, the logger maintains a stack of these.
// Creating a VMState object enters a state by pushing on the stack, and
// destroying a VMState object leaves a state by popping the current state
// from the stack.
#define STATE_TAG_LIST(V) \
V(JS) \
V(GC) \
V(COMPILER) \
V(OTHER) \
V(EXTERNAL)
enum StateTag {
#define DEF_STATE_TAG(name) name,
STATE_TAG_LIST(DEF_STATE_TAG)
#undef DEF_STATE_TAG
// Pseudo-types.
state_tag_count
};
// -----------------------------------------------------------------------------
// Macros
// Testers for test.
#define HAS_SMI_TAG(value) \
((reinterpret_cast<intptr_t>(value) & kSmiTagMask) == kSmiTag)
#define HAS_FAILURE_TAG(value) \
((reinterpret_cast<intptr_t>(value) & kFailureTagMask) == kFailureTag)
// OBJECT_POINTER_ALIGN returns the value aligned as a HeapObject pointer
#define OBJECT_POINTER_ALIGN(value) \
(((value) + kObjectAlignmentMask) & ~kObjectAlignmentMask)
// POINTER_SIZE_ALIGN returns the value aligned as a pointer.
#define POINTER_SIZE_ALIGN(value) \
(((value) + kPointerAlignmentMask) & ~kPointerAlignmentMask)
// MAP_POINTER_ALIGN returns the value aligned as a map pointer.
#define MAP_POINTER_ALIGN(value) \
(((value) + kMapAlignmentMask) & ~kMapAlignmentMask)
// CODE_POINTER_ALIGN returns the value aligned as a generated code segment.
#define CODE_POINTER_ALIGN(value) \
(((value) + kCodeAlignmentMask) & ~kCodeAlignmentMask)
// The expression OFFSET_OF(type, field) computes the byte-offset
// of the specified field relative to the containing type. This
// corresponds to 'offsetof' (in stddef.h), except that it doesn't
@ -669,26 +279,6 @@ F FUNCTION_CAST(Address addr) {
DISALLOW_COPY_AND_ASSIGN(TypeName)
// Support for tracking C++ memory allocation. Insert TRACK_MEMORY("Fisk")
// inside a C++ class and new and delete will be overloaded so logging is
// performed.
// This file (globals.h) is included before log.h, so we use direct calls to
// the Logger rather than the LOG macro.
#ifdef DEBUG
#define TRACK_MEMORY(name) \
void* operator new(size_t size) { \
void* result = ::operator new(size); \
Logger::NewEvent(name, result, size); \
return result; \
} \
void operator delete(void* object) { \
Logger::DeleteEvent(name, object); \
::operator delete(object); \
}
#else
#define TRACK_MEMORY(name)
#endif
// Define used for helping GCC to make better inlining. Don't bother for debug
// builds. On GCC 3.4.5 using __attribute__((always_inline)) causes compilation
// errors in debug build.
@ -712,20 +302,12 @@ F FUNCTION_CAST(Address addr) {
#define MUST_USE_RESULT
#endif
// -----------------------------------------------------------------------------
// Forward declarations for frequently used classes
// (sorted alphabetically)
// Feature flags bit positions. They are mostly based on the CPUID spec.
// (We assign CPUID itself to one of the currently reserved bits --
// feel free to change this if needed.)
// On X86/X64, values below 32 are bits in EDX, values above 32 are bits in ECX.
enum CpuFeature { SSE4_1 = 32 + 19, // x86
SSE3 = 32 + 0, // x86
SSE2 = 26, // x86
CMOV = 15, // x86
RDTSC = 4, // x86
CPUID = 10, // x86
VFP3 = 1, // ARM
ARMv7 = 2, // ARM
SAHF = 0}; // x86
class FreeStoreAllocationPolicy;
template <typename T, class P = FreeStoreAllocationPolicy> class List;
} } // namespace v8::internal

4
deps/v8/src/handles.cc

@ -499,6 +499,10 @@ void InitScriptLineEnds(Handle<Script> script) {
Handle<FixedArray> array = CalculateLineEnds(src, true);
if (*array != Heap::empty_fixed_array()) {
array->set_map(Heap::fixed_cow_array_map());
}
script->set_line_ends(*array);
ASSERT(script->line_ends()->IsFixedArray());
}

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; \

4
deps/v8/src/heap-profiler.cc

@ -788,15 +788,13 @@ void AggregatedHeapSnapshotGenerator::CalculateStringsStats() {
void AggregatedHeapSnapshotGenerator::CollectStats(HeapObject* obj) {
InstanceType type = obj->map()->instance_type();
ASSERT(0 <= type && type <= LAST_TYPE);
if (!FreeListNode::IsFreeListNode(obj)) {
agg_snapshot_->info()[type].increment_number(1);
agg_snapshot_->info()[type].increment_bytes(obj->Size());
}
}
void AggregatedHeapSnapshotGenerator::GenerateSnapshot() {
HeapIterator iterator;
HeapIterator iterator(HeapIterator::kPreciseFiltering);
for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
CollectStats(obj);
agg_snapshot_->js_cons_profile()->CollectStats(obj);

196
deps/v8/src/heap.cc

@ -38,7 +38,7 @@
#include "mark-compact.h"
#include "natives.h"
#include "objects-visiting.h"
#include "scanner.h"
#include "scanner-base.h"
#include "scopeinfo.h"
#include "snapshot.h"
#include "v8threads.h"
@ -79,20 +79,32 @@ int Heap::amount_of_external_allocated_memory_at_last_global_gc_ = 0;
// semispace_size_ should be a power of 2 and old_generation_size_ should be
// a multiple of Page::kPageSize.
#if defined(ANDROID)
int Heap::max_semispace_size_ = 2*MB;
static const int default_max_semispace_size_ = 2*MB;
intptr_t Heap::max_old_generation_size_ = 192*MB;
int Heap::initial_semispace_size_ = 128*KB;
intptr_t Heap::code_range_size_ = 0;
intptr_t Heap::max_executable_size_ = max_old_generation_size_;
#elif defined(V8_TARGET_ARCH_X64)
int Heap::max_semispace_size_ = 16*MB;
static const int default_max_semispace_size_ = 16*MB;
intptr_t Heap::max_old_generation_size_ = 1*GB;
int Heap::initial_semispace_size_ = 1*MB;
intptr_t Heap::code_range_size_ = 512*MB;
intptr_t Heap::max_executable_size_ = 256*MB;
#else
int Heap::max_semispace_size_ = 8*MB;
static const int default_max_semispace_size_ = 8*MB;
intptr_t Heap::max_old_generation_size_ = 512*MB;
int Heap::initial_semispace_size_ = 512*KB;
intptr_t Heap::code_range_size_ = 0;
intptr_t Heap::max_executable_size_ = 128*MB;
#endif
// Allow build-time customization of the max semispace size. Building
// V8 with snapshots and a non-default max semispace size is much
// easier if you can define it as part of the build environment.
#if defined(V8_MAX_SEMISPACE_SIZE)
int Heap::max_semispace_size_ = V8_MAX_SEMISPACE_SIZE;
#else
int Heap::max_semispace_size_ = default_max_semispace_size_;
#endif
// The snapshot semispace size will be the default semispace size if
@ -172,6 +184,12 @@ intptr_t Heap::CommittedMemory() {
lo_space_->Size();
}
intptr_t Heap::CommittedMemoryExecutable() {
if (!HasBeenSetup()) return 0;
return MemoryAllocator::SizeExecutable();
}
intptr_t Heap::Available() {
if (!HasBeenSetup()) return 0;
@ -386,7 +404,7 @@ intptr_t Heap::SizeOfObjects() {
intptr_t total = 0;
AllSpaces spaces;
for (Space* space = spaces.next(); space != NULL; space = spaces.next()) {
total += space->Size();
total += space->SizeOfObjects();
}
return total;
}
@ -429,7 +447,31 @@ void Heap::CollectAllGarbage(bool force_compaction) {
}
void Heap::CollectGarbage(AllocationSpace space) {
void Heap::CollectAllAvailableGarbage() {
// Since we are ignoring the return value, the exact choice of space does
// not matter, so long as we do not specify NEW_SPACE, which would not
// cause a full GC.
MarkCompactCollector::SetForceCompaction(true);
// Major GC would invoke weak handle callbacks on weakly reachable
// handles, but won't collect weakly reachable objects until next
// major GC. Therefore if we collect aggressively and weak handle callback
// has been invoked, we rerun major GC to release objects which become
// garbage.
// Note: as weak callbacks can execute arbitrary code, we cannot
// hope that eventually there will be no weak callbacks invocations.
// Therefore stop recollecting after several attempts.
const int kMaxNumberOfAttempts = 7;
for (int attempt = 0; attempt < kMaxNumberOfAttempts; attempt++) {
if (!CollectGarbage(OLD_POINTER_SPACE, MARK_COMPACTOR)) {
break;
}
}
MarkCompactCollector::SetForceCompaction(false);
}
bool Heap::CollectGarbage(AllocationSpace space, GarbageCollector collector) {
// The VM is in the GC state until exiting this function.
VMState state(GC);
@ -442,13 +484,14 @@ void Heap::CollectGarbage(AllocationSpace space) {
allocation_timeout_ = Max(6, FLAG_gc_interval);
#endif
bool next_gc_likely_to_collect_more = false;
{ GCTracer tracer;
GarbageCollectionPrologue();
// The GC count was incremented in the prologue. Tell the tracer about
// it.
tracer.set_gc_count(gc_count_);
GarbageCollector collector = SelectGarbageCollector(space);
// Tell the tracer which collector we've selected.
tracer.set_collector(collector);
@ -456,6 +499,7 @@ void Heap::CollectGarbage(AllocationSpace space) {
? &Counters::gc_scavenger
: &Counters::gc_compactor;
rate->Start();
next_gc_likely_to_collect_more =
PerformGarbageCollection(collector, &tracer);
rate->Stop();
@ -467,6 +511,8 @@ void Heap::CollectGarbage(AllocationSpace space) {
if (FLAG_log_gc) HeapProfiler::WriteSample();
if (CpuProfiler::is_profiling()) CpuProfiler::ProcessMovedFunctions();
#endif
return next_gc_likely_to_collect_more;
}
@ -653,8 +699,10 @@ void Heap::UpdateSurvivalRateTrend(int start_new_space_size) {
survival_rate_ = survival_rate;
}
void Heap::PerformGarbageCollection(GarbageCollector collector,
bool Heap::PerformGarbageCollection(GarbageCollector collector,
GCTracer* tracer) {
bool next_gc_likely_to_collect_more = false;
if (collector != SCAVENGER) {
PROFILE(CodeMovingGCEvent());
}
@ -720,6 +768,7 @@ void Heap::PerformGarbageCollection(GarbageCollector collector,
if (collector == MARK_COMPACTOR) {
DisableAssertNoAllocation allow_allocation;
GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
next_gc_likely_to_collect_more =
GlobalHandles::PostGarbageCollectionProcessing();
}
@ -747,6 +796,8 @@ void Heap::PerformGarbageCollection(GarbageCollector collector,
global_gc_epilogue_callback_();
}
VerifySymbolTable();
return next_gc_likely_to_collect_more;
}
@ -3198,7 +3249,8 @@ MaybeObject* Heap::AllocateStringFromUtf8(Vector<const char> string,
const uc32 kMaxSupportedChar = 0xFFFF;
// Count the number of characters in the UTF-8 string and check if
// it is an ASCII string.
Access<Scanner::Utf8Decoder> decoder(Scanner::utf8_decoder());
Access<ScannerConstants::Utf8Decoder>
decoder(ScannerConstants::utf8_decoder());
decoder->Reset(string.start(), string.length());
int chars = 0;
bool is_ascii = true;
@ -4280,7 +4332,9 @@ static bool heap_configured = false;
// TODO(1236194): Since the heap size is configurable on the command line
// and through the API, we should gracefully handle the case that the heap
// size is not big enough to fit all the initial objects.
bool Heap::ConfigureHeap(int max_semispace_size, int max_old_gen_size) {
bool Heap::ConfigureHeap(int max_semispace_size,
int max_old_gen_size,
int max_executable_size) {
if (HasBeenSetup()) return false;
if (max_semispace_size > 0) max_semispace_size_ = max_semispace_size;
@ -4301,6 +4355,15 @@ bool Heap::ConfigureHeap(int max_semispace_size, int max_old_gen_size) {
}
if (max_old_gen_size > 0) max_old_generation_size_ = max_old_gen_size;
if (max_executable_size > 0) {
max_executable_size_ = RoundUp(max_executable_size, Page::kPageSize);
}
// The max executable size must be less than or equal to the max old
// generation size.
if (max_executable_size_ > max_old_generation_size_) {
max_executable_size_ = max_old_generation_size_;
}
// The new space size must be a power of two to support single-bit testing
// for containment.
@ -4318,8 +4381,9 @@ bool Heap::ConfigureHeap(int max_semispace_size, int max_old_gen_size) {
bool Heap::ConfigureHeapDefault() {
return ConfigureHeap(
FLAG_max_new_space_size * (KB / 2), FLAG_max_old_space_size * MB);
return ConfigureHeap(FLAG_max_new_space_size / 2 * KB,
FLAG_max_old_space_size * MB,
FLAG_max_executable_size * MB);
}
@ -4345,13 +4409,10 @@ void Heap::RecordStats(HeapStats* stats, bool take_snapshot) {
MemoryAllocator::Size() + MemoryAllocator::Available();
*stats->os_error = OS::GetLastError();
if (take_snapshot) {
HeapIterator iterator;
HeapIterator iterator(HeapIterator::kPreciseFiltering);
for (HeapObject* obj = iterator.next();
obj != NULL;
obj = iterator.next()) {
// Note: snapshot won't be precise because IsFreeListNode returns true
// for any bytearray.
if (FreeListNode::IsFreeListNode(obj)) continue;
InstanceType type = obj->map()->instance_type();
ASSERT(0 <= type && type <= LAST_TYPE);
stats->objects_per_type[type]++;
@ -4402,7 +4463,7 @@ bool Heap::Setup(bool create_heap_objects) {
// space. The chunk is double the size of the requested reserved
// new space size to ensure that we can find a pair of semispaces that
// are contiguous and aligned to their size.
if (!MemoryAllocator::Setup(MaxReserved())) return false;
if (!MemoryAllocator::Setup(MaxReserved(), MaxExecutableSize())) return false;
void* chunk =
MemoryAllocator::ReserveInitialChunk(4 * reserved_semispace_size_);
if (chunk == NULL) return false;
@ -4706,7 +4767,17 @@ OldSpace* OldSpaces::next() {
}
SpaceIterator::SpaceIterator() : current_space_(FIRST_SPACE), iterator_(NULL) {
SpaceIterator::SpaceIterator()
: current_space_(FIRST_SPACE),
iterator_(NULL),
size_func_(NULL) {
}
SpaceIterator::SpaceIterator(HeapObjectCallback size_func)
: current_space_(FIRST_SPACE),
iterator_(NULL),
size_func_(size_func) {
}
@ -4744,25 +4815,25 @@ ObjectIterator* SpaceIterator::CreateIterator() {
switch (current_space_) {
case NEW_SPACE:
iterator_ = new SemiSpaceIterator(Heap::new_space());
iterator_ = new SemiSpaceIterator(Heap::new_space(), size_func_);
break;
case OLD_POINTER_SPACE:
iterator_ = new HeapObjectIterator(Heap::old_pointer_space());
iterator_ = new HeapObjectIterator(Heap::old_pointer_space(), size_func_);
break;
case OLD_DATA_SPACE:
iterator_ = new HeapObjectIterator(Heap::old_data_space());
iterator_ = new HeapObjectIterator(Heap::old_data_space(), size_func_);
break;
case CODE_SPACE:
iterator_ = new HeapObjectIterator(Heap::code_space());
iterator_ = new HeapObjectIterator(Heap::code_space(), size_func_);
break;
case MAP_SPACE:
iterator_ = new HeapObjectIterator(Heap::map_space());
iterator_ = new HeapObjectIterator(Heap::map_space(), size_func_);
break;
case CELL_SPACE:
iterator_ = new HeapObjectIterator(Heap::cell_space());
iterator_ = new HeapObjectIterator(Heap::cell_space(), size_func_);
break;
case LO_SPACE:
iterator_ = new LargeObjectIterator(Heap::lo_space());
iterator_ = new LargeObjectIterator(Heap::lo_space(), size_func_);
break;
}
@ -4772,7 +4843,54 @@ ObjectIterator* SpaceIterator::CreateIterator() {
}
HeapIterator::HeapIterator() {
class FreeListNodesFilter {
public:
FreeListNodesFilter() {
MarkFreeListNodes();
}
inline bool IsFreeListNode(HeapObject* object) {
if (object->IsMarked()) {
object->ClearMark();
return true;
} else {
return false;
}
}
private:
void MarkFreeListNodes() {
Heap::old_pointer_space()->MarkFreeListNodes();
Heap::old_data_space()->MarkFreeListNodes();
MarkCodeSpaceFreeListNodes();
Heap::map_space()->MarkFreeListNodes();
Heap::cell_space()->MarkFreeListNodes();
}
void MarkCodeSpaceFreeListNodes() {
// For code space, using FreeListNode::IsFreeListNode is OK.
HeapObjectIterator iter(Heap::code_space());
for (HeapObject* obj = iter.next_object();
obj != NULL;
obj = iter.next_object()) {
if (FreeListNode::IsFreeListNode(obj)) obj->SetMark();
}
}
AssertNoAllocation no_alloc;
};
HeapIterator::HeapIterator()
: filtering_(HeapIterator::kNoFiltering),
filter_(NULL) {
Init();
}
HeapIterator::HeapIterator(HeapIterator::FreeListNodesFiltering filtering)
: filtering_(filtering),
filter_(NULL) {
Init();
}
@ -4784,20 +4902,44 @@ HeapIterator::~HeapIterator() {
void HeapIterator::Init() {
// Start the iteration.
space_iterator_ = new SpaceIterator();
if (filtering_ == kPreciseFiltering) {
filter_ = new FreeListNodesFilter;
space_iterator_ =
new SpaceIterator(MarkCompactCollector::SizeOfMarkedObject);
} else {
space_iterator_ = new SpaceIterator;
}
object_iterator_ = space_iterator_->next();
}
void HeapIterator::Shutdown() {
#ifdef DEBUG
// Assert that in precise mode we have iterated through all
// objects. Otherwise, heap will be left in an inconsistent state.
if (filtering_ == kPreciseFiltering) {
ASSERT(object_iterator_ == NULL);
}
#endif
// Make sure the last iterator is deallocated.
delete space_iterator_;
space_iterator_ = NULL;
object_iterator_ = NULL;
delete filter_;
filter_ = NULL;
}
HeapObject* HeapIterator::next() {
if (filter_ == NULL) return NextObject();
HeapObject* obj = NextObject();
while (obj != NULL && filter_->IsFreeListNode(obj)) obj = NextObject();
return obj;
}
HeapObject* HeapIterator::NextObject() {
// No iterator means we are done.
if (object_iterator_ == NULL) return NULL;

55
deps/v8/src/heap.h

@ -222,7 +222,9 @@ class Heap : public AllStatic {
public:
// Configure heap size before setup. Return false if the heap has been
// setup already.
static bool ConfigureHeap(int max_semispace_size, int max_old_gen_size);
static bool ConfigureHeap(int max_semispace_size,
int max_old_gen_size,
int max_executable_size);
static bool ConfigureHeapDefault();
// Initializes the global object heap. If create_heap_objects is true,
@ -253,6 +255,7 @@ class Heap : public AllStatic {
static int ReservedSemiSpaceSize() { return reserved_semispace_size_; }
static int InitialSemiSpaceSize() { return initial_semispace_size_; }
static intptr_t MaxOldGenerationSize() { return max_old_generation_size_; }
static intptr_t MaxExecutableSize() { return max_executable_size_; }
// Returns the capacity of the heap in bytes w/o growing. Heap grows when
// more spaces are needed until it reaches the limit.
@ -261,6 +264,9 @@ class Heap : public AllStatic {
// Returns the amount of memory currently committed for the heap.
static intptr_t CommittedMemory();
// Returns the amount of executable memory currently committed for the heap.
static intptr_t CommittedMemoryExecutable();
// Returns the available bytes in space w/o growing.
// Heap doesn't guarantee that it can allocate an object that requires
// all available bytes. Check MaxHeapObjectSize() instead.
@ -705,13 +711,22 @@ class Heap : public AllStatic {
static void GarbageCollectionEpilogue();
// Performs garbage collection operation.
// Returns whether required_space bytes are available after the collection.
static void CollectGarbage(AllocationSpace space);
// Returns whether there is a chance that another major GC could
// collect more garbage.
static bool CollectGarbage(AllocationSpace space, GarbageCollector collector);
// Performs garbage collection operation.
// Returns whether there is a chance that another major GC could
// collect more garbage.
inline static bool CollectGarbage(AllocationSpace space);
// Performs a full garbage collection. Force compaction if the
// parameter is true.
static void CollectAllGarbage(bool force_compaction);
// Last hope GC, should try to squeeze as much as possible.
static void CollectAllAvailableGarbage();
// Notify the heap that a context has been disposed.
static int NotifyContextDisposed() { return ++contexts_disposed_; }
@ -1087,6 +1102,7 @@ class Heap : public AllStatic {
static int max_semispace_size_;
static int initial_semispace_size_;
static intptr_t max_old_generation_size_;
static intptr_t max_executable_size_;
static intptr_t code_range_size_;
// For keeping track of how much data has survived
@ -1246,7 +1262,9 @@ class Heap : public AllStatic {
static GarbageCollector SelectGarbageCollector(AllocationSpace space);
// Performs garbage collection
static void PerformGarbageCollection(GarbageCollector collector,
// Returns whether there is a chance another major GC could
// collect more garbage.
static bool PerformGarbageCollection(GarbageCollector collector,
GCTracer* tracer);
// Allocate an uninitialized object in map space. The behavior is identical
@ -1540,6 +1558,7 @@ class PagedSpaces BASE_EMBEDDED {
class SpaceIterator : public Malloced {
public:
SpaceIterator();
explicit SpaceIterator(HeapObjectCallback size_func);
virtual ~SpaceIterator();
bool has_next();
@ -1550,17 +1569,31 @@ class SpaceIterator : public Malloced {
int current_space_; // from enum AllocationSpace.
ObjectIterator* iterator_; // object iterator for the current space.
HeapObjectCallback size_func_;
};
// A HeapIterator provides iteration over the whole heap It aggregates a the
// specific iterators for the different spaces as these can only iterate over
// one space only.
// A HeapIterator provides iteration over the whole heap. It
// aggregates the specific iterators for the different spaces as
// these can only iterate over one space only.
//
// HeapIterator can skip free list nodes (that is, de-allocated heap
// objects that still remain in the heap). As implementation of free
// nodes filtering uses GC marks, it can't be used during MS/MC GC
// phases. Also, it is forbidden to interrupt iteration in this mode,
// as this will leave heap objects marked (and thus, unusable).
class FreeListNodesFilter;
class HeapIterator BASE_EMBEDDED {
public:
explicit HeapIterator();
virtual ~HeapIterator();
enum FreeListNodesFiltering {
kNoFiltering,
kPreciseFiltering
};
HeapIterator();
explicit HeapIterator(FreeListNodesFiltering filtering);
~HeapIterator();
HeapObject* next();
void reset();
@ -1568,10 +1601,12 @@ class HeapIterator BASE_EMBEDDED {
private:
// Perform the initialization.
void Init();
// Perform all necessary shutdown (destruction) work.
void Shutdown();
HeapObject* NextObject();
FreeListNodesFiltering filtering_;
FreeListNodesFilter* filter_;
// Space iterator for iterating all the spaces.
SpaceIterator* space_iterator_;
// Object iterator for the space currently being iterated.

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;
};

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

@ -3058,15 +3058,6 @@ void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
}
void ApiGetterEntryStub::Generate(MacroAssembler* masm) {
__ PrepareCallApiFunction(kStackSpace, kArgc);
STATIC_ASSERT(kArgc == 2);
__ mov(ApiParameterOperand(0), ebx); // name.
__ mov(ApiParameterOperand(1), eax); // arguments pointer.
__ CallApiFunctionAndReturn(fun(), kArgc);
}
void CEntryStub::GenerateCore(MacroAssembler* masm,
Label* throw_normal_exception,
Label* throw_termination_exception,

123
deps/v8/src/ia32/codegen-ia32.cc

@ -154,7 +154,7 @@ CodeGenerator::CodeGenerator(MacroAssembler* masm)
safe_int32_mode_enabled_(true),
function_return_is_shadowed_(false),
in_spilled_code_(false),
jit_cookie_((FLAG_mask_constants_with_cookie) ? V8::Random() : 0) {
jit_cookie_((FLAG_mask_constants_with_cookie) ? V8::RandomPrivate() : 0) {
}
@ -686,10 +686,10 @@ void CodeGenerator::Load(Expression* expr) {
void CodeGenerator::LoadGlobal() {
if (in_spilled_code()) {
frame_->EmitPush(GlobalObject());
frame_->EmitPush(GlobalObjectOperand());
} else {
Result temp = allocator_->Allocate();
__ mov(temp.reg(), GlobalObject());
__ mov(temp.reg(), GlobalObjectOperand());
frame_->Push(&temp);
}
}
@ -698,7 +698,7 @@ void CodeGenerator::LoadGlobal() {
void CodeGenerator::LoadGlobalReceiver() {
Result temp = allocator_->Allocate();
Register reg = temp.reg();
__ mov(reg, GlobalObject());
__ mov(reg, GlobalObjectOperand());
__ mov(reg, FieldOperand(reg, GlobalObject::kGlobalReceiverOffset));
frame_->Push(&temp);
}
@ -3734,7 +3734,7 @@ void CodeGenerator::VisitReturnStatement(ReturnStatement* node) {
CodeForStatementPosition(node);
Load(node->expression());
Result return_value = frame_->Pop();
masm()->WriteRecordedPositions();
masm()->positions_recorder()->WriteRecordedPositions();
if (function_return_is_shadowed_) {
function_return_.Jump(&return_value);
} else {
@ -6294,6 +6294,18 @@ void CodeGenerator::VisitCall(Call* node) {
// Push the receiver onto the frame.
Load(property->obj());
// Load the name of the function.
Load(property->key());
// Swap the name of the function and the receiver on the stack to follow
// the calling convention for call ICs.
Result key = frame_->Pop();
Result receiver = frame_->Pop();
frame_->Push(&key);
frame_->Push(&receiver);
key.Unuse();
receiver.Unuse();
// Load the arguments.
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
@ -6301,15 +6313,14 @@ void CodeGenerator::VisitCall(Call* node) {
frame_->SpillTop();
}
// Load the name of the function.
Load(property->key());
// Call the IC initialization code.
// Place the key on top of stack and call the IC initialization code.
frame_->PushElementAt(arg_count + 1);
CodeForSourcePosition(node->position());
Result result =
frame_->CallKeyedCallIC(RelocInfo::CODE_TARGET,
arg_count,
loop_nesting());
frame_->Drop(); // Drop the key still on the stack.
frame_->RestoreContextRegister();
frame_->Push(&result);
}
@ -6778,8 +6789,8 @@ class DeferredIsStringWrapperSafeForDefaultValueOf : public DeferredCode {
__ mov(scratch2_,
FieldOperand(scratch2_, GlobalObject::kGlobalContextOffset));
__ cmp(scratch1_,
CodeGenerator::ContextOperand(
scratch2_, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
ContextOperand(scratch2_,
Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
__ j(not_equal, &false_result);
// Set the bit in the map to indicate that it has been checked safe for
// default valueOf and set true result.
@ -7292,88 +7303,6 @@ void CodeGenerator::GenerateRegExpConstructResult(ZoneList<Expression*>* args) {
}
void CodeGenerator::GenerateRegExpCloneResult(ZoneList<Expression*>* args) {
ASSERT_EQ(1, args->length());
Load(args->at(0));
Result object_result = frame_->Pop();
object_result.ToRegister(eax);
object_result.Unuse();
{
VirtualFrame::SpilledScope spilled_scope;
Label done;
__ test(eax, Immediate(kSmiTagMask));
__ j(zero, &done);
// Load JSRegExpResult map into edx.
// Arguments to this function should be results of calling RegExp exec,
// which is either an unmodified JSRegExpResult or null. Anything not having
// the unmodified JSRegExpResult map is returned unmodified.
// This also ensures that elements are fast.
__ mov(edx, ContextOperand(esi, Context::GLOBAL_INDEX));
__ mov(edx, FieldOperand(edx, GlobalObject::kGlobalContextOffset));
__ mov(edx, ContextOperand(edx, Context::REGEXP_RESULT_MAP_INDEX));
__ cmp(edx, FieldOperand(eax, HeapObject::kMapOffset));
__ j(not_equal, &done);
if (FLAG_debug_code) {
// Check that object really has empty properties array, as the map
// should guarantee.
__ cmp(FieldOperand(eax, JSObject::kPropertiesOffset),
Immediate(Factory::empty_fixed_array()));
__ Check(equal, "JSRegExpResult: default map but non-empty properties.");
}
DeferredAllocateInNewSpace* allocate_fallback =
new DeferredAllocateInNewSpace(JSRegExpResult::kSize,
ebx,
edx.bit() | eax.bit());
// All set, copy the contents to a new object.
__ AllocateInNewSpace(JSRegExpResult::kSize,
ebx,
ecx,
no_reg,
allocate_fallback->entry_label(),
TAG_OBJECT);
__ bind(allocate_fallback->exit_label());
// Copy all fields from eax to ebx.
STATIC_ASSERT(JSRegExpResult::kSize % (2 * kPointerSize) == 0);
// There is an even number of fields, so unroll the loop once
// for efficiency.
for (int i = 0; i < JSRegExpResult::kSize; i += 2 * kPointerSize) {
STATIC_ASSERT(JSObject::kMapOffset % (2 * kPointerSize) == 0);
if (i != JSObject::kMapOffset) {
// The map was already loaded into edx.
__ mov(edx, FieldOperand(eax, i));
}
__ mov(ecx, FieldOperand(eax, i + kPointerSize));
STATIC_ASSERT(JSObject::kElementsOffset % (2 * kPointerSize) == 0);
if (i == JSObject::kElementsOffset) {
// If the elements array isn't empty, make it copy-on-write
// before copying it.
Label empty;
__ cmp(Operand(edx), Immediate(Factory::empty_fixed_array()));
__ j(equal, &empty);
__ mov(FieldOperand(edx, HeapObject::kMapOffset),
Immediate(Factory::fixed_cow_array_map()));
__ bind(&empty);
}
__ mov(FieldOperand(ebx, i), edx);
__ mov(FieldOperand(ebx, i + kPointerSize), ecx);
}
__ mov(eax, ebx);
__ bind(&done);
}
frame_->Push(eax);
}
class DeferredSearchCache: public DeferredCode {
public:
DeferredSearchCache(Register dst, Register cache, Register key)
@ -8016,7 +7945,7 @@ void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
// Push the builtins object found in the current global object.
Result temp = allocator()->Allocate();
ASSERT(temp.is_valid());
__ mov(temp.reg(), GlobalObject());
__ mov(temp.reg(), GlobalObjectOperand());
__ mov(temp.reg(), FieldOperand(temp.reg(), GlobalObject::kBuiltinsOffset));
frame_->Push(&temp);
}
@ -8660,9 +8589,11 @@ void CodeGenerator::Int32BinaryOperation(BinaryOperation* node) {
}
right.Unuse();
frame_->Push(&left);
if (!node->to_int32()) {
// If ToInt32 is called on the result of ADD, SUB, or MUL, we don't
if (!node->to_int32() || op == Token::MUL) {
// If ToInt32 is called on the result of ADD, SUB, we don't
// care about overflows.
// Result of MUL can be non-representable precisely in double so
// we have to check for overflow.
unsafe_bailout_->Branch(overflow);
}
break;

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

@ -352,10 +352,6 @@ class CodeGenerator: public AstVisitor {
return FieldOperand(array, index_as_smi, times_half_pointer_size, offset);
}
static Operand ContextOperand(Register context, int index) {
return Operand(context, Context::SlotOffset(index));
}
private:
// Type of a member function that generates inline code for a native function.
typedef void (CodeGenerator::*InlineFunctionGenerator)
@ -441,10 +437,6 @@ class CodeGenerator: public AstVisitor {
JumpTarget* slow);
// Expressions
static Operand GlobalObject() {
return ContextOperand(esi, Context::GLOBAL_INDEX);
}
void LoadCondition(Expression* expr,
ControlDestination* destination,
bool force_control);
@ -628,10 +620,6 @@ class CodeGenerator: public AstVisitor {
void ProcessDeclarations(ZoneList<Declaration*>* declarations);
static Handle<Code> ComputeCallInitialize(int argc, InLoopFlag in_loop);
static Handle<Code> ComputeKeyedCallInitialize(int argc, InLoopFlag in_loop);
// Declare global variables and functions in the given array of
// name/value pairs.
void DeclareGlobals(Handle<FixedArray> pairs);
@ -697,11 +685,6 @@ class CodeGenerator: public AstVisitor {
// Construct a RegExp exec result with two in-object properties.
void GenerateRegExpConstructResult(ZoneList<Expression*>* args);
// Clone the result of a regexp function.
// Must be an object created by GenerateRegExpConstructResult with
// no extra properties.
void GenerateRegExpCloneResult(ZoneList<Expression*>* args);
// Support for fast native caches.
void GenerateGetFromCache(ZoneList<Expression*>* args);

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

@ -36,6 +36,7 @@
#include "full-codegen.h"
#include "parser.h"
#include "scopes.h"
#include "stub-cache.h"
namespace v8 {
namespace internal {
@ -954,7 +955,7 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
// All extension objects were empty and it is safe to use a global
// load IC call.
__ mov(eax, CodeGenerator::GlobalObject());
__ mov(eax, GlobalObjectOperand());
__ mov(ecx, slot->var()->name());
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
@ -1057,7 +1058,7 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var) {
Comment cmnt(masm_, "Global variable");
// Use inline caching. Variable name is passed in ecx and the global
// object on the stack.
__ mov(eax, CodeGenerator::GlobalObject());
__ mov(eax, GlobalObjectOperand());
__ mov(ecx, var->name());
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
@ -1834,7 +1835,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
// assignment. Right-hand-side value is passed in eax, variable name in
// ecx, and the global object on the stack.
__ mov(ecx, var->name());
__ mov(edx, CodeGenerator::GlobalObject());
__ mov(edx, GlobalObjectOperand());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
EmitCallIC(ic, RelocInfo::CODE_TARGET);
@ -1996,14 +1997,16 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
// Code common for calls using the IC.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
}
__ Set(ecx, Immediate(name));
}
// Record source position of the IC call.
SetSourcePosition(expr->position());
SetSourcePosition(expr->position(), FORCED_POSITION);
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop);
Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, in_loop);
EmitCallIC(ic, mode);
// Restore context register.
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
@ -2014,23 +2017,32 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
Expression* key,
RelocInfo::Mode mode) {
// Code common for calls using the IC.
// Load the key.
VisitForAccumulatorValue(key);
// Swap the name of the function and the receiver on the stack to follow
// the calling convention for call ICs.
__ pop(ecx);
__ push(eax);
__ push(ecx);
// Load the arguments.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
}
VisitForAccumulatorValue(key);
__ mov(ecx, eax);
}
// Record source position of the IC call.
SetSourcePosition(expr->position());
SetSourcePosition(expr->position(), FORCED_POSITION);
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic = CodeGenerator::ComputeKeyedCallInitialize(
arg_count, in_loop);
Handle<Code> ic = StubCache::ComputeKeyedCallInitialize(arg_count, in_loop);
__ mov(ecx, Operand(esp, (arg_count + 1) * kPointerSize)); // Key.
EmitCallIC(ic, mode);
// Restore context register.
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
context()->Plug(eax);
context()->DropAndPlug(1, eax); // Drop the key still on the stack.
}
@ -2038,11 +2050,13 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr) {
// Code common for calls using the call stub.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
{ 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,12 +2076,14 @@ 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.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
{ PreserveStatementPositionScope pos_scope(masm()->positions_recorder());
VisitForStackValue(fun);
__ push(Immediate(Factory::undefined_value())); // Reserved receiver slot.
// Reserved receiver slot.
__ push(Immediate(Factory::undefined_value()));
// 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));
}
@ -2090,9 +2106,9 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// edx (receiver). Touch up the stack with the right values.
__ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
__ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
}
// Record source position for debugger.
SetSourcePosition(expr->position());
SetSourcePosition(expr->position(), FORCED_POSITION);
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
__ CallStub(&stub);
@ -2101,19 +2117,21 @@ void FullCodeGenerator::VisitCall(Call* expr) {
context()->DropAndPlug(1, eax);
} else if (var != NULL && !var->is_this() && var->is_global()) {
// Push global object as receiver for the call IC.
__ push(CodeGenerator::GlobalObject());
__ push(GlobalObjectOperand());
EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
} else if (var != NULL && var->AsSlot() != NULL &&
var->AsSlot()->type() == Slot::LOOKUP) {
// Call to a lookup slot (dynamically introduced variable).
Label slow, done;
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
NOT_INSIDE_TYPEOF,
&slow,
&done);
}
__ bind(&slow);
// Call the runtime to find the function to call (returned in eax)
@ -2134,7 +2152,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// Push function.
__ push(eax);
// Push global receiver.
__ mov(ebx, CodeGenerator::GlobalObject());
__ mov(ebx, GlobalObjectOperand());
__ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
__ bind(&call);
}
@ -2152,11 +2170,15 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// Call to a keyed property.
// For a synthetic property use keyed load IC followed by function call,
// for a regular property use keyed EmitCallIC.
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
VisitForStackValue(prop->obj());
}
if (prop->is_synthetic()) {
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
VisitForAccumulatorValue(prop->key());
}
// Record source code position for IC call.
SetSourcePosition(prop->position());
SetSourcePosition(prop->position(), FORCED_POSITION);
__ pop(edx); // We do not need to keep the receiver.
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
@ -2164,7 +2186,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// Push result (function).
__ push(eax);
// Push Global receiver.
__ mov(ecx, CodeGenerator::GlobalObject());
__ mov(ecx, GlobalObjectOperand());
__ push(FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset));
EmitCallWithStub(expr);
} else {
@ -2181,9 +2203,11 @@ void FullCodeGenerator::VisitCall(Call* expr) {
loop_depth() == 0) {
lit->set_try_full_codegen(true);
}
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
VisitForStackValue(fun);
}
// Load global receiver object.
__ mov(ebx, CodeGenerator::GlobalObject());
__ mov(ebx, GlobalObjectOperand());
__ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
// Emit function call.
EmitCallWithStub(expr);
@ -3073,7 +3097,7 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
if (expr->is_jsruntime()) {
// Prepare for calling JS runtime function.
__ mov(eax, CodeGenerator::GlobalObject());
__ mov(eax, GlobalObjectOperand());
__ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset));
}
@ -3087,7 +3111,7 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
// Call the JS runtime function via a call IC.
__ Set(ecx, Immediate(expr->name()));
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop);
Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, in_loop);
EmitCallIC(ic, RelocInfo::CODE_TARGET);
// Restore context register.
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
@ -3124,7 +3148,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
VisitForStackValue(prop->obj());
VisitForStackValue(prop->key());
} else if (var->is_global()) {
__ push(CodeGenerator::GlobalObject());
__ push(GlobalObjectOperand());
__ push(Immediate(var->name()));
} else {
// Non-global variable. Call the runtime to look up the context
@ -3402,7 +3426,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) {
Comment cmnt(masm_, "Global variable");
__ mov(eax, CodeGenerator::GlobalObject());
__ mov(eax, GlobalObjectOperand());
__ mov(ecx, Immediate(proxy->name()));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
// Use a regular load, not a contextual load, to avoid a reference

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 {

88
deps/v8/src/ia32/macro-assembler-ia32.cc

@ -392,13 +392,8 @@ void MacroAssembler::EnterExitFrame() {
}
void MacroAssembler::EnterApiExitFrame(int stack_space,
int argc) {
void MacroAssembler::EnterApiExitFrame(int argc) {
EnterExitFramePrologue();
int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
lea(esi, Operand(ebp, (stack_space * kPointerSize) + offset));
EnterExitFrameEpilogue(argc);
}
@ -411,6 +406,13 @@ void MacroAssembler::LeaveExitFrame() {
// Pop the arguments and the receiver from the caller stack.
lea(esp, Operand(esi, 1 * kPointerSize));
// Push the return address to get ready to return.
push(ecx);
LeaveExitFrameEpilogue();
}
void MacroAssembler::LeaveExitFrameEpilogue() {
// Restore current context from top and clear it in debug mode.
ExternalReference context_address(Top::k_context_address);
mov(esi, Operand::StaticVariable(context_address));
@ -418,15 +420,20 @@ void MacroAssembler::LeaveExitFrame() {
mov(Operand::StaticVariable(context_address), Immediate(0));
#endif
// Push the return address to get ready to return.
push(ecx);
// Clear the top frame.
ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
mov(Operand::StaticVariable(c_entry_fp_address), Immediate(0));
}
void MacroAssembler::LeaveApiExitFrame() {
mov(esp, Operand(ebp));
pop(ebp);
LeaveExitFrameEpilogue();
}
void MacroAssembler::PushTryHandler(CodeLocation try_location,
HandlerType type) {
// Adjust this code if not the case.
@ -1110,6 +1117,17 @@ void MacroAssembler::TailCallExternalReference(const ExternalReference& ext,
}
MaybeObject* MacroAssembler::TryTailCallExternalReference(
const ExternalReference& ext, int num_arguments, int result_size) {
// TODO(1236192): Most runtime routines don't need the number of
// arguments passed in because it is constant. At some point we
// should remove this need and make the runtime routine entry code
// smarter.
Set(eax, Immediate(num_arguments));
return TryJumpToExternalReference(ext);
}
void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
int num_arguments,
int result_size) {
@ -1117,6 +1135,14 @@ void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
}
MaybeObject* MacroAssembler::TryTailCallRuntime(Runtime::FunctionId fid,
int num_arguments,
int result_size) {
return TryTailCallExternalReference(
ExternalReference(fid), num_arguments, result_size);
}
// If true, a Handle<T> passed by value is passed and returned by
// using the location_ field directly. If false, it is passed and
// returned as a pointer to a handle.
@ -1132,20 +1158,15 @@ Operand ApiParameterOperand(int index) {
}
void MacroAssembler::PrepareCallApiFunction(int stack_space, int argc) {
void MacroAssembler::PrepareCallApiFunction(int argc, Register scratch) {
if (kPassHandlesDirectly) {
EnterApiExitFrame(stack_space, argc);
EnterApiExitFrame(argc);
// When handles as passed directly we don't have to allocate extra
// space for and pass an out parameter.
} else {
// We allocate two additional slots: return value and pointer to it.
EnterApiExitFrame(stack_space, argc + 2);
}
}
EnterApiExitFrame(argc + 2);
void MacroAssembler::CallApiFunctionAndReturn(ApiFunction* function, int argc) {
if (!kPassHandlesDirectly) {
// The argument slots are filled as follows:
//
// n + 1: output cell
@ -1157,11 +1178,19 @@ void MacroAssembler::CallApiFunctionAndReturn(ApiFunction* function, int argc) {
// Note that this is one more "argument" than the function expects
// so the out cell will have to be popped explicitly after returning
// from the function. The out cell contains Handle.
lea(eax, Operand(esp, (argc + 1) * kPointerSize)); // pointer to out cell.
mov(Operand(esp, 0 * kPointerSize), eax); // output.
// pointer to out cell.
lea(scratch, Operand(esp, (argc + 1) * kPointerSize));
mov(Operand(esp, 0 * kPointerSize), scratch); // output.
if (FLAG_debug_code) {
mov(Operand(esp, (argc + 1) * kPointerSize), Immediate(0)); // out cell.
}
}
}
MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(ApiFunction* function,
int stack_space) {
ExternalReference next_address =
ExternalReference::handle_scope_next_address();
ExternalReference limit_address =
@ -1210,10 +1239,14 @@ void MacroAssembler::CallApiFunctionAndReturn(ApiFunction* function, int argc) {
cmp(Operand::StaticVariable(scheduled_exception_address),
Immediate(Factory::the_hole_value()));
j(not_equal, &promote_scheduled_exception, not_taken);
LeaveExitFrame();
ret(0);
LeaveApiExitFrame();
ret(stack_space * kPointerSize);
bind(&promote_scheduled_exception);
TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
MaybeObject* result =
TryTailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
if (result->IsFailure()) {
return result;
}
bind(&empty_handle);
// It was zero; the result is undefined.
mov(eax, Factory::undefined_value());
@ -1227,6 +1260,8 @@ void MacroAssembler::CallApiFunctionAndReturn(ApiFunction* function, int argc) {
call(Operand(eax));
mov(eax, edi);
jmp(&leave_exit_frame);
return result;
}
@ -1238,6 +1273,15 @@ void MacroAssembler::JumpToExternalReference(const ExternalReference& ext) {
}
MaybeObject* MacroAssembler::TryJumpToExternalReference(
const ExternalReference& ext) {
// Set the entry point and jump to the C entry runtime stub.
mov(ebx, Immediate(ext));
CEntryStub ces(1);
return TryTailCallStub(&ces);
}
void MacroAssembler::InvokePrologue(const ParameterCount& expected,
const ParameterCount& actual,
Handle<Code> code_constant,

46
deps/v8/src/ia32/macro-assembler-ia32.h

@ -123,13 +123,17 @@ class MacroAssembler: public Assembler {
// to the first argument in register esi.
void EnterExitFrame();
void EnterApiExitFrame(int stack_space, int argc);
void EnterApiExitFrame(int argc);
// Leave the current exit frame. Expects the return value in
// register eax:edx (untouched) and the pointer to the first
// argument in register esi.
void LeaveExitFrame();
// Leave the current exit frame. Expects the return value in
// register eax (untouched).
void LeaveApiExitFrame();
// Find the function context up the context chain.
void LoadContext(Register dst, int context_chain_length);
@ -460,11 +464,23 @@ class MacroAssembler: public Assembler {
int num_arguments,
int result_size);
// Tail call of a runtime routine (jump). Try to generate the code if
// necessary. Do not perform a GC but instead return a retry after GC failure.
MUST_USE_RESULT MaybeObject* TryTailCallExternalReference(
const ExternalReference& ext, int num_arguments, int result_size);
// Convenience function: tail call a runtime routine (jump).
void TailCallRuntime(Runtime::FunctionId fid,
int num_arguments,
int result_size);
// Convenience function: tail call a runtime routine (jump). Try to generate
// the code if necessary. Do not perform a GC but instead return a retry after
// GC failure.
MUST_USE_RESULT MaybeObject* TryTailCallRuntime(Runtime::FunctionId fid,
int num_arguments,
int result_size);
// Before calling a C-function from generated code, align arguments on stack.
// After aligning the frame, arguments must be stored in esp[0], esp[4],
// etc., not pushed. The argument count assumes all arguments are word sized.
@ -485,17 +501,22 @@ class MacroAssembler: public Assembler {
// Prepares stack to put arguments (aligns and so on). Reserves
// space for return value if needed (assumes the return value is a handle).
// Uses callee-saved esi to restore stack state after call. Arguments must be
// stored in ApiParameterOperand(0), ApiParameterOperand(1) etc.
void PrepareCallApiFunction(int stack_space, int argc);
// stored in ApiParameterOperand(0), ApiParameterOperand(1) etc. Saves
// context (esi).
void PrepareCallApiFunction(int argc, Register scratch);
// Tail call an API function (jump). Allocates HandleScope, extracts
// Calls an API function. Allocates HandleScope, extracts
// returned value from handle and propagates exceptions.
// Clobbers ebx, esi, edi and caller-save registers.
void CallApiFunctionAndReturn(ApiFunction* function, int argc);
// Clobbers ebx, edi and caller-save registers. Restores context.
// On return removes stack_space * kPointerSize (GCed).
MaybeObject* TryCallApiFunctionAndReturn(ApiFunction* function,
int stack_space);
// Jump to a runtime routine.
void JumpToExternalReference(const ExternalReference& ext);
MaybeObject* TryJumpToExternalReference(const ExternalReference& ext);
// ---------------------------------------------------------------------------
// Utilities
@ -589,6 +610,8 @@ class MacroAssembler: public Assembler {
void EnterExitFramePrologue();
void EnterExitFrameEpilogue(int argc);
void LeaveExitFrameEpilogue();
// Allocation support helpers.
void LoadAllocationTopHelper(Register result,
Register result_end,
@ -642,6 +665,17 @@ static inline Operand FieldOperand(Register object,
return Operand(object, index, scale, offset - kHeapObjectTag);
}
static inline Operand ContextOperand(Register context, int index) {
return Operand(context, Context::SlotOffset(index));
}
static inline Operand GlobalObjectOperand() {
return ContextOperand(esi, Context::GLOBAL_INDEX);
}
// Generates an Operand for saving parameters after PrepareCallApiFunction.
Operand ApiParameterOperand(int index);

203
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);
for (int i = 0; i < kFastApiCallArguments; i++) {
__ push(Immediate(Smi::FromInt(0)));
__ push(Immediate(Smi::FromInt(0)));
__ push(Immediate(Smi::FromInt(0)));
__ push(Immediate(Smi::FromInt(0)));
}
__ push(scratch);
}
@ -434,75 +437,92 @@ static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
// Undoes the effects of ReserveSpaceForFastApiCall.
static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
// ----------- S t a t e -------------
// -- esp[0] : return address
// -- esp[4] : last fast api call extra argument
// -- esp[0] : return address.
// -- esp[4] : last fast api call extra argument.
// -- ...
// -- esp[16] : first fast api call extra argument
// -- esp[20] : last argument in the internal frame
// -- esp[kFastApiCallArguments * 4] : first fast api call extra argument.
// -- esp[kFastApiCallArguments * 4 + 4] : last argument in the internal
// frame.
// -----------------------------------
__ pop(scratch);
__ add(Operand(esp), Immediate(kPointerSize * 4));
__ add(Operand(esp), Immediate(kPointerSize * kFastApiCallArguments));
__ push(scratch);
}
// Generates call to FastHandleApiCall builtin.
static void GenerateFastApiCall(MacroAssembler* masm,
static bool GenerateFastApiCall(MacroAssembler* masm,
const CallOptimization& optimization,
int argc) {
int argc,
Failure** failure) {
// ----------- S t a t e -------------
// -- esp[0] : return address
// -- esp[4] : object passing the type check
// (last fast api call extra argument,
// set by CheckPrototypes)
// -- esp[8] : api call data
// -- esp[12] : api callback
// -- esp[16] : api function
// -- esp[8] : api function
// (first fast api call extra argument)
// -- esp[20] : last argument
// -- esp[12] : api call data
// -- esp[16] : last argument
// -- ...
// -- esp[(argc + 5) * 4] : first argument
// -- esp[(argc + 6) * 4] : receiver
// -- esp[(argc + 3) * 4] : first argument
// -- esp[(argc + 4) * 4] : receiver
// -----------------------------------
// Get the function and setup the context.
JSFunction* function = optimization.constant_function();
__ mov(edi, Immediate(Handle<JSFunction>(function)));
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
// Pass the additional arguments FastHandleApiCall expects.
__ mov(Operand(esp, 4 * kPointerSize), edi);
bool info_loaded = false;
Object* callback = optimization.api_call_info()->callback();
if (Heap::InNewSpace(callback)) {
info_loaded = true;
__ mov(ecx, Handle<CallHandlerInfo>(optimization.api_call_info()));
__ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kCallbackOffset));
__ mov(Operand(esp, 3 * kPointerSize), ebx);
} else {
__ mov(Operand(esp, 3 * kPointerSize), Immediate(Handle<Object>(callback)));
}
__ mov(Operand(esp, 2 * kPointerSize), edi);
Object* call_data = optimization.api_call_info()->data();
Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info());
if (Heap::InNewSpace(call_data)) {
if (!info_loaded) {
__ mov(ecx, Handle<CallHandlerInfo>(optimization.api_call_info()));
}
__ mov(ecx, api_call_info_handle);
__ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset));
__ mov(Operand(esp, 2 * kPointerSize), ebx);
__ mov(Operand(esp, 3 * kPointerSize), ebx);
} else {
__ mov(Operand(esp, 2 * kPointerSize),
__ mov(Operand(esp, 3 * kPointerSize),
Immediate(Handle<Object>(call_data)));
}
// Set the number of arguments.
__ mov(eax, Immediate(argc + 4));
// Prepare arguments.
__ lea(eax, Operand(esp, 3 * kPointerSize));
// Jump to the fast api call builtin (tail call).
Handle<Code> code = Handle<Code>(
Builtins::builtin(Builtins::FastHandleApiCall));
ParameterCount expected(0);
__ InvokeCode(code, expected, expected,
RelocInfo::CODE_TARGET, JUMP_FUNCTION);
Object* callback = optimization.api_call_info()->callback();
Address api_function_address = v8::ToCData<Address>(callback);
ApiFunction fun(api_function_address);
const int kApiArgc = 1; // API function gets reference to the v8::Arguments.
// Allocate the v8::Arguments structure in the arguments' space since
// it's not controlled by GC.
const int kApiStackSpace = 4;
__ PrepareCallApiFunction(kApiArgc + kApiStackSpace, ebx);
__ mov(ApiParameterOperand(1), eax); // v8::Arguments::implicit_args_.
__ add(Operand(eax), Immediate(argc * kPointerSize));
__ mov(ApiParameterOperand(2), eax); // v8::Arguments::values_.
__ Set(ApiParameterOperand(3), Immediate(argc)); // v8::Arguments::length_.
// v8::Arguments::is_construct_call_.
__ Set(ApiParameterOperand(4), Immediate(0));
// v8::InvocationCallback's argument.
__ lea(eax, ApiParameterOperand(1));
__ mov(ApiParameterOperand(0), eax);
// Emitting a stub call may try to allocate (if the code is not
// already generated). Do not allow the assembler to perform a
// garbage collection but instead return the allocation failure
// object.
MaybeObject* result =
masm->TryCallApiFunctionAndReturn(&fun, argc + kFastApiCallArguments + 1);
if (result->IsFailure()) {
*failure = Failure::cast(result);
return false;
}
return true;
}
@ -515,7 +535,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
arguments_(arguments),
name_(name) {}
void Compile(MacroAssembler* masm,
bool Compile(MacroAssembler* masm,
JSObject* object,
JSObject* holder,
String* name,
@ -524,7 +544,8 @@ class CallInterceptorCompiler BASE_EMBEDDED {
Register scratch1,
Register scratch2,
Register scratch3,
Label* miss) {
Label* miss,
Failure** failure) {
ASSERT(holder->HasNamedInterceptor());
ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
@ -535,7 +556,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
CallOptimization optimization(lookup);
if (optimization.is_constant_call()) {
CompileCacheable(masm,
return CompileCacheable(masm,
object,
receiver,
scratch1,
@ -545,7 +566,8 @@ class CallInterceptorCompiler BASE_EMBEDDED {
lookup,
name,
optimization,
miss);
miss,
failure);
} else {
CompileRegular(masm,
object,
@ -556,11 +578,12 @@ class CallInterceptorCompiler BASE_EMBEDDED {
name,
holder,
miss);
return true;
}
}
private:
void CompileCacheable(MacroAssembler* masm,
bool CompileCacheable(MacroAssembler* masm,
JSObject* object,
Register receiver,
Register scratch1,
@ -570,7 +593,8 @@ class CallInterceptorCompiler BASE_EMBEDDED {
LookupResult* lookup,
String* name,
const CallOptimization& optimization,
Label* miss_label) {
Label* miss_label,
Failure** failure) {
ASSERT(optimization.is_constant_call());
ASSERT(!lookup->holder()->IsGlobalObject());
@ -632,7 +656,11 @@ class CallInterceptorCompiler BASE_EMBEDDED {
// Invoke function.
if (can_do_fast_api_call) {
GenerateFastApiCall(masm, optimization, arguments_.immediate());
bool success = GenerateFastApiCall(masm, optimization,
arguments_.immediate(), failure);
if (!success) {
return false;
}
} else {
__ InvokeFunction(optimization.constant_function(), arguments_,
JUMP_FUNCTION);
@ -650,6 +678,8 @@ class CallInterceptorCompiler BASE_EMBEDDED {
if (can_do_fast_api_call) {
FreeSpaceForFastApiCall(masm, scratch1);
}
return true;
}
void CompileRegular(MacroAssembler* masm,
@ -905,7 +935,7 @@ Register StubCompiler::CheckPrototypes(JSObject* object,
MaybeObject* maybe_lookup_result = Heap::LookupSymbol(name);
Object* lookup_result = NULL; // Initialization to please compiler.
if (!maybe_lookup_result->ToObject(&lookup_result)) {
set_failure(Failure::cast(lookup_result));
set_failure(Failure::cast(maybe_lookup_result));
return reg;
}
name = String::cast(lookup_result);
@ -1044,46 +1074,55 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object,
Handle<AccessorInfo> callback_handle(callback);
__ EnterInternalFrame();
// Push the stack address where the list of arguments ends.
__ mov(scratch2, esp);
__ sub(Operand(scratch2), Immediate(2 * kPointerSize));
__ push(scratch2);
// Insert additional parameters into the stack frame above return address.
ASSERT(!scratch3.is(reg));
__ pop(scratch3); // Get return address to place it below.
__ push(receiver); // receiver
__ mov(scratch2, Operand(esp));
ASSERT(!scratch2.is(reg));
__ push(reg); // holder
// Push data from AccessorInfo.
if (Heap::InNewSpace(callback_handle->data())) {
__ mov(scratch2, Immediate(callback_handle));
__ push(FieldOperand(scratch2, AccessorInfo::kDataOffset));
__ mov(scratch1, Immediate(callback_handle));
__ push(FieldOperand(scratch1, AccessorInfo::kDataOffset));
} else {
__ push(Immediate(Handle<Object>(callback_handle->data())));
}
__ push(name_reg); // name
// Save a pointer to where we pushed the arguments pointer.
// This will be passed as the const AccessorInfo& to the C++ callback.
__ mov(eax, esp);
__ add(Operand(eax), Immediate(4 * kPointerSize));
__ mov(ebx, esp);
__ push(scratch2);
__ push(name_reg); // name
__ mov(ebx, esp); // esp points to reference to name (handler).
__ push(scratch3); // Restore return address.
// Do call through the api.
ASSERT_EQ(5, ApiGetterEntryStub::kStackSpace);
Address getter_address = v8::ToCData<Address>(callback->getter());
ApiFunction fun(getter_address);
ApiGetterEntryStub stub(callback_handle, &fun);
// 3 elements array for v8::Agruments::values_, handler for name and pointer
// to the values (it considered as smi in GC).
const int kStackSpace = 5;
const int kApiArgc = 2;
__ PrepareCallApiFunction(kApiArgc, eax);
__ mov(ApiParameterOperand(0), ebx); // name.
__ add(Operand(ebx), Immediate(kPointerSize));
__ mov(ApiParameterOperand(1), ebx); // arguments pointer.
// Emitting a stub call may try to allocate (if the code is not
// already generated). Do not allow the assembler to perform a
// garbage collection but instead return the allocation failure
// object.
Object* result = NULL; // Initialization to please compiler.
{ MaybeObject* try_call_result = masm()->TryCallStub(&stub);
if (!try_call_result->ToObject(&result)) {
MaybeObject* result = masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace);
if (result->IsFailure()) {
*failure = Failure::cast(result);
return false;
}
}
__ LeaveInternalFrame();
__ ret(0);
return true;
}
@ -2129,7 +2168,10 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
if (depth != kInvalidProtoDepth) {
__ IncrementCounter(&Counters::call_const_fast_api, 1);
ReserveSpaceForFastApiCall(masm(), eax);
// Allocate space for v8::Arguments implicit values. Must be initialized
// before to call any runtime function.
__ sub(Operand(esp), Immediate(kFastApiCallArguments * kPointerSize));
}
// Check that the maps haven't changed.
@ -2208,7 +2250,17 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
}
if (depth != kInvalidProtoDepth) {
GenerateFastApiCall(masm(), optimization, argc);
Failure* failure;
// Move the return address on top of the stack.
__ mov(eax, Operand(esp, 3 * kPointerSize));
__ mov(Operand(esp, 0 * kPointerSize), eax);
// esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains
// duplicate of return address and will be overwritten.
bool success = GenerateFastApiCall(masm(), optimization, argc, &failure);
if (!success) {
return failure;
}
} else {
__ InvokeFunction(function, arguments(), JUMP_FUNCTION);
}
@ -2216,7 +2268,7 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
// Handle call cache miss.
__ bind(&miss);
if (depth != kInvalidProtoDepth) {
FreeSpaceForFastApiCall(masm(), eax);
__ add(Operand(esp), Immediate(kFastApiCallArguments * kPointerSize));
}
__ bind(&miss_in_smi_check);
Object* obj;
@ -2253,7 +2305,8 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
__ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
CallInterceptorCompiler compiler(this, arguments(), ecx);
compiler.Compile(masm(),
Failure* failure;
bool success = compiler.Compile(masm(),
object,
holder,
name,
@ -2262,7 +2315,11 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
ebx,
edi,
eax,
&miss);
&miss,
&failure);
if (!success) {
return false;
}
// Restore receiver.
__ mov(edx, Operand(esp, (argc + 1) * kPointerSize));

5
deps/v8/src/ia32/virtual-frame-ia32.cc

@ -33,6 +33,7 @@
#include "register-allocator-inl.h"
#include "scopes.h"
#include "virtual-frame-inl.h"
#include "stub-cache.h"
namespace v8 {
namespace internal {
@ -1108,7 +1109,7 @@ Result VirtualFrame::CallCallIC(RelocInfo::Mode mode,
// The IC expects the name in ecx and the rest on the stack and
// drops them all.
InLoopFlag in_loop = loop_nesting > 0 ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic = cgen()->ComputeCallInitialize(arg_count, in_loop);
Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, in_loop);
// Spill args, receiver, and function. The call will drop args and
// receiver.
Result name = Pop();
@ -1126,7 +1127,7 @@ Result VirtualFrame::CallKeyedCallIC(RelocInfo::Mode mode,
// The IC expects the name in ecx and the rest on the stack and
// drops them all.
InLoopFlag in_loop = loop_nesting > 0 ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic = cgen()->ComputeKeyedCallInitialize(arg_count, in_loop);
Handle<Code> ic = StubCache::ComputeKeyedCallInitialize(arg_count, in_loop);
// Spill args, receiver, and function. The call will drop args and
// receiver.
Result name = Pop();

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);

8
deps/v8/src/list.h

@ -148,14 +148,6 @@ class List {
DISALLOW_COPY_AND_ASSIGN(List);
};
class FrameElement;
// Add() is inlined, ResizeAdd() called by Add() is inlined except for
// Lists of FrameElements, and ResizeAddInternal() is inlined in ResizeAdd().
template <>
void List<FrameElement,
FreeStoreAllocationPolicy>::ResizeAdd(const FrameElement& element);
} } // namespace v8::internal
#endif // V8_LIST_H_

16
deps/v8/src/mark-compact.cc

@ -1099,13 +1099,6 @@ void MarkCompactCollector::MarkLiveObjects() {
}
static int CountMarkedCallback(HeapObject* obj) {
MapWord map_word = obj->map_word();
map_word.ClearMark();
return obj->SizeFromMap(map_word.ToMap());
}
#ifdef DEBUG
void MarkCompactCollector::UpdateLiveObjectCount(HeapObject* obj) {
live_bytes_ += obj->Size();
@ -1152,7 +1145,7 @@ bool MarkCompactCollector::SafeIsMap(HeapObject* object) {
void MarkCompactCollector::ClearNonLiveTransitions() {
HeapObjectIterator map_iterator(Heap::map_space(), &CountMarkedCallback);
HeapObjectIterator map_iterator(Heap::map_space(), &SizeOfMarkedObject);
// Iterate over the map space, setting map transitions that go from
// a marked map to an unmarked map to null transitions. At the same time,
// set all the prototype fields of maps back to their original value,
@ -2673,6 +2666,13 @@ void MarkCompactCollector::ReportDeleteIfNeeded(HeapObject* obj) {
}
int MarkCompactCollector::SizeOfMarkedObject(HeapObject* obj) {
MapWord map_word = obj->map_word();
map_word.ClearMark();
return obj->SizeFromMap(map_word.ToMap());
}
void MarkCompactCollector::Initialize() {
StaticPointersToNewGenUpdatingVisitor::Initialize();
StaticMarkingVisitor::Initialize();

3
deps/v8/src/mark-compact.h

@ -119,6 +119,9 @@ class MarkCompactCollector: public AllStatic {
// Determine type of object and emit deletion log event.
static void ReportDeleteIfNeeded(HeapObject* obj);
// Returns size of a possibly marked object.
static int SizeOfMarkedObject(HeapObject* obj);
// Distinguishable invalid map encodings (for single word and multiple words)
// that indicate free regions.
static const uint32_t kSingleFreeEncoding = 0;

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

@ -982,7 +982,6 @@ void AccessorInfo::AccessorInfoVerify() {
VerifyPointer(name());
VerifyPointer(data());
VerifyPointer(flag());
VerifyPointer(load_stub_cache());
}
void AccessorInfo::AccessorInfoPrint() {
@ -1054,6 +1053,7 @@ void CallHandlerInfo::CallHandlerInfoPrint() {
callback()->ShortPrint();
PrintF("\n - data: ");
data()->ShortPrint();
PrintF("\n - call_stub_cache: ");
}
void TemplateInfo::TemplateInfoVerify() {

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

@ -2542,7 +2542,6 @@ ACCESSORS(AccessorInfo, setter, Object, kSetterOffset)
ACCESSORS(AccessorInfo, data, Object, kDataOffset)
ACCESSORS(AccessorInfo, name, Object, kNameOffset)
ACCESSORS(AccessorInfo, flag, Smi, kFlagOffset)
ACCESSORS(AccessorInfo, load_stub_cache, Object, kLoadStubCacheOffset)
ACCESSORS(AccessCheckInfo, named_callback, Object, kNamedCallbackOffset)
ACCESSORS(AccessCheckInfo, indexed_callback, Object, kIndexedCallbackOffset)
@ -2671,6 +2670,7 @@ SMI_ACCESSORS(SharedFunctionInfo, this_property_assignments_count,
#else
#define PSEUDO_SMI_ACCESSORS_LO(holder, name, offset) \
STATIC_ASSERT(holder::offset % kPointerSize == 0); \
int holder::name() { \
int value = READ_INT_FIELD(this, offset); \
ASSERT(kHeapObjectTag == 1); \
@ -2687,28 +2687,34 @@ SMI_ACCESSORS(SharedFunctionInfo, this_property_assignments_count,
}
#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,
PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo,
formal_parameter_count,
kFormalParameterCountOffset)
PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, expected_nof_properties,
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,
PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, end_position, kEndPositionOffset)
PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo,
start_position_and_type,
kStartPositionAndTypeOffset)
PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo, end_position, kEndPositionOffset)
PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, function_token_position,
PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo,
function_token_position,
kFunctionTokenPositionOffset)
PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo, compiler_hints,
PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo,
compiler_hints,
kCompilerHintsOffset)
PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, this_property_assignments_count,
PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo,
this_property_assignments_count,
kThisPropertyAssignmentsCountOffset)
#endif

8
deps/v8/src/objects.cc

@ -35,7 +35,7 @@
#include "objects-inl.h"
#include "objects-visiting.h"
#include "macro-assembler.h"
#include "scanner.h"
#include "scanner-base.h"
#include "scopeinfo.h"
#include "string-stream.h"
#include "utils.h"
@ -1208,7 +1208,8 @@ MaybeObject* JSObject::AddFastProperty(String* name,
// Normalize the object if the name is an actual string (not the
// hidden symbols) and is not a real identifier.
StringInputBuffer buffer(name);
if (!Scanner::IsIdentifier(&buffer) && name != Heap::hidden_symbol()) {
if (!ScannerConstants::IsIdentifier(&buffer)
&& name != Heap::hidden_symbol()) {
Object* obj;
{ MaybeObject* maybe_obj =
NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
@ -5088,7 +5089,8 @@ bool String::MarkAsUndetectable() {
bool String::IsEqualTo(Vector<const char> str) {
int slen = length();
Access<Scanner::Utf8Decoder> decoder(Scanner::utf8_decoder());
Access<ScannerConstants::Utf8Decoder>
decoder(ScannerConstants::utf8_decoder());
decoder->Reset(str.start(), str.length());
int i;
for (i = 0; i < slen && decoder->has_more(); i++) {

4
deps/v8/src/objects.h

@ -5327,7 +5327,6 @@ class AccessorInfo: public Struct {
DECL_ACCESSORS(data, Object)
DECL_ACCESSORS(name, Object)
DECL_ACCESSORS(flag, Smi)
DECL_ACCESSORS(load_stub_cache, Object)
inline bool all_can_read();
inline void set_all_can_read(bool value);
@ -5353,8 +5352,7 @@ class AccessorInfo: public Struct {
static const int kDataOffset = kSetterOffset + kPointerSize;
static const int kNameOffset = kDataOffset + kPointerSize;
static const int kFlagOffset = kNameOffset + kPointerSize;
static const int kLoadStubCacheOffset = kFlagOffset + kPointerSize;
static const int kSize = kLoadStubCacheOffset + kPointerSize;
static const int kSize = kFlagOffset + kPointerSize;
private:
// Bit positions in flag.

878
deps/v8/src/parser.cc

File diff suppressed because it is too large

236
deps/v8/src/parser.h

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

69
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);
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_;
}

3
deps/v8/src/platform-win32.cc

@ -865,7 +865,8 @@ void* OS::Allocate(const size_t requested,
// For exectutable pages try and randomize the allocation address
if (prot == PAGE_EXECUTE_READWRITE && msize >= Page::kPageSize) {
address = (V8::Random() << kPageSizeBits) | kAllocationRandomAddressMin;
address = (V8::RandomPrivate() << kPageSizeBits)
| kAllocationRandomAddressMin;
address &= kAllocationRandomAddressMax;
}

1419
deps/v8/src/preparser.h

File diff suppressed because it is too large

1098
deps/v8/src/prescanner.h

File diff suppressed because it is too large

28
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());
}
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);

142
deps/v8/src/regexp.js

@ -71,9 +71,6 @@ function DoConstructRegExp(object, pattern, flags, isConstructorCall) {
}
}
if (!isConstructorCall) {
regExpCache.type = 'none';
}
%RegExpInitializeObject(object, pattern, global, ignoreCase, multiline);
// Call internal function to compile the pattern.
@ -121,22 +118,6 @@ function DoRegExpExec(regexp, string, index) {
}
function RegExpCache() {
this.type = 'none';
this.regExp = 0;
this.subject = 0;
this.replaceString = 0;
this.answer = 0;
// answerSaved marks whether the contents of answer is valid for a cache
// hit in RegExpExec, StringMatch and StringSplit.
this.answerSaved = false;
this.splitLimit = 0; // Used only when type is "split".
}
var regExpCache = new RegExpCache();
function BuildResultFromMatchInfo(lastMatchInfo, s) {
var numResults = NUMBER_OF_CAPTURES(lastMatchInfo) >> 1;
var result = %_RegExpConstructResult(numResults, lastMatchInfo[CAPTURE0], s);
@ -178,32 +159,6 @@ function RegExpExec(string) {
['RegExp.prototype.exec', this]);
}
var cache = regExpCache;
var saveAnswer = false;
var lastIndex = this.lastIndex;
// Since cache.subject is always a string, a matching input can not
// cause visible side-effects when converted to a string, so we can omit
// the conversion required by the specification.
// Likewise, the regexp.lastIndex and regexp.global properties are value
// properties that are not configurable, so reading them can also not cause
// any side effects (converting lastIndex to a number can, though).
if (%_ObjectEquals(cache.type, 'exec') &&
%_ObjectEquals(0, lastIndex) &&
%_IsRegExpEquivalent(cache.regExp, this) &&
%_ObjectEquals(cache.subject, string)) {
if (cache.answerSaved) {
// The regexp.lastIndex value must be 0 for non-global RegExps, and for
// global RegExps we only cache negative results, which gives a lastIndex
// of zero as well.
this.lastIndex = 0;
return %_RegExpCloneResult(cache.answer);
} else {
saveAnswer = true;
}
}
if (%_ArgumentsLength() === 0) {
var regExpInput = LAST_INPUT(lastMatchInfo);
if (IS_UNDEFINED(regExpInput)) {
@ -217,11 +172,13 @@ function RegExpExec(string) {
} else {
s = ToString(string);
}
var global = this.global;
var lastIndex = this.lastIndex;
// Conversion is required by the ES5 specification (RegExp.prototype.exec
// algorithm, step 5) even if the value is discarded for non-global RegExps.
var i = TO_INTEGER(lastIndex);
var global = this.global;
if (global) {
if (i < 0 || i > s.length) {
this.lastIndex = 0;
@ -236,35 +193,16 @@ function RegExpExec(string) {
var matchIndices = %_RegExpExec(this, s, i, lastMatchInfo);
if (matchIndices === null) {
if (global) {
// Cache negative result only if initial lastIndex was zero.
this.lastIndex = 0;
if (lastIndex !== 0) return matchIndices;
}
cache.regExp = this;
cache.subject = s; // Always a string.
cache.answer = null;
cache.answerSaved = true; // Safe since no cloning is needed.
cache.type = 'exec';
return matchIndices; // No match.
if (global) this.lastIndex = 0;
return null;
}
// Successful match.
lastMatchInfoOverride = null;
var result = BuildResultFromMatchInfo(matchIndices, s);
if (global) {
// Don't cache positive results for global regexps.
this.lastIndex = lastMatchInfo[CAPTURE1];
} else {
cache.regExp = this;
cache.subject = s;
if (saveAnswer) cache.answer = %_RegExpCloneResult(result);
cache.answerSaved = saveAnswer;
cache.type = 'exec';
}
return result;
return BuildResultFromMatchInfo(matchIndices, s);
}
@ -289,80 +227,57 @@ function RegExpTest(string) {
string = regExpInput;
}
var lastIndex = this.lastIndex;
var cache = regExpCache;
if (%_ObjectEquals(cache.type, 'test') &&
%_IsRegExpEquivalent(cache.regExp, this) &&
%_ObjectEquals(cache.subject, string) &&
%_ObjectEquals(0, lastIndex)) {
// The regexp.lastIndex value must be 0 for non-global RegExps, and for
// global RegExps we only cache negative results, which gives a resulting
// lastIndex of zero as well.
if (global) this.lastIndex = 0;
return cache.answer;
}
var s;
if (IS_STRING(string)) {
s = string;
} else {
s = ToString(string);
}
var length = s.length;
var lastIndex = this.lastIndex;
// Conversion is required by the ES5 specification (RegExp.prototype.exec
// algorithm, step 5) even if the value is discarded for non-global RegExps.
var i = TO_INTEGER(lastIndex);
if (global) {
if (i < 0 || i > length) {
if (this.global) {
if (i < 0 || i > s.length) {
this.lastIndex = 0;
return false;
}
} else {
i = 0;
%_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]);
// matchIndices is either null or the lastMatchInfo array.
var matchIndices = %_RegExpExec(this, s, i, lastMatchInfo);
if (matchIndices === null) {
this.lastIndex = 0;
return false;
}
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 '?'
lastMatchInfoOverride = null;
this.lastIndex = lastMatchInfo[CAPTURE1];
return true;
} else {
// Non-global regexp.
// Remove irrelevant preceeding '.*' in a non-global test regexp.
// The expression checks whether this.source starts with '.*' and
// that the third char is not a '?'.
if (%_StringCharCodeAt(this.source, 0) == 46 && // '.'
%_StringCharCodeAt(this.source, 1) == 42 && // '*'
%_StringCharCodeAt(this.source, 2) != 63) { // '?'
if (!%_ObjectEquals(regexp_key, this)) {
regexp_key = this;
regexp_val = new $RegExp(this.source.substring(2, this.source.length),
(this.global ? 'g' : '')
+ (this.ignoreCase ? 'i' : '')
(this.ignoreCase ? 'i' : '')
+ (this.multiline ? 'm' : ''));
}
if (!regexp_val.test(s)) return false;
}
%_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]);
// matchIndices is either null or the lastMatchInfo array.
var matchIndices = %_RegExpExec(this, s, i, lastMatchInfo);
var result = (matchIndices !== null);
if (result) {
var matchIndices = %_RegExpExec(this, s, 0, lastMatchInfo);
if (matchIndices === null) return false;
lastMatchInfoOverride = null;
}
if (global) {
if (result) {
this.lastIndex = lastMatchInfo[CAPTURE1];
return true;
} else {
this.lastIndex = 0;
if (lastIndex !== 0) return false;
}
}
cache.type = 'test';
cache.regExp = this;
cache.subject = s;
cache.answer = result;
return result;
}
@ -510,7 +425,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);

3
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) \
@ -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)

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

@ -0,0 +1,195 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Features shared by parsing and pre-parsing scanners.
#include "../include/v8stdint.h"
#include "scanner-base.h"
namespace v8 {
namespace internal {
// ----------------------------------------------------------------------------
// Character predicates
unibrow::Predicate<IdentifierStart, 128> ScannerConstants::kIsIdentifierStart;
unibrow::Predicate<IdentifierPart, 128> ScannerConstants::kIsIdentifierPart;
unibrow::Predicate<unibrow::WhiteSpace, 128> ScannerConstants::kIsWhiteSpace;
unibrow::Predicate<unibrow::LineTerminator, 128>
ScannerConstants::kIsLineTerminator;
StaticResource<ScannerConstants::Utf8Decoder> ScannerConstants::utf8_decoder_;
// Compound predicates.
bool ScannerConstants::IsIdentifier(unibrow::CharacterStream* buffer) {
// Checks whether the buffer contains an identifier (no escape).
if (!buffer->has_more()) return false;
if (!kIsIdentifierStart.get(buffer->GetNext())) {
return false;
}
while (buffer->has_more()) {
if (!kIsIdentifierPart.get(buffer->GetNext())) {
return false;
}
}
return true;
}
// ----------------------------------------------------------------------------
// Keyword Matcher
KeywordMatcher::FirstState KeywordMatcher::first_states_[] = {
{ "break", KEYWORD_PREFIX, Token::BREAK },
{ NULL, C, Token::ILLEGAL },
{ NULL, D, Token::ILLEGAL },
{ "else", KEYWORD_PREFIX, Token::ELSE },
{ NULL, F, Token::ILLEGAL },
{ NULL, UNMATCHABLE, Token::ILLEGAL },
{ NULL, UNMATCHABLE, Token::ILLEGAL },
{ NULL, I, Token::ILLEGAL },
{ NULL, UNMATCHABLE, Token::ILLEGAL },
{ NULL, UNMATCHABLE, Token::ILLEGAL },
{ NULL, UNMATCHABLE, Token::ILLEGAL },
{ NULL, UNMATCHABLE, Token::ILLEGAL },
{ NULL, N, Token::ILLEGAL },
{ NULL, UNMATCHABLE, Token::ILLEGAL },
{ NULL, UNMATCHABLE, Token::ILLEGAL },
{ NULL, UNMATCHABLE, Token::ILLEGAL },
{ "return", KEYWORD_PREFIX, Token::RETURN },
{ "switch", KEYWORD_PREFIX, Token::SWITCH },
{ NULL, T, Token::ILLEGAL },
{ NULL, UNMATCHABLE, Token::ILLEGAL },
{ NULL, V, Token::ILLEGAL },
{ NULL, W, Token::ILLEGAL }
};
void KeywordMatcher::Step(unibrow::uchar input) {
switch (state_) {
case INITIAL: {
// matching the first character is the only state with significant fanout.
// Match only lower-case letters in range 'b'..'w'.
unsigned int offset = input - kFirstCharRangeMin;
if (offset < kFirstCharRangeLength) {
state_ = first_states_[offset].state;
if (state_ == KEYWORD_PREFIX) {
keyword_ = first_states_[offset].keyword;
counter_ = 1;
keyword_token_ = first_states_[offset].token;
}
return;
}
break;
}
case KEYWORD_PREFIX:
if (static_cast<unibrow::uchar>(keyword_[counter_]) == input) {
counter_++;
if (keyword_[counter_] == '\0') {
state_ = KEYWORD_MATCHED;
token_ = keyword_token_;
}
return;
}
break;
case KEYWORD_MATCHED:
token_ = Token::IDENTIFIER;
break;
case C:
if (MatchState(input, 'a', CA)) return;
if (MatchState(input, 'o', CO)) return;
break;
case CA:
if (MatchKeywordStart(input, "case", 2, Token::CASE)) return;
if (MatchKeywordStart(input, "catch", 2, Token::CATCH)) return;
break;
case CO:
if (MatchState(input, 'n', CON)) return;
break;
case CON:
if (MatchKeywordStart(input, "const", 3, Token::CONST)) return;
if (MatchKeywordStart(input, "continue", 3, Token::CONTINUE)) return;
break;
case D:
if (MatchState(input, 'e', DE)) return;
if (MatchKeyword(input, 'o', KEYWORD_MATCHED, Token::DO)) return;
break;
case DE:
if (MatchKeywordStart(input, "debugger", 2, Token::DEBUGGER)) return;
if (MatchKeywordStart(input, "default", 2, Token::DEFAULT)) return;
if (MatchKeywordStart(input, "delete", 2, Token::DELETE)) return;
break;
case F:
if (MatchKeywordStart(input, "false", 1, Token::FALSE_LITERAL)) return;
if (MatchKeywordStart(input, "finally", 1, Token::FINALLY)) return;
if (MatchKeywordStart(input, "for", 1, Token::FOR)) return;
if (MatchKeywordStart(input, "function", 1, Token::FUNCTION)) return;
break;
case I:
if (MatchKeyword(input, 'f', KEYWORD_MATCHED, Token::IF)) return;
if (MatchKeyword(input, 'n', IN, Token::IN)) return;
break;
case IN:
token_ = Token::IDENTIFIER;
if (MatchKeywordStart(input, "instanceof", 2, Token::INSTANCEOF)) {
return;
}
break;
case N:
if (MatchKeywordStart(input, "native", 1, Token::NATIVE)) return;
if (MatchKeywordStart(input, "new", 1, Token::NEW)) return;
if (MatchKeywordStart(input, "null", 1, Token::NULL_LITERAL)) return;
break;
case T:
if (MatchState(input, 'h', TH)) return;
if (MatchState(input, 'r', TR)) return;
if (MatchKeywordStart(input, "typeof", 1, Token::TYPEOF)) return;
break;
case TH:
if (MatchKeywordStart(input, "this", 2, Token::THIS)) return;
if (MatchKeywordStart(input, "throw", 2, Token::THROW)) return;
break;
case TR:
if (MatchKeywordStart(input, "true", 2, Token::TRUE_LITERAL)) return;
if (MatchKeyword(input, 'y', KEYWORD_MATCHED, Token::TRY)) return;
break;
case V:
if (MatchKeywordStart(input, "var", 1, Token::VAR)) return;
if (MatchKeywordStart(input, "void", 1, Token::VOID)) return;
break;
case W:
if (MatchKeywordStart(input, "while", 1, Token::WHILE)) return;
if (MatchKeywordStart(input, "with", 1, Token::WITH)) return;
break;
case UNMATCHABLE:
break;
}
// On fallthrough, it's a failure.
state_ = UNMATCHABLE;
}
} } // namespace v8::internal

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

@ -0,0 +1,206 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Features shared by parsing and pre-parsing scanners.
#ifndef V8_SCANNER_BASE_H_
#define V8_SCANNER_BASE_H_
#include "globals.h"
#include "checks.h"
#include "allocation.h"
#include "token.h"
#include "unicode-inl.h"
#include "char-predicates.h"
#include "utils.h"
namespace v8 {
namespace internal {
// Interface through which the scanner reads characters from the input source.
class UTF16Buffer {
public:
UTF16Buffer();
virtual ~UTF16Buffer() {}
virtual void PushBack(uc32 ch) = 0;
// Returns a value < 0 when the buffer end is reached.
virtual uc32 Advance() = 0;
virtual void SeekForward(int pos) = 0;
int pos() const { return pos_; }
protected:
int pos_; // Current position in the buffer.
int end_; // Position where scanning should stop (EOF).
};
class ScannerConstants : AllStatic {
public:
typedef unibrow::Utf8InputBuffer<1024> Utf8Decoder;
static StaticResource<Utf8Decoder>* utf8_decoder() {
return &utf8_decoder_;
}
static unibrow::Predicate<IdentifierStart, 128> kIsIdentifierStart;
static unibrow::Predicate<IdentifierPart, 128> kIsIdentifierPart;
static unibrow::Predicate<unibrow::LineTerminator, 128> kIsLineTerminator;
static unibrow::Predicate<unibrow::WhiteSpace, 128> kIsWhiteSpace;
static bool IsIdentifier(unibrow::CharacterStream* buffer);
private:
static StaticResource<Utf8Decoder> utf8_decoder_;
};
class KeywordMatcher {
// Incrementally recognize keywords.
//
// Recognized keywords:
// break case catch const* continue debugger* default delete do else
// finally false for function if in instanceof native* new null
// return switch this throw true try typeof var void while with
//
// *: Actually "future reserved keywords". These are the only ones we
// recognize, the remaining are allowed as identifiers.
// In ES5 strict mode, we should disallow all reserved keywords.
public:
KeywordMatcher()
: state_(INITIAL),
token_(Token::IDENTIFIER),
keyword_(NULL),
counter_(0),
keyword_token_(Token::ILLEGAL) {}
Token::Value token() { return token_; }
inline void AddChar(unibrow::uchar input) {
if (state_ != UNMATCHABLE) {
Step(input);
}
}
void Fail() {
token_ = Token::IDENTIFIER;
state_ = UNMATCHABLE;
}
private:
enum State {
UNMATCHABLE,
INITIAL,
KEYWORD_PREFIX,
KEYWORD_MATCHED,
C,
CA,
CO,
CON,
D,
DE,
F,
I,
IN,
N,
T,
TH,
TR,
V,
W
};
struct FirstState {
const char* keyword;
State state;
Token::Value token;
};
// Range of possible first characters of a keyword.
static const unsigned int kFirstCharRangeMin = 'b';
static const unsigned int kFirstCharRangeMax = 'w';
static const unsigned int kFirstCharRangeLength =
kFirstCharRangeMax - kFirstCharRangeMin + 1;
// State map for first keyword character range.
static FirstState first_states_[kFirstCharRangeLength];
// If input equals keyword's character at position, continue matching keyword
// from that position.
inline bool MatchKeywordStart(unibrow::uchar input,
const char* keyword,
int position,
Token::Value token_if_match) {
if (input == static_cast<unibrow::uchar>(keyword[position])) {
state_ = KEYWORD_PREFIX;
this->keyword_ = keyword;
this->counter_ = position + 1;
this->keyword_token_ = token_if_match;
return true;
}
return false;
}
// If input equals match character, transition to new state and return true.
inline bool MatchState(unibrow::uchar input, char match, State new_state) {
if (input == static_cast<unibrow::uchar>(match)) {
state_ = new_state;
return true;
}
return false;
}
inline bool MatchKeyword(unibrow::uchar input,
char match,
State new_state,
Token::Value keyword_token) {
if (input != static_cast<unibrow::uchar>(match)) {
return false;
}
state_ = new_state;
token_ = keyword_token;
return true;
}
void Step(unibrow::uchar input);
// Current state.
State state_;
// Token for currently added characters.
Token::Value token_;
// Matching a specific keyword string (there is only one possible valid
// keyword with the current prefix).
const char* keyword_;
int counter_;
Token::Value keyword_token_;
};
} } // namespace v8::internal
#endif // V8_SCANNER_BASE_H_

323
deps/v8/src/scanner.cc

@ -30,27 +30,15 @@
#include "ast.h"
#include "handles.h"
#include "scanner.h"
#include "unicode-inl.h"
namespace v8 {
namespace internal {
// ----------------------------------------------------------------------------
// Character predicates
unibrow::Predicate<IdentifierStart, 128> Scanner::kIsIdentifierStart;
unibrow::Predicate<IdentifierPart, 128> Scanner::kIsIdentifierPart;
unibrow::Predicate<unibrow::LineTerminator, 128> Scanner::kIsLineTerminator;
unibrow::Predicate<unibrow::WhiteSpace, 128> Scanner::kIsWhiteSpace;
StaticResource<Scanner::Utf8Decoder> Scanner::utf8_decoder_;
// ----------------------------------------------------------------------------
// UTF8Buffer
UTF8Buffer::UTF8Buffer() : buffer_(kInitialCapacity) { }
UTF8Buffer::UTF8Buffer() : buffer_(kInitialCapacity), recording_(false) { }
UTF8Buffer::~UTF8Buffer() {}
@ -135,191 +123,6 @@ void CharacterStreamUTF16Buffer::SeekForward(int pos) {
}
// ExternalStringUTF16Buffer
template <typename StringType, typename CharType>
ExternalStringUTF16Buffer<StringType, CharType>::ExternalStringUTF16Buffer()
: raw_data_(NULL) { }
template <typename StringType, typename CharType>
void ExternalStringUTF16Buffer<StringType, CharType>::Initialize(
Handle<StringType> data,
int start_position,
int end_position) {
ASSERT(!data.is_null());
raw_data_ = data->resource()->data();
ASSERT(end_position <= data->length());
if (start_position > 0) {
SeekForward(start_position);
}
end_ =
end_position != Scanner::kNoEndPosition ? end_position : data->length();
}
template <typename StringType, typename CharType>
uc32 ExternalStringUTF16Buffer<StringType, CharType>::Advance() {
if (pos_ < end_) {
return raw_data_[pos_++];
} else {
// note: currently the following increment is necessary to avoid a
// test-parser problem!
pos_++;
return static_cast<uc32>(-1);
}
}
template <typename StringType, typename CharType>
void ExternalStringUTF16Buffer<StringType, CharType>::PushBack(uc32 ch) {
pos_--;
ASSERT(pos_ >= Scanner::kCharacterLookaheadBufferSize);
ASSERT(raw_data_[pos_ - Scanner::kCharacterLookaheadBufferSize] == ch);
}
template <typename StringType, typename CharType>
void ExternalStringUTF16Buffer<StringType, CharType>::SeekForward(int pos) {
pos_ = pos;
}
// ----------------------------------------------------------------------------
// Keyword Matcher
KeywordMatcher::FirstState KeywordMatcher::first_states_[] = {
{ "break", KEYWORD_PREFIX, Token::BREAK },
{ NULL, C, Token::ILLEGAL },
{ NULL, D, Token::ILLEGAL },
{ "else", KEYWORD_PREFIX, Token::ELSE },
{ NULL, F, Token::ILLEGAL },
{ NULL, UNMATCHABLE, Token::ILLEGAL },
{ NULL, UNMATCHABLE, Token::ILLEGAL },
{ NULL, I, Token::ILLEGAL },
{ NULL, UNMATCHABLE, Token::ILLEGAL },
{ NULL, UNMATCHABLE, Token::ILLEGAL },
{ NULL, UNMATCHABLE, Token::ILLEGAL },
{ NULL, UNMATCHABLE, Token::ILLEGAL },
{ NULL, N, Token::ILLEGAL },
{ NULL, UNMATCHABLE, Token::ILLEGAL },
{ NULL, UNMATCHABLE, Token::ILLEGAL },
{ NULL, UNMATCHABLE, Token::ILLEGAL },
{ "return", KEYWORD_PREFIX, Token::RETURN },
{ "switch", KEYWORD_PREFIX, Token::SWITCH },
{ NULL, T, Token::ILLEGAL },
{ NULL, UNMATCHABLE, Token::ILLEGAL },
{ NULL, V, Token::ILLEGAL },
{ NULL, W, Token::ILLEGAL }
};
void KeywordMatcher::Step(uc32 input) {
switch (state_) {
case INITIAL: {
// matching the first character is the only state with significant fanout.
// Match only lower-case letters in range 'b'..'w'.
unsigned int offset = input - kFirstCharRangeMin;
if (offset < kFirstCharRangeLength) {
state_ = first_states_[offset].state;
if (state_ == KEYWORD_PREFIX) {
keyword_ = first_states_[offset].keyword;
counter_ = 1;
keyword_token_ = first_states_[offset].token;
}
return;
}
break;
}
case KEYWORD_PREFIX:
if (keyword_[counter_] == input) {
ASSERT_NE(input, '\0');
counter_++;
if (keyword_[counter_] == '\0') {
state_ = KEYWORD_MATCHED;
token_ = keyword_token_;
}
return;
}
break;
case KEYWORD_MATCHED:
token_ = Token::IDENTIFIER;
break;
case C:
if (MatchState(input, 'a', CA)) return;
if (MatchState(input, 'o', CO)) return;
break;
case CA:
if (MatchKeywordStart(input, "case", 2, Token::CASE)) return;
if (MatchKeywordStart(input, "catch", 2, Token::CATCH)) return;
break;
case CO:
if (MatchState(input, 'n', CON)) return;
break;
case CON:
if (MatchKeywordStart(input, "const", 3, Token::CONST)) return;
if (MatchKeywordStart(input, "continue", 3, Token::CONTINUE)) return;
break;
case D:
if (MatchState(input, 'e', DE)) return;
if (MatchKeyword(input, 'o', KEYWORD_MATCHED, Token::DO)) return;
break;
case DE:
if (MatchKeywordStart(input, "debugger", 2, Token::DEBUGGER)) return;
if (MatchKeywordStart(input, "default", 2, Token::DEFAULT)) return;
if (MatchKeywordStart(input, "delete", 2, Token::DELETE)) return;
break;
case F:
if (MatchKeywordStart(input, "false", 1, Token::FALSE_LITERAL)) return;
if (MatchKeywordStart(input, "finally", 1, Token::FINALLY)) return;
if (MatchKeywordStart(input, "for", 1, Token::FOR)) return;
if (MatchKeywordStart(input, "function", 1, Token::FUNCTION)) return;
break;
case I:
if (MatchKeyword(input, 'f', KEYWORD_MATCHED, Token::IF)) return;
if (MatchKeyword(input, 'n', IN, Token::IN)) return;
break;
case IN:
token_ = Token::IDENTIFIER;
if (MatchKeywordStart(input, "instanceof", 2, Token::INSTANCEOF)) {
return;
}
break;
case N:
if (MatchKeywordStart(input, "native", 1, Token::NATIVE)) return;
if (MatchKeywordStart(input, "new", 1, Token::NEW)) return;
if (MatchKeywordStart(input, "null", 1, Token::NULL_LITERAL)) return;
break;
case T:
if (MatchState(input, 'h', TH)) return;
if (MatchState(input, 'r', TR)) return;
if (MatchKeywordStart(input, "typeof", 1, Token::TYPEOF)) return;
break;
case TH:
if (MatchKeywordStart(input, "this", 2, Token::THIS)) return;
if (MatchKeywordStart(input, "throw", 2, Token::THROW)) return;
break;
case TR:
if (MatchKeywordStart(input, "true", 2, Token::TRUE_LITERAL)) return;
if (MatchKeyword(input, 'y', KEYWORD_MATCHED, Token::TRY)) return;
break;
case V:
if (MatchKeywordStart(input, "var", 1, Token::VAR)) return;
if (MatchKeywordStart(input, "void", 1, Token::VOID)) return;
break;
case W:
if (MatchKeywordStart(input, "while", 1, Token::WHILE)) return;
if (MatchKeywordStart(input, "with", 1, Token::WITH)) return;
break;
default:
UNREACHABLE();
}
// On fallthrough, it's a failure.
state_ = UNMATCHABLE;
}
// ----------------------------------------------------------------------------
// Scanner::LiteralScope
@ -445,7 +248,7 @@ void Scanner::StartLiteral() {
}
void Scanner::AddChar(uc32 c) {
void Scanner::AddLiteralChar(uc32 c) {
literal_buffer_.AddChar(c);
}
@ -460,8 +263,8 @@ void Scanner::DropLiteral() {
}
void Scanner::AddCharAdvance() {
AddChar(c0_);
void Scanner::AddLiteralCharAdvance() {
AddLiteralChar(c0_);
Advance();
}
@ -494,9 +297,9 @@ bool Scanner::SkipJavaScriptWhiteSpace() {
while (true) {
// We treat byte-order marks (BOMs) as whitespace for better
// compatibility with Spidermonkey and other JavaScript engines.
while (kIsWhiteSpace.get(c0_) || IsByteOrderMark(c0_)) {
while (ScannerConstants::kIsWhiteSpace.get(c0_) || IsByteOrderMark(c0_)) {
// IsWhiteSpace() includes line terminators!
if (kIsLineTerminator.get(c0_)) {
if (ScannerConstants::kIsLineTerminator.get(c0_)) {
// Ignore line terminators, but remember them. This is necessary
// for automatic semicolon insertion.
has_line_terminator_before_next_ = true;
@ -536,7 +339,7 @@ Token::Value Scanner::SkipSingleLineComment() {
// separately by the lexical grammar and becomes part of the
// stream of input elements for the syntactic grammar (see
// ECMA-262, section 7.4, page 12).
while (c0_ >= 0 && !kIsLineTerminator.get(c0_)) {
while (c0_ >= 0 && !ScannerConstants::kIsLineTerminator.get(c0_)) {
Advance();
}
@ -673,29 +476,29 @@ Token::Value Scanner::ScanJsonString() {
// Check for control character (0x00-0x1f) or unterminated string (<0).
if (c0_ < 0x20) return Token::ILLEGAL;
if (c0_ != '\\') {
AddCharAdvance();
AddLiteralCharAdvance();
} else {
Advance();
switch (c0_) {
case '"':
case '\\':
case '/':
AddChar(c0_);
AddLiteralChar(c0_);
break;
case 'b':
AddChar('\x08');
AddLiteralChar('\x08');
break;
case 'f':
AddChar('\x0c');
AddLiteralChar('\x0c');
break;
case 'n':
AddChar('\x0a');
AddLiteralChar('\x0a');
break;
case 'r':
AddChar('\x0d');
AddLiteralChar('\x0d');
break;
case 't':
AddChar('\x09');
AddLiteralChar('\x09');
break;
case 'u': {
uc32 value = 0;
@ -707,7 +510,7 @@ Token::Value Scanner::ScanJsonString() {
}
value = value * 16 + digit;
}
AddChar(value);
AddLiteralChar(value);
break;
}
default:
@ -727,31 +530,31 @@ Token::Value Scanner::ScanJsonString() {
Token::Value Scanner::ScanJsonNumber() {
LiteralScope literal(this);
if (c0_ == '-') AddCharAdvance();
if (c0_ == '-') AddLiteralCharAdvance();
if (c0_ == '0') {
AddCharAdvance();
AddLiteralCharAdvance();
// Prefix zero is only allowed if it's the only digit before
// a decimal point or exponent.
if ('0' <= c0_ && c0_ <= '9') return Token::ILLEGAL;
} else {
if (c0_ < '1' || c0_ > '9') return Token::ILLEGAL;
do {
AddCharAdvance();
AddLiteralCharAdvance();
} while (c0_ >= '0' && c0_ <= '9');
}
if (c0_ == '.') {
AddCharAdvance();
AddLiteralCharAdvance();
if (c0_ < '0' || c0_ > '9') return Token::ILLEGAL;
do {
AddCharAdvance();
AddLiteralCharAdvance();
} while (c0_ >= '0' && c0_ <= '9');
}
if (AsciiAlphaToLower(c0_) == 'e') {
AddCharAdvance();
if (c0_ == '-' || c0_ == '+') AddCharAdvance();
AddLiteralCharAdvance();
if (c0_ == '-' || c0_ == '+') AddLiteralCharAdvance();
if (c0_ < '0' || c0_ > '9') return Token::ILLEGAL;
do {
AddCharAdvance();
AddLiteralCharAdvance();
} while (c0_ >= '0' && c0_ <= '9');
}
literal.Complete();
@ -767,7 +570,7 @@ Token::Value Scanner::ScanJsonIdentifier(const char* text,
Advance();
text++;
}
if (kIsIdentifierPart.get(c0_)) return Token::ILLEGAL;
if (ScannerConstants::kIsIdentifierPart.get(c0_)) return Token::ILLEGAL;
literal.Complete();
return token;
}
@ -990,7 +793,7 @@ void Scanner::ScanJavaScript() {
break;
default:
if (kIsIdentifierStart.get(c0_)) {
if (ScannerConstants::kIsIdentifierStart.get(c0_)) {
token = ScanIdentifier();
} else if (IsDecimalDigit(c0_)) {
token = ScanNumber(false);
@ -1073,7 +876,7 @@ void Scanner::ScanEscape() {
Advance();
// Skip escaped newlines.
if (kIsLineTerminator.get(c)) {
if (ScannerConstants::kIsLineTerminator.get(c)) {
// Allow CR+LF newlines in multiline string literals.
if (IsCarriageReturn(c) && IsLineFeed(c0_)) Advance();
// Allow LF+CR newlines in multiline string literals.
@ -1106,7 +909,7 @@ void Scanner::ScanEscape() {
// According to ECMA-262, 3rd, 7.8.4 (p 18ff) these
// should be illegal, but they are commonly handled
// as non-escaped characters by JS VMs.
AddChar(c);
AddLiteralChar(c);
}
@ -1115,14 +918,15 @@ Token::Value Scanner::ScanString() {
Advance(); // consume quote
LiteralScope literal(this);
while (c0_ != quote && c0_ >= 0 && !kIsLineTerminator.get(c0_)) {
while (c0_ != quote && c0_ >= 0
&& !ScannerConstants::kIsLineTerminator.get(c0_)) {
uc32 c = c0_;
Advance();
if (c == '\\') {
if (c0_ < 0) return Token::ILLEGAL;
ScanEscape();
} else {
AddChar(c);
AddLiteralChar(c);
}
}
if (c0_ != quote) return Token::ILLEGAL;
@ -1153,7 +957,7 @@ Token::Value Scanner::Select(uc32 next, Token::Value then, Token::Value else_) {
// Returns true if any decimal digits were scanned, returns false otherwise.
void Scanner::ScanDecimalDigits() {
while (IsDecimalDigit(c0_))
AddCharAdvance();
AddLiteralCharAdvance();
}
@ -1165,25 +969,25 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
LiteralScope literal(this);
if (seen_period) {
// we have already seen a decimal point of the float
AddChar('.');
AddLiteralChar('.');
ScanDecimalDigits(); // we know we have at least one digit
} else {
// if the first character is '0' we must check for octals and hex
if (c0_ == '0') {
AddCharAdvance();
AddLiteralCharAdvance();
// either 0, 0exxx, 0Exxx, 0.xxx, an octal number, or a hex number
if (c0_ == 'x' || c0_ == 'X') {
// hex number
kind = HEX;
AddCharAdvance();
AddLiteralCharAdvance();
if (!IsHexDigit(c0_)) {
// we must have at least one hex digit after 'x'/'X'
return Token::ILLEGAL;
}
while (IsHexDigit(c0_)) {
AddCharAdvance();
AddLiteralCharAdvance();
}
} else if ('0' <= c0_ && c0_ <= '7') {
// (possible) octal number
@ -1194,7 +998,7 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
break;
}
if (c0_ < '0' || '7' < c0_) break;
AddCharAdvance();
AddLiteralCharAdvance();
}
}
}
@ -1203,7 +1007,7 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
if (kind == DECIMAL) {
ScanDecimalDigits(); // optional
if (c0_ == '.') {
AddCharAdvance();
AddLiteralCharAdvance();
ScanDecimalDigits(); // optional
}
}
@ -1214,9 +1018,9 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
ASSERT(kind != HEX); // 'e'/'E' must be scanned as part of the hex number
if (kind == OCTAL) return Token::ILLEGAL; // no exponent for octals allowed
// scan exponent
AddCharAdvance();
AddLiteralCharAdvance();
if (c0_ == '+' || c0_ == '-')
AddCharAdvance();
AddLiteralCharAdvance();
if (!IsDecimalDigit(c0_)) {
// we must have at least one decimal digit after 'e'/'E'
return Token::ILLEGAL;
@ -1228,7 +1032,7 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
// not be an identifier start or a decimal digit; see ECMA-262
// section 7.8.3, page 17 (note that we read only one decimal digit
// if the value is 0).
if (IsDecimalDigit(c0_) || kIsIdentifierStart.get(c0_))
if (IsDecimalDigit(c0_) || ScannerConstants::kIsIdentifierStart.get(c0_))
return Token::ILLEGAL;
literal.Complete();
@ -1250,7 +1054,7 @@ uc32 Scanner::ScanIdentifierUnicodeEscape() {
Token::Value Scanner::ScanIdentifier() {
ASSERT(kIsIdentifierStart.get(c0_));
ASSERT(ScannerConstants::kIsIdentifierStart.get(c0_));
LiteralScope literal(this);
KeywordMatcher keyword_match;
@ -1259,25 +1063,25 @@ Token::Value Scanner::ScanIdentifier() {
if (c0_ == '\\') {
uc32 c = ScanIdentifierUnicodeEscape();
// Only allow legal identifier start characters.
if (!kIsIdentifierStart.get(c)) return Token::ILLEGAL;
AddChar(c);
if (!ScannerConstants::kIsIdentifierStart.get(c)) return Token::ILLEGAL;
AddLiteralChar(c);
keyword_match.Fail();
} else {
AddChar(c0_);
AddLiteralChar(c0_);
keyword_match.AddChar(c0_);
Advance();
}
// Scan the rest of the identifier characters.
while (kIsIdentifierPart.get(c0_)) {
while (ScannerConstants::kIsIdentifierPart.get(c0_)) {
if (c0_ == '\\') {
uc32 c = ScanIdentifierUnicodeEscape();
// Only allow legal identifier part characters.
if (!kIsIdentifierPart.get(c)) return Token::ILLEGAL;
AddChar(c);
if (!ScannerConstants::kIsIdentifierPart.get(c)) return Token::ILLEGAL;
AddLiteralChar(c);
keyword_match.Fail();
} else {
AddChar(c0_);
AddLiteralChar(c0_);
keyword_match.AddChar(c0_);
Advance();
}
@ -1289,17 +1093,6 @@ Token::Value Scanner::ScanIdentifier() {
bool Scanner::IsIdentifier(unibrow::CharacterStream* buffer) {
// Checks whether the buffer contains an identifier (no escape).
if (!buffer->has_more()) return false;
if (!kIsIdentifierStart.get(buffer->GetNext())) return false;
while (buffer->has_more()) {
if (!kIsIdentifierPart.get(buffer->GetNext())) return false;
}
return true;
}
bool Scanner::ScanRegExpPattern(bool seen_equal) {
// Scan: ('/' | '/=') RegularExpressionBody '/' RegularExpressionFlags
bool in_character_class = false;
@ -1314,18 +1107,18 @@ bool Scanner::ScanRegExpPattern(bool seen_equal) {
// constructor.
LiteralScope literal(this);
if (seen_equal)
AddChar('=');
AddLiteralChar('=');
while (c0_ != '/' || in_character_class) {
if (kIsLineTerminator.get(c0_) || c0_ < 0) return false;
if (ScannerConstants::kIsLineTerminator.get(c0_) || c0_ < 0) return false;
if (c0_ == '\\') { // escaped character
AddCharAdvance();
if (kIsLineTerminator.get(c0_) || c0_ < 0) return false;
AddCharAdvance();
AddLiteralCharAdvance();
if (ScannerConstants::kIsLineTerminator.get(c0_) || c0_ < 0) return false;
AddLiteralCharAdvance();
} else { // unescaped character
if (c0_ == '[') in_character_class = true;
if (c0_ == ']') in_character_class = false;
AddCharAdvance();
AddLiteralCharAdvance();
}
}
Advance(); // consume '/'
@ -1338,17 +1131,17 @@ bool Scanner::ScanRegExpPattern(bool seen_equal) {
bool Scanner::ScanRegExpFlags() {
// Scan regular expression flags.
LiteralScope literal(this);
while (kIsIdentifierPart.get(c0_)) {
while (ScannerConstants::kIsIdentifierPart.get(c0_)) {
if (c0_ == '\\') {
uc32 c = ScanIdentifierUnicodeEscape();
if (c != static_cast<uc32>(unibrow::Utf8::kBadChar)) {
// We allow any escaped character, unlike the restriction on
// IdentifierPart when it is used to build an IdentifierName.
AddChar(c);
AddLiteralChar(c);
continue;
}
}
AddCharAdvance();
AddLiteralCharAdvance();
}
literal.Complete();

215
deps/v8/src/scanner.h

@ -30,6 +30,7 @@
#include "token.h"
#include "char-predicates-inl.h"
#include "scanner-base.h"
namespace v8 {
namespace internal {
@ -41,26 +42,36 @@ class UTF8Buffer {
~UTF8Buffer();
inline void AddChar(uc32 c) {
if (recording_) {
if (static_cast<unsigned>(c) <= unibrow::Utf8::kMaxOneByteChar) {
buffer_.Add(static_cast<char>(c));
} else {
AddCharSlow(c);
}
}
}
void StartLiteral() {
buffer_.StartSequence();
recording_ = true;
}
Vector<const char> EndLiteral() {
if (recording_) {
recording_ = false;
buffer_.Add(kEndMarker);
Vector<char> sequence = buffer_.EndSequence();
return Vector<const char>(sequence.start(), sequence.length());
}
return Vector<const char>();
}
void DropLiteral() {
if (recording_) {
recording_ = false;
buffer_.DropSequence();
}
}
void Reset() {
buffer_.Reset();
@ -78,30 +89,11 @@ class UTF8Buffer {
private:
static const int kInitialCapacity = 256;
SequenceCollector<char, 4> buffer_;
bool recording_;
void AddCharSlow(uc32 c);
};
// Interface through which the scanner reads characters from the input source.
class UTF16Buffer {
public:
UTF16Buffer();
virtual ~UTF16Buffer() {}
virtual void PushBack(uc32 ch) = 0;
// Returns a value < 0 when the buffer end is reached.
virtual uc32 Advance() = 0;
virtual void SeekForward(int pos) = 0;
int pos() const { return pos_; }
protected:
int pos_; // Current position in the buffer.
int end_; // Position where scanning should stop (EOF).
};
// UTF16 buffer to read characters from a character stream.
class CharacterStreamUTF16Buffer: public UTF16Buffer {
public:
@ -142,127 +134,6 @@ class ExternalStringUTF16Buffer: public UTF16Buffer {
};
class KeywordMatcher {
// Incrementally recognize keywords.
//
// Recognized keywords:
// break case catch const* continue debugger* default delete do else
// finally false for function if in instanceof native* new null
// return switch this throw true try typeof var void while with
//
// *: Actually "future reserved keywords". These are the only ones we
// recognized, the remaining are allowed as identifiers.
public:
KeywordMatcher()
: state_(INITIAL),
token_(Token::IDENTIFIER),
keyword_(NULL),
counter_(0),
keyword_token_(Token::ILLEGAL) {}
Token::Value token() { return token_; }
inline void AddChar(uc32 input) {
if (state_ != UNMATCHABLE) {
Step(input);
}
}
void Fail() {
token_ = Token::IDENTIFIER;
state_ = UNMATCHABLE;
}
private:
enum State {
UNMATCHABLE,
INITIAL,
KEYWORD_PREFIX,
KEYWORD_MATCHED,
C,
CA,
CO,
CON,
D,
DE,
F,
I,
IN,
N,
T,
TH,
TR,
V,
W
};
struct FirstState {
const char* keyword;
State state;
Token::Value token;
};
// Range of possible first characters of a keyword.
static const unsigned int kFirstCharRangeMin = 'b';
static const unsigned int kFirstCharRangeMax = 'w';
static const unsigned int kFirstCharRangeLength =
kFirstCharRangeMax - kFirstCharRangeMin + 1;
// State map for first keyword character range.
static FirstState first_states_[kFirstCharRangeLength];
// If input equals keyword's character at position, continue matching keyword
// from that position.
inline bool MatchKeywordStart(uc32 input,
const char* keyword,
int position,
Token::Value token_if_match) {
if (input == keyword[position]) {
state_ = KEYWORD_PREFIX;
this->keyword_ = keyword;
this->counter_ = position + 1;
this->keyword_token_ = token_if_match;
return true;
}
return false;
}
// If input equals match character, transition to new state and return true.
inline bool MatchState(uc32 input, char match, State new_state) {
if (input == match) {
state_ = new_state;
return true;
}
return false;
}
inline bool MatchKeyword(uc32 input,
char match,
State new_state,
Token::Value keyword_token) {
if (input != match) {
return false;
}
state_ = new_state;
token_ = keyword_token;
return true;
}
void Step(uc32 input);
// Current state.
State state_;
// Token for currently added characters.
Token::Value token_;
// Matching a specific keyword string (there is only one possible valid
// keyword with the current prefix).
const char* keyword_;
int counter_;
Token::Value keyword_token_;
};
enum ParserMode { PARSE, PREPARSE };
enum ParserLanguage { JAVASCRIPT, JSON };
@ -371,17 +242,10 @@ class Scanner {
bool stack_overflow() { return stack_overflow_; }
static StaticResource<Utf8Decoder>* utf8_decoder() { return &utf8_decoder_; }
// Tells whether the buffer contains an identifier (no escapes).
// Used for checking if a property name is an identifier.
static bool IsIdentifier(unibrow::CharacterStream* buffer);
static unibrow::Predicate<IdentifierStart, 128> kIsIdentifierStart;
static unibrow::Predicate<IdentifierPart, 128> kIsIdentifierPart;
static unibrow::Predicate<unibrow::LineTerminator, 128> kIsLineTerminator;
static unibrow::Predicate<unibrow::WhiteSpace, 128> kIsWhiteSpace;
static const int kCharacterLookaheadBufferSize = 1;
static const int kNoEndPosition = 1;
@ -400,8 +264,8 @@ class Scanner {
// Literal buffer support
inline void StartLiteral();
inline void AddChar(uc32 ch);
inline void AddCharAdvance();
inline void AddLiteralChar(uc32 ch);
inline void AddLiteralCharAdvance();
inline void TerminateLiteral();
// Stops scanning of a literal, e.g., due to an encountered error.
inline void DropLiteral();
@ -511,12 +375,61 @@ class Scanner {
UTF8Buffer literal_buffer_;
bool stack_overflow_;
static StaticResource<Utf8Decoder> utf8_decoder_;
// One Unicode character look-ahead; c0_ < 0 at the end of the input.
uc32 c0_;
};
// ExternalStringUTF16Buffer
template <typename StringType, typename CharType>
ExternalStringUTF16Buffer<StringType, CharType>::ExternalStringUTF16Buffer()
: raw_data_(NULL) { }
template <typename StringType, typename CharType>
void ExternalStringUTF16Buffer<StringType, CharType>::Initialize(
Handle<StringType> data,
int start_position,
int end_position) {
ASSERT(!data.is_null());
raw_data_ = data->resource()->data();
ASSERT(end_position <= data->length());
if (start_position > 0) {
SeekForward(start_position);
}
end_ =
end_position != Scanner::kNoEndPosition ? end_position : data->length();
}
template <typename StringType, typename CharType>
uc32 ExternalStringUTF16Buffer<StringType, CharType>::Advance() {
if (pos_ < end_) {
return raw_data_[pos_++];
} else {
// note: currently the following increment is necessary to avoid a
// test-parser problem!
pos_++;
return static_cast<uc32>(-1);
}
}
template <typename StringType, typename CharType>
void ExternalStringUTF16Buffer<StringType, CharType>::PushBack(uc32 ch) {
pos_--;
ASSERT(pos_ >= Scanner::kCharacterLookaheadBufferSize);
ASSERT(raw_data_[pos_ - Scanner::kCharacterLookaheadBufferSize] == ch);
}
template <typename StringType, typename CharType>
void ExternalStringUTF16Buffer<StringType, CharType>::SeekForward(int pos) {
pos_ = pos;
}
} } // namespace v8::internal
#endif // V8_SCANNER_H_

4
deps/v8/src/serialize.cc

@ -290,10 +290,6 @@ void ExternalReferenceTable::PopulateTable() {
Add(Top::get_address_from_id((Top::AddressId)i), TOP_ADDRESS, i, chars);
}
// Extensions
Add(FUNCTION_ADDR(GCExtension::GC), EXTENSION, 1,
"GCExtension::GC");
// Accessors
#define ACCESSOR_DESCRIPTOR_DECLARATION(name) \
Add((Address)&Accessors::name, \

60
deps/v8/src/spaces.cc

@ -271,6 +271,7 @@ void CodeRange::TearDown() {
// MemoryAllocator
//
intptr_t MemoryAllocator::capacity_ = 0;
intptr_t MemoryAllocator::capacity_executable_ = 0;
intptr_t MemoryAllocator::size_ = 0;
intptr_t MemoryAllocator::size_executable_ = 0;
@ -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()) {
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, (executable == EXECUTABLE));
mem = OS::Allocate(requested, allocated, true);
}
// Update executable memory size.
size_executable_ += static_cast<int>(*allocated);
} else {
mem = OS::Allocate(requested, allocated, false);
}
int alloced = static_cast<int>(*allocated);
size_ += alloced;
if (executable == EXECUTABLE) size_executable_ += alloced;
#ifdef DEBUG
ZapBlock(reinterpret_cast<Address>(mem), alloced);
#endif
@ -391,6 +410,7 @@ void MemoryAllocator::FreeRawMemory(void* mem,
if (executable == EXECUTABLE) size_executable_ -= static_cast<int>(length);
ASSERT(size_ >= 0);
ASSERT(size_executable_ >= 0);
}
@ -1878,6 +1898,18 @@ MaybeObject* OldSpaceFreeList::Allocate(int size_in_bytes, int* wasted_bytes) {
}
void OldSpaceFreeList::MarkNodes() {
for (int i = 0; i < kFreeListsLength; i++) {
Address cur_addr = free_[i].head_node_;
while (cur_addr != NULL) {
FreeListNode* cur_node = FreeListNode::FromAddress(cur_addr);
cur_addr = cur_node->next();
cur_node->SetMark();
}
}
}
#ifdef DEBUG
bool OldSpaceFreeList::Contains(FreeListNode* node) {
for (int i = 0; i < kFreeListsLength; i++) {
@ -1937,6 +1969,16 @@ MaybeObject* FixedSizeFreeList::Allocate() {
}
void FixedSizeFreeList::MarkNodes() {
Address cur_addr = head_;
while (cur_addr != NULL && cur_addr != tail_) {
FreeListNode* cur_node = FreeListNode::FromAddress(cur_addr);
cur_addr = cur_node->next();
cur_node->SetMark();
}
}
// -----------------------------------------------------------------------------
// OldSpace implementation
@ -2691,13 +2733,15 @@ LargeObjectSpace::LargeObjectSpace(AllocationSpace id)
: Space(id, NOT_EXECUTABLE), // Managed on a per-allocation basis
first_chunk_(NULL),
size_(0),
page_count_(0) {}
page_count_(0),
objects_size_(0) {}
bool LargeObjectSpace::Setup() {
first_chunk_ = NULL;
size_ = 0;
page_count_ = 0;
objects_size_ = 0;
return true;
}
@ -2720,6 +2764,7 @@ void LargeObjectSpace::TearDown() {
size_ = 0;
page_count_ = 0;
objects_size_ = 0;
}
@ -2766,6 +2811,7 @@ MaybeObject* LargeObjectSpace::AllocateRawInternal(int requested_size,
}
size_ += static_cast<int>(chunk_size);
objects_size_ += requested_size;
page_count_++;
chunk->set_next(first_chunk_);
chunk->set_size(chunk_size);
@ -2928,6 +2974,7 @@ void LargeObjectSpace::FreeUnmarkedObjects() {
// Free the chunk.
MarkCompactCollector::ReportDeleteIfNeeded(object);
size_ -= static_cast<int>(chunk_size);
objects_size_ -= object->Size();
page_count_--;
ObjectSpace space = kObjectSpaceLoSpace;
if (executable == EXECUTABLE) space = kObjectSpaceCodeSpace;
@ -3032,7 +3079,8 @@ void LargeObjectSpace::ReportStatistics() {
CollectHistogramInfo(obj);
}
PrintF(" number of objects %d\n", num_objects);
PrintF(" number of objects %d, "
"size of objects %" V8_PTR_PREFIX "d\n", num_objects, objects_size_);
if (num_objects > 0) ReportHistogram(false);
}

32
deps/v8/src/spaces.h

@ -371,8 +371,13 @@ class Space : public Malloced {
// Identity used in error reporting.
AllocationSpace identity() { return id_; }
// Returns allocated size.
virtual intptr_t Size() = 0;
// Returns size of objects. Can differ from the allocated size
// (e.g. see LargeObjectSpace).
virtual intptr_t SizeOfObjects() { return Size(); }
#ifdef ENABLE_HEAP_PROTECTION
// Protect/unprotect the space by marking it read-only/writable.
virtual void Protect() = 0;
@ -491,8 +496,8 @@ class CodeRange : public AllStatic {
class MemoryAllocator : public AllStatic {
public:
// Initializes its internal bookkeeping structures.
// Max capacity of the total space.
static bool Setup(intptr_t max_capacity);
// Max capacity of the total space and executable memory limit.
static bool Setup(intptr_t max_capacity, intptr_t capacity_executable);
// Deletes valid chunks.
static void TearDown();
@ -590,6 +595,12 @@ class MemoryAllocator : public AllStatic {
// Returns allocated spaces in bytes.
static intptr_t Size() { return size_; }
// Returns the maximum available executable bytes of heaps.
static intptr_t AvailableExecutable() {
if (capacity_executable_ < size_executable_) return 0;
return capacity_executable_ - size_executable_;
}
// Returns allocated executable spaces in bytes.
static intptr_t SizeExecutable() { return size_executable_; }
@ -653,6 +664,8 @@ class MemoryAllocator : public AllStatic {
private:
// Maximum space size in bytes.
static intptr_t capacity_;
// Maximum subset of capacity_ that can be executable
static intptr_t capacity_executable_;
// Allocated space size in bytes.
static intptr_t size_;
@ -1707,6 +1720,8 @@ class OldSpaceFreeList BASE_EMBEDDED {
// 'wasted_bytes'. The size should be a non-zero multiple of the word size.
MUST_USE_RESULT MaybeObject* Allocate(int size_in_bytes, int* wasted_bytes);
void MarkNodes();
private:
// The size range of blocks, in bytes. (Smaller allocations are allowed, but
// will always result in waste.)
@ -1805,6 +1820,8 @@ class FixedSizeFreeList BASE_EMBEDDED {
// A failure is returned if no block is available.
MUST_USE_RESULT MaybeObject* Allocate();
void MarkNodes();
private:
// Available bytes on the free list.
intptr_t available_;
@ -1876,6 +1893,8 @@ class OldSpace : public PagedSpace {
virtual void PutRestOfCurrentPageOnFreeList(Page* current_page);
void MarkFreeListNodes() { free_list_.MarkNodes(); }
#ifdef DEBUG
// Reports statistics for the space
void ReportStatistics();
@ -1943,6 +1962,9 @@ class FixedSpace : public PagedSpace {
virtual void DeallocateBlock(Address start,
int size_in_bytes,
bool add_to_freelist);
void MarkFreeListNodes() { free_list_.MarkNodes(); }
#ifdef DEBUG
// Reports statistic info of the space
void ReportStatistics();
@ -2183,6 +2205,10 @@ class LargeObjectSpace : public Space {
return size_;
}
virtual intptr_t SizeOfObjects() {
return objects_size_;
}
int PageCount() {
return page_count_;
}
@ -2234,7 +2260,7 @@ class LargeObjectSpace : public Space {
LargeObjectChunk* first_chunk_;
intptr_t size_; // allocated bytes
int page_count_; // number of chunks
intptr_t objects_size_; // size of objects
// Shared implementation of AllocateRaw, AllocateRawCode and
// AllocateRawFixedArray.

78
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,
return %StringReplaceRegExpWithString(subject,
regexp,
replace,
TO_STRING_INLINE(replace),
lastMatchInfo);
cache.subject = subject;
cache.regExp = regexp;
cache.replaceString = replace;
cache.answer = answer;
cache.type = 'replace';
return answer;
}
@ -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;
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save