mirror of https://github.com/lukechilds/node.git
Browse Source
Pick up the latest branch-head for V8 5.1. This branch brings in improved language support and performance improvements. For full details: http://v8project.blogspot.com/2016/04/v8-release-51.html * Picks up the latest branch head for 5.1 [1] * Edit v8 gitignore to allow trace_event copy * Update V8 DEP trace_event as per deps/v8/DEPS [2] [1] https://chromium.googlesource.com/v8/v8.git/+/dc81244 [2] https://chromium.googlesource.com/chromium/src/base/trace_event/common/+/c8c8665 PR-URL: https://github.com/nodejs/node/pull/7016 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>v7.x
1487 changed files with 280129 additions and 62497 deletions
@ -0,0 +1,8 @@ |
|||
# V8 Code of Conduct |
|||
|
|||
As part of the Chromium team, the V8 team is committed to preserving and |
|||
fostering a diverse, welcoming community. To this end, the [Chromium Code of |
|||
Conduct](https://chromium.googlesource.com/chromium/src/+/master/CODE_OF_CONDUCT.md) |
|||
applies to our repos and organizations, mailing lists, blog content, and any |
|||
other Chromium-supported communication group, as well as any private |
|||
communication initiated in the context of these spaces. |
File diff suppressed because it is too large
@ -0,0 +1,36 @@ |
|||
#!/usr/bin/env python |
|||
# Copyright 2016 the V8 project authors. All rights reserved. |
|||
# Use of this source code is governed by a BSD-style license that can be |
|||
# found in the LICENSE file. |
|||
|
|||
# CC/CXX wrapper script that excludes certain file patterns from coverage |
|||
# instrumentation. |
|||
|
|||
import re |
|||
import subprocess |
|||
import sys |
|||
|
|||
exclusions = [ |
|||
'buildtools', |
|||
'src/third_party', |
|||
'third_party', |
|||
'test', |
|||
'testing', |
|||
] |
|||
|
|||
def remove_if_exists(string_list, item): |
|||
if item in string_list: |
|||
string_list.remove(item) |
|||
|
|||
args = sys.argv[1:] |
|||
text = ' '.join(sys.argv[2:]) |
|||
for exclusion in exclusions: |
|||
if re.search(r'\-o obj/%s[^ ]*\.o' % exclusion, text): |
|||
remove_if_exists(args, '-fprofile-arcs') |
|||
remove_if_exists(args, '-ftest-coverage') |
|||
remove_if_exists(args, '-fsanitize-coverage=func') |
|||
remove_if_exists(args, '-fsanitize-coverage=bb') |
|||
remove_if_exists(args, '-fsanitize-coverage=edge') |
|||
break |
|||
|
|||
sys.exit(subprocess.check_call(args)) |
@ -0,0 +1,31 @@ |
|||
// Copyright 2016 the V8 project authors. All rights reserved.
|
|||
// Use of this source code is governed by a BSD-style license that can be
|
|||
// found in the LICENSE file.
|
|||
|
|||
#include "src/api-arguments.h" |
|||
|
|||
namespace v8 { |
|||
namespace internal { |
|||
|
|||
Handle<Object> FunctionCallbackArguments::Call(FunctionCallback f) { |
|||
Isolate* isolate = this->isolate(); |
|||
VMState<EXTERNAL> state(isolate); |
|||
ExternalCallbackScope call_scope(isolate, FUNCTION_ADDR(f)); |
|||
FunctionCallbackInfo<v8::Value> info(begin(), argv_, argc_, |
|||
is_construct_call_); |
|||
f(info); |
|||
return GetReturnValue<Object>(isolate); |
|||
} |
|||
|
|||
Handle<JSObject> PropertyCallbackArguments::Call( |
|||
IndexedPropertyEnumeratorCallback f) { |
|||
Isolate* isolate = this->isolate(); |
|||
VMState<EXTERNAL> state(isolate); |
|||
ExternalCallbackScope call_scope(isolate, FUNCTION_ADDR(f)); |
|||
PropertyCallbackInfo<v8::Array> info(begin()); |
|||
f(info); |
|||
return GetReturnValue<JSObject>(isolate); |
|||
} |
|||
|
|||
} // namespace internal
|
|||
} // namespace v8
|
@ -0,0 +1,254 @@ |
|||
// Copyright 2016 the V8 project authors. All rights reserved.
|
|||
// Use of this source code is governed by a BSD-style license that can be
|
|||
// found in the LICENSE file.
|
|||
|
|||
#ifndef V8_API_ARGUMENTS_H_ |
|||
#define V8_API_ARGUMENTS_H_ |
|||
|
|||
#include "src/api.h" |
|||
#include "src/isolate.h" |
|||
#include "src/tracing/trace-event.h" |
|||
#include "src/vm-state-inl.h" |
|||
|
|||
namespace v8 { |
|||
namespace internal { |
|||
|
|||
// Custom arguments replicate a small segment of stack that can be
|
|||
// accessed through an Arguments object the same way the actual stack
|
|||
// can.
|
|||
template <int kArrayLength> |
|||
class CustomArgumentsBase : public Relocatable { |
|||
public: |
|||
virtual inline void IterateInstance(ObjectVisitor* v) { |
|||
v->VisitPointers(values_, values_ + kArrayLength); |
|||
} |
|||
|
|||
protected: |
|||
inline Object** begin() { return values_; } |
|||
explicit inline CustomArgumentsBase(Isolate* isolate) |
|||
: Relocatable(isolate) {} |
|||
Object* values_[kArrayLength]; |
|||
}; |
|||
|
|||
template <typename T> |
|||
class CustomArguments : public CustomArgumentsBase<T::kArgsLength> { |
|||
public: |
|||
static const int kReturnValueOffset = T::kReturnValueIndex; |
|||
|
|||
typedef CustomArgumentsBase<T::kArgsLength> Super; |
|||
~CustomArguments() { |
|||
this->begin()[kReturnValueOffset] = |
|||
reinterpret_cast<Object*>(kHandleZapValue); |
|||
} |
|||
|
|||
protected: |
|||
explicit inline CustomArguments(Isolate* isolate) : Super(isolate) {} |
|||
|
|||
template <typename V> |
|||
Handle<V> GetReturnValue(Isolate* isolate); |
|||
|
|||
inline Isolate* isolate() { |
|||
return reinterpret_cast<Isolate*>(this->begin()[T::kIsolateIndex]); |
|||
} |
|||
}; |
|||
|
|||
template <typename T> |
|||
template <typename V> |
|||
Handle<V> CustomArguments<T>::GetReturnValue(Isolate* isolate) { |
|||
// Check the ReturnValue.
|
|||
Object** handle = &this->begin()[kReturnValueOffset]; |
|||
// Nothing was set, return empty handle as per previous behaviour.
|
|||
if ((*handle)->IsTheHole()) return Handle<V>(); |
|||
Handle<V> result = Handle<V>::cast(Handle<Object>(handle)); |
|||
result->VerifyApiCallResultType(); |
|||
return result; |
|||
} |
|||
|
|||
class PropertyCallbackArguments |
|||
: public CustomArguments<PropertyCallbackInfo<Value> > { |
|||
public: |
|||
typedef PropertyCallbackInfo<Value> T; |
|||
typedef CustomArguments<T> Super; |
|||
static const int kArgsLength = T::kArgsLength; |
|||
static const int kThisIndex = T::kThisIndex; |
|||
static const int kHolderIndex = T::kHolderIndex; |
|||
static const int kDataIndex = T::kDataIndex; |
|||
static const int kReturnValueDefaultValueIndex = |
|||
T::kReturnValueDefaultValueIndex; |
|||
static const int kIsolateIndex = T::kIsolateIndex; |
|||
static const int kShouldThrowOnErrorIndex = T::kShouldThrowOnErrorIndex; |
|||
|
|||
PropertyCallbackArguments(Isolate* isolate, Object* data, Object* self, |
|||
JSObject* holder, Object::ShouldThrow should_throw) |
|||
: Super(isolate) { |
|||
Object** values = this->begin(); |
|||
values[T::kThisIndex] = self; |
|||
values[T::kHolderIndex] = holder; |
|||
values[T::kDataIndex] = data; |
|||
values[T::kIsolateIndex] = reinterpret_cast<Object*>(isolate); |
|||
values[T::kShouldThrowOnErrorIndex] = |
|||
Smi::FromInt(should_throw == Object::THROW_ON_ERROR ? 1 : 0); |
|||
|
|||
// Here the hole is set as default value.
|
|||
// It cannot escape into js as it's remove in Call below.
|
|||
values[T::kReturnValueDefaultValueIndex] = |
|||
isolate->heap()->the_hole_value(); |
|||
values[T::kReturnValueIndex] = isolate->heap()->the_hole_value(); |
|||
DCHECK(values[T::kHolderIndex]->IsHeapObject()); |
|||
DCHECK(values[T::kIsolateIndex]->IsSmi()); |
|||
} |
|||
|
|||
/*
|
|||
* The following Call functions wrap the calling of all callbacks to handle |
|||
* calling either the old or the new style callbacks depending on which one |
|||
* has been registered. |
|||
* For old callbacks which return an empty handle, the ReturnValue is checked |
|||
* and used if it's been set to anything inside the callback. |
|||
* New style callbacks always use the return value. |
|||
*/ |
|||
Handle<JSObject> Call(IndexedPropertyEnumeratorCallback f); |
|||
|
|||
#define FOR_EACH_CALLBACK_TABLE_MAPPING_1_NAME(F) \ |
|||
F(AccessorNameGetterCallback, "get", v8::Value, Object) \ |
|||
F(GenericNamedPropertyQueryCallback, "has", v8::Integer, Object) \ |
|||
F(GenericNamedPropertyDeleterCallback, "delete", v8::Boolean, Object) |
|||
|
|||
#define WRITE_CALL_1_NAME(Function, type, ApiReturn, InternalReturn) \ |
|||
Handle<InternalReturn> Call(Function f, Handle<Name> name) { \ |
|||
Isolate* isolate = this->isolate(); \ |
|||
VMState<EXTERNAL> state(isolate); \ |
|||
ExternalCallbackScope call_scope(isolate, FUNCTION_ADDR(f)); \ |
|||
PropertyCallbackInfo<ApiReturn> info(begin()); \ |
|||
LOG(isolate, \ |
|||
ApiNamedPropertyAccess("interceptor-named-" type, holder(), *name)); \ |
|||
f(v8::Utils::ToLocal(name), info); \ |
|||
return GetReturnValue<InternalReturn>(isolate); \ |
|||
} |
|||
|
|||
FOR_EACH_CALLBACK_TABLE_MAPPING_1_NAME(WRITE_CALL_1_NAME) |
|||
|
|||
#undef FOR_EACH_CALLBACK_TABLE_MAPPING_1_NAME |
|||
#undef WRITE_CALL_1_NAME |
|||
|
|||
#define FOR_EACH_CALLBACK_TABLE_MAPPING_1_INDEX(F) \ |
|||
F(IndexedPropertyGetterCallback, "get", v8::Value, Object) \ |
|||
F(IndexedPropertyQueryCallback, "has", v8::Integer, Object) \ |
|||
F(IndexedPropertyDeleterCallback, "delete", v8::Boolean, Object) |
|||
|
|||
#define WRITE_CALL_1_INDEX(Function, type, ApiReturn, InternalReturn) \ |
|||
Handle<InternalReturn> Call(Function f, uint32_t index) { \ |
|||
Isolate* isolate = this->isolate(); \ |
|||
VMState<EXTERNAL> state(isolate); \ |
|||
ExternalCallbackScope call_scope(isolate, FUNCTION_ADDR(f)); \ |
|||
PropertyCallbackInfo<ApiReturn> info(begin()); \ |
|||
LOG(isolate, ApiIndexedPropertyAccess("interceptor-indexed-" type, \ |
|||
holder(), index)); \ |
|||
f(index, info); \ |
|||
return GetReturnValue<InternalReturn>(isolate); \ |
|||
} |
|||
|
|||
FOR_EACH_CALLBACK_TABLE_MAPPING_1_INDEX(WRITE_CALL_1_INDEX) |
|||
|
|||
#undef FOR_EACH_CALLBACK_TABLE_MAPPING_1_INDEX |
|||
#undef WRITE_CALL_1_INDEX |
|||
|
|||
Handle<Object> Call(GenericNamedPropertySetterCallback f, Handle<Name> name, |
|||
Handle<Object> value) { |
|||
Isolate* isolate = this->isolate(); |
|||
VMState<EXTERNAL> state(isolate); |
|||
ExternalCallbackScope call_scope(isolate, FUNCTION_ADDR(f)); |
|||
PropertyCallbackInfo<v8::Value> info(begin()); |
|||
LOG(isolate, |
|||
ApiNamedPropertyAccess("interceptor-named-set", holder(), *name)); |
|||
f(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), info); |
|||
return GetReturnValue<Object>(isolate); |
|||
} |
|||
|
|||
Handle<Object> Call(IndexedPropertySetterCallback f, uint32_t index, |
|||
Handle<Object> value) { |
|||
Isolate* isolate = this->isolate(); |
|||
VMState<EXTERNAL> state(isolate); |
|||
ExternalCallbackScope call_scope(isolate, FUNCTION_ADDR(f)); |
|||
PropertyCallbackInfo<v8::Value> info(begin()); |
|||
LOG(isolate, |
|||
ApiIndexedPropertyAccess("interceptor-indexed-set", holder(), index)); |
|||
f(index, v8::Utils::ToLocal(value), info); |
|||
return GetReturnValue<Object>(isolate); |
|||
} |
|||
|
|||
void Call(AccessorNameSetterCallback f, Handle<Name> name, |
|||
Handle<Object> value) { |
|||
Isolate* isolate = this->isolate(); |
|||
VMState<EXTERNAL> state(isolate); |
|||
ExternalCallbackScope call_scope(isolate, FUNCTION_ADDR(f)); |
|||
PropertyCallbackInfo<void> info(begin()); |
|||
LOG(isolate, |
|||
ApiNamedPropertyAccess("interceptor-named-set", holder(), *name)); |
|||
f(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), info); |
|||
} |
|||
|
|||
private: |
|||
inline JSObject* holder() { |
|||
return JSObject::cast(this->begin()[T::kHolderIndex]); |
|||
} |
|||
}; |
|||
|
|||
class FunctionCallbackArguments |
|||
: public CustomArguments<FunctionCallbackInfo<Value> > { |
|||
public: |
|||
typedef FunctionCallbackInfo<Value> T; |
|||
typedef CustomArguments<T> Super; |
|||
static const int kArgsLength = T::kArgsLength; |
|||
static const int kHolderIndex = T::kHolderIndex; |
|||
static const int kDataIndex = T::kDataIndex; |
|||
static const int kReturnValueDefaultValueIndex = |
|||
T::kReturnValueDefaultValueIndex; |
|||
static const int kIsolateIndex = T::kIsolateIndex; |
|||
static const int kCalleeIndex = T::kCalleeIndex; |
|||
static const int kContextSaveIndex = T::kContextSaveIndex; |
|||
|
|||
FunctionCallbackArguments(internal::Isolate* isolate, internal::Object* data, |
|||
internal::HeapObject* callee, |
|||
internal::Object* holder, internal::Object** argv, |
|||
int argc, bool is_construct_call) |
|||
: Super(isolate), |
|||
argv_(argv), |
|||
argc_(argc), |
|||
is_construct_call_(is_construct_call) { |
|||
Object** values = begin(); |
|||
values[T::kDataIndex] = data; |
|||
values[T::kCalleeIndex] = callee; |
|||
values[T::kHolderIndex] = holder; |
|||
values[T::kContextSaveIndex] = isolate->heap()->the_hole_value(); |
|||
values[T::kIsolateIndex] = reinterpret_cast<internal::Object*>(isolate); |
|||
// Here the hole is set as default value.
|
|||
// It cannot escape into js as it's remove in Call below.
|
|||
values[T::kReturnValueDefaultValueIndex] = |
|||
isolate->heap()->the_hole_value(); |
|||
values[T::kReturnValueIndex] = isolate->heap()->the_hole_value(); |
|||
DCHECK(values[T::kCalleeIndex]->IsJSFunction() || |
|||
values[T::kCalleeIndex]->IsFunctionTemplateInfo()); |
|||
DCHECK(values[T::kHolderIndex]->IsHeapObject()); |
|||
DCHECK(values[T::kIsolateIndex]->IsSmi()); |
|||
} |
|||
|
|||
/*
|
|||
* The following Call function wraps the calling of all callbacks to handle |
|||
* calling either the old or the new style callbacks depending on which one |
|||
* has been registered. |
|||
* For old callbacks which return an empty handle, the ReturnValue is checked |
|||
* and used if it's been set to anything inside the callback. |
|||
* New style callbacks always use the return value. |
|||
*/ |
|||
Handle<Object> Call(FunctionCallback f); |
|||
|
|||
private: |
|||
internal::Object** argv_; |
|||
int argc_; |
|||
bool is_construct_call_; |
|||
}; |
|||
|
|||
} // namespace internal
|
|||
} // namespace v8
|
|||
|
|||
#endif // V8_API_ARGUMENTS_H_
|
@ -0,0 +1,33 @@ |
|||
// Copyright 2016 the V8 project authors. All rights reserved.
|
|||
// Use of this source code is governed by a BSD-style license that can be
|
|||
// found in the LICENSE file.
|
|||
|
|||
#include "src/base/accounting-allocator.h" |
|||
|
|||
#include <cstdlib> |
|||
|
|||
#if V8_LIBC_BIONIC |
|||
#include <malloc.h> // NOLINT |
|||
#endif |
|||
|
|||
namespace v8 { |
|||
namespace base { |
|||
|
|||
void* AccountingAllocator::Allocate(size_t bytes) { |
|||
void* memory = malloc(bytes); |
|||
if (memory) NoBarrier_AtomicIncrement(¤t_memory_usage_, bytes); |
|||
return memory; |
|||
} |
|||
|
|||
void AccountingAllocator::Free(void* memory, size_t bytes) { |
|||
free(memory); |
|||
NoBarrier_AtomicIncrement(¤t_memory_usage_, |
|||
-static_cast<AtomicWord>(bytes)); |
|||
} |
|||
|
|||
size_t AccountingAllocator::GetCurrentMemoryUsage() const { |
|||
return NoBarrier_Load(¤t_memory_usage_); |
|||
} |
|||
|
|||
} // namespace base
|
|||
} // namespace v8
|
@ -0,0 +1,34 @@ |
|||
// Copyright 2016 the V8 project authors. All rights reserved.
|
|||
// Use of this source code is governed by a BSD-style license that can be
|
|||
// found in the LICENSE file.
|
|||
|
|||
#ifndef V8_BASE_ACCOUNTING_ALLOCATOR_H_ |
|||
#define V8_BASE_ACCOUNTING_ALLOCATOR_H_ |
|||
|
|||
#include "src/base/atomicops.h" |
|||
#include "src/base/macros.h" |
|||
|
|||
namespace v8 { |
|||
namespace base { |
|||
|
|||
class AccountingAllocator final { |
|||
public: |
|||
AccountingAllocator() = default; |
|||
~AccountingAllocator() = default; |
|||
|
|||
// Returns nullptr on failed allocation.
|
|||
void* Allocate(size_t bytes); |
|||
void Free(void* memory, size_t bytes); |
|||
|
|||
size_t GetCurrentMemoryUsage() const; |
|||
|
|||
private: |
|||
AtomicWord current_memory_usage_ = 0; |
|||
|
|||
DISALLOW_COPY_AND_ASSIGN(AccountingAllocator); |
|||
}; |
|||
|
|||
} // namespace base
|
|||
} // namespace v8
|
|||
|
|||
#endif // V8_BASE_ACCOUNTING_ALLOCATOR_H_
|
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -0,0 +1,247 @@ |
|||
// Copyright 2016 the V8 project authors. All rights reserved.
|
|||
// Use of this source code is governed by a BSD-style license that can be
|
|||
// found in the LICENSE file.
|
|||
|
|||
#ifndef V8_COLLECTOR_H_ |
|||
#define V8_COLLECTOR_H_ |
|||
|
|||
#include "src/checks.h" |
|||
#include "src/list.h" |
|||
#include "src/vector.h" |
|||
|
|||
namespace v8 { |
|||
namespace internal { |
|||
|
|||
/*
|
|||
* A class that collects values into a backing store. |
|||
* Specialized versions of the class can allow access to the backing store |
|||
* in different ways. |
|||
* There is no guarantee that the backing store is contiguous (and, as a |
|||
* consequence, no guarantees that consecutively added elements are adjacent |
|||
* in memory). The collector may move elements unless it has guaranteed not |
|||
* to. |
|||
*/ |
|||
template <typename T, int growth_factor = 2, int max_growth = 1 * MB> |
|||
class Collector { |
|||
public: |
|||
explicit Collector(int initial_capacity = kMinCapacity) |
|||
: index_(0), size_(0) { |
|||
current_chunk_ = Vector<T>::New(initial_capacity); |
|||
} |
|||
|
|||
virtual ~Collector() { |
|||
// Free backing store (in reverse allocation order).
|
|||
current_chunk_.Dispose(); |
|||
for (int i = chunks_.length() - 1; i >= 0; i--) { |
|||
chunks_.at(i).Dispose(); |
|||
} |
|||
} |
|||
|
|||
// Add a single element.
|
|||
inline void Add(T value) { |
|||
if (index_ >= current_chunk_.length()) { |
|||
Grow(1); |
|||
} |
|||
current_chunk_[index_] = value; |
|||
index_++; |
|||
size_++; |
|||
} |
|||
|
|||
// Add a block of contiguous elements and return a Vector backed by the
|
|||
// memory area.
|
|||
// A basic Collector will keep this vector valid as long as the Collector
|
|||
// is alive.
|
|||
inline Vector<T> AddBlock(int size, T initial_value) { |
|||
DCHECK(size > 0); |
|||
if (size > current_chunk_.length() - index_) { |
|||
Grow(size); |
|||
} |
|||
T* position = current_chunk_.start() + index_; |
|||
index_ += size; |
|||
size_ += size; |
|||
for (int i = 0; i < size; i++) { |
|||
position[i] = initial_value; |
|||
} |
|||
return Vector<T>(position, size); |
|||
} |
|||
|
|||
// Add a contiguous block of elements and return a vector backed
|
|||
// by the added block.
|
|||
// A basic Collector will keep this vector valid as long as the Collector
|
|||
// is alive.
|
|||
inline Vector<T> AddBlock(Vector<const T> source) { |
|||
if (source.length() > current_chunk_.length() - index_) { |
|||
Grow(source.length()); |
|||
} |
|||
T* position = current_chunk_.start() + index_; |
|||
index_ += source.length(); |
|||
size_ += source.length(); |
|||
for (int i = 0; i < source.length(); i++) { |
|||
position[i] = source[i]; |
|||
} |
|||
return Vector<T>(position, source.length()); |
|||
} |
|||
|
|||
// Write the contents of the collector into the provided vector.
|
|||
void WriteTo(Vector<T> destination) { |
|||
DCHECK(size_ <= destination.length()); |
|||
int position = 0; |
|||
for (int i = 0; i < chunks_.length(); i++) { |
|||
Vector<T> chunk = chunks_.at(i); |
|||
for (int j = 0; j < chunk.length(); j++) { |
|||
destination[position] = chunk[j]; |
|||
position++; |
|||
} |
|||
} |
|||
for (int i = 0; i < index_; i++) { |
|||
destination[position] = current_chunk_[i]; |
|||
position++; |
|||
} |
|||
} |
|||
|
|||
// Allocate a single contiguous vector, copy all the collected
|
|||
// elements to the vector, and return it.
|
|||
// The caller is responsible for freeing the memory of the returned
|
|||
// vector (e.g., using Vector::Dispose).
|
|||
Vector<T> ToVector() { |
|||
Vector<T> new_store = Vector<T>::New(size_); |
|||
WriteTo(new_store); |
|||
return new_store; |
|||
} |
|||
|
|||
// Resets the collector to be empty.
|
|||
virtual void Reset() { |
|||
for (int i = chunks_.length() - 1; i >= 0; i--) { |
|||
chunks_.at(i).Dispose(); |
|||
} |
|||
chunks_.Rewind(0); |
|||
index_ = 0; |
|||
size_ = 0; |
|||
} |
|||
|
|||
// Total number of elements added to collector so far.
|
|||
inline int size() { return size_; } |
|||
|
|||
protected: |
|||
static const int kMinCapacity = 16; |
|||
List<Vector<T> > chunks_; |
|||
Vector<T> current_chunk_; // Block of memory currently being written into.
|
|||
int index_; // Current index in current chunk.
|
|||
int size_; // Total number of elements in collector.
|
|||
|
|||
// Creates a new current chunk, and stores the old chunk in the chunks_ list.
|
|||
void Grow(int min_capacity) { |
|||
DCHECK(growth_factor > 1); |
|||
int new_capacity; |
|||
int current_length = current_chunk_.length(); |
|||
if (current_length < kMinCapacity) { |
|||
// The collector started out as empty.
|
|||
new_capacity = min_capacity * growth_factor; |
|||
if (new_capacity < kMinCapacity) new_capacity = kMinCapacity; |
|||
} else { |
|||
int growth = current_length * (growth_factor - 1); |
|||
if (growth > max_growth) { |
|||
growth = max_growth; |
|||
} |
|||
new_capacity = current_length + growth; |
|||
if (new_capacity < min_capacity) { |
|||
new_capacity = min_capacity + growth; |
|||
} |
|||
} |
|||
NewChunk(new_capacity); |
|||
DCHECK(index_ + min_capacity <= current_chunk_.length()); |
|||
} |
|||
|
|||
// Before replacing the current chunk, give a subclass the option to move
|
|||
// some of the current data into the new chunk. The function may update
|
|||
// the current index_ value to represent data no longer in the current chunk.
|
|||
// Returns the initial index of the new chunk (after copied data).
|
|||
virtual void NewChunk(int new_capacity) { |
|||
Vector<T> new_chunk = Vector<T>::New(new_capacity); |
|||
if (index_ > 0) { |
|||
chunks_.Add(current_chunk_.SubVector(0, index_)); |
|||
} else { |
|||
current_chunk_.Dispose(); |
|||
} |
|||
current_chunk_ = new_chunk; |
|||
index_ = 0; |
|||
} |
|||
}; |
|||
|
|||
/*
|
|||
* A collector that allows sequences of values to be guaranteed to |
|||
* stay consecutive. |
|||
* If the backing store grows while a sequence is active, the current |
|||
* sequence might be moved, but after the sequence is ended, it will |
|||
* not move again. |
|||
* NOTICE: Blocks allocated using Collector::AddBlock(int) can move |
|||
* as well, if inside an active sequence where another element is added. |
|||
*/ |
|||
template <typename T, int growth_factor = 2, int max_growth = 1 * MB> |
|||
class SequenceCollector : public Collector<T, growth_factor, max_growth> { |
|||
public: |
|||
explicit SequenceCollector(int initial_capacity) |
|||
: Collector<T, growth_factor, max_growth>(initial_capacity), |
|||
sequence_start_(kNoSequence) {} |
|||
|
|||
virtual ~SequenceCollector() {} |
|||
|
|||
void StartSequence() { |
|||
DCHECK(sequence_start_ == kNoSequence); |
|||
sequence_start_ = this->index_; |
|||
} |
|||
|
|||
Vector<T> EndSequence() { |
|||
DCHECK(sequence_start_ != kNoSequence); |
|||
int sequence_start = sequence_start_; |
|||
sequence_start_ = kNoSequence; |
|||
if (sequence_start == this->index_) return Vector<T>(); |
|||
return this->current_chunk_.SubVector(sequence_start, this->index_); |
|||
} |
|||
|
|||
// Drops the currently added sequence, and all collected elements in it.
|
|||
void DropSequence() { |
|||
DCHECK(sequence_start_ != kNoSequence); |
|||
int sequence_length = this->index_ - sequence_start_; |
|||
this->index_ = sequence_start_; |
|||
this->size_ -= sequence_length; |
|||
sequence_start_ = kNoSequence; |
|||
} |
|||
|
|||
virtual void Reset() { |
|||
sequence_start_ = kNoSequence; |
|||
this->Collector<T, growth_factor, max_growth>::Reset(); |
|||
} |
|||
|
|||
private: |
|||
static const int kNoSequence = -1; |
|||
int sequence_start_; |
|||
|
|||
// Move the currently active sequence to the new chunk.
|
|||
virtual void NewChunk(int new_capacity) { |
|||
if (sequence_start_ == kNoSequence) { |
|||
// Fall back on default behavior if no sequence has been started.
|
|||
this->Collector<T, growth_factor, max_growth>::NewChunk(new_capacity); |
|||
return; |
|||
} |
|||
int sequence_length = this->index_ - sequence_start_; |
|||
Vector<T> new_chunk = Vector<T>::New(sequence_length + new_capacity); |
|||
DCHECK(sequence_length < new_chunk.length()); |
|||
for (int i = 0; i < sequence_length; i++) { |
|||
new_chunk[i] = this->current_chunk_[sequence_start_ + i]; |
|||
} |
|||
if (sequence_start_ > 0) { |
|||
this->chunks_.Add(this->current_chunk_.SubVector(0, sequence_start_)); |
|||
} else { |
|||
this->current_chunk_.Dispose(); |
|||
} |
|||
this->current_chunk_ = new_chunk; |
|||
this->index_ = sequence_length; |
|||
sequence_start_ = 0; |
|||
} |
|||
}; |
|||
|
|||
} // namespace internal
|
|||
} // namespace v8
|
|||
|
|||
#endif // V8_COLLECTOR_H_
|
File diff suppressed because it is too large
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue