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