Minimize malloc heap allocation on process startup.
R=vegorov@chromium.org BUG=http://b/issue?id=5095592 Review URL: http://codereview.chromium.org/7572018 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8833 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
d63014d62e
commit
1dcb6e33cd
@ -84,7 +84,7 @@ namespace v8 {
|
||||
if (has_pending_exception) { \
|
||||
if (handle_scope_implementer->CallDepthIsZero() && \
|
||||
(isolate)->is_out_of_memory()) { \
|
||||
if (!handle_scope_implementer->ignore_out_of_memory()) \
|
||||
if (!(isolate)->ignore_out_of_memory()) \
|
||||
i::V8::FatalProcessOutOfMemory(NULL); \
|
||||
} \
|
||||
bool call_depth_is_zero = handle_scope_implementer->CallDepthIsZero(); \
|
||||
@ -4259,8 +4259,8 @@ static void* ExternalValueImpl(i::Handle<i::Object> obj) {
|
||||
Local<Value> v8::External::Wrap(void* data) {
|
||||
i::Isolate* isolate = i::Isolate::Current();
|
||||
STATIC_ASSERT(sizeof(data) == sizeof(i::Address));
|
||||
LOG_API(isolate, "External::Wrap");
|
||||
EnsureInitializedForIsolate(isolate, "v8::External::Wrap()");
|
||||
LOG_API(isolate, "External::Wrap");
|
||||
ENTER_V8(isolate);
|
||||
|
||||
v8::Local<v8::Value> result = CanBeEncodedAsSmi(data)
|
||||
@ -4304,8 +4304,8 @@ void* v8::External::FullUnwrap(v8::Handle<v8::Value> wrapper) {
|
||||
Local<External> v8::External::New(void* data) {
|
||||
STATIC_ASSERT(sizeof(data) == sizeof(i::Address));
|
||||
i::Isolate* isolate = i::Isolate::Current();
|
||||
LOG_API(isolate, "External::New");
|
||||
EnsureInitializedForIsolate(isolate, "v8::External::New()");
|
||||
LOG_API(isolate, "External::New");
|
||||
ENTER_V8(isolate);
|
||||
return ExternalNewImpl(data);
|
||||
}
|
||||
@ -4797,8 +4797,7 @@ Local<Integer> Integer::NewFromUnsigned(uint32_t value) {
|
||||
|
||||
|
||||
void V8::IgnoreOutOfMemoryException() {
|
||||
EnterIsolateIfNeeded()->handle_scope_implementer()->set_ignore_out_of_memory(
|
||||
true);
|
||||
EnterIsolateIfNeeded()->set_ignore_out_of_memory(true);
|
||||
}
|
||||
|
||||
|
||||
|
@ -404,7 +404,6 @@ class HandleScopeImplementer {
|
||||
entered_contexts_(0),
|
||||
saved_contexts_(0),
|
||||
spare_(NULL),
|
||||
ignore_out_of_memory_(false),
|
||||
call_depth_(0) { }
|
||||
|
||||
// Threading support for handle data.
|
||||
@ -437,10 +436,6 @@ class HandleScopeImplementer {
|
||||
inline bool HasSavedContexts();
|
||||
|
||||
inline List<internal::Object**>* blocks() { return &blocks_; }
|
||||
inline bool ignore_out_of_memory() { return ignore_out_of_memory_; }
|
||||
inline void set_ignore_out_of_memory(bool value) {
|
||||
ignore_out_of_memory_ = value;
|
||||
}
|
||||
|
||||
private:
|
||||
void ResetAfterArchive() {
|
||||
@ -448,7 +443,6 @@ class HandleScopeImplementer {
|
||||
entered_contexts_.Initialize(0);
|
||||
saved_contexts_.Initialize(0);
|
||||
spare_ = NULL;
|
||||
ignore_out_of_memory_ = false;
|
||||
call_depth_ = 0;
|
||||
}
|
||||
|
||||
@ -473,7 +467,6 @@ class HandleScopeImplementer {
|
||||
// Used as a stack to keep track of saved contexts.
|
||||
List<Context*> saved_contexts_;
|
||||
Object** spare_;
|
||||
bool ignore_out_of_memory_;
|
||||
int call_depth_;
|
||||
// This is only used for threading support.
|
||||
v8::ImplementationUtilities::HandleScopeData handle_scope_data_;
|
||||
|
@ -1965,7 +1965,7 @@ void Debug::AfterGarbageCollection() {
|
||||
|
||||
|
||||
Debugger::Debugger(Isolate* isolate)
|
||||
: debugger_access_(OS::CreateMutex()),
|
||||
: debugger_access_(isolate->debugger_access()),
|
||||
event_listener_(Handle<Object>()),
|
||||
event_listener_data_(Handle<Object>()),
|
||||
compiling_natives_(false),
|
||||
@ -1987,8 +1987,6 @@ Debugger::Debugger(Isolate* isolate)
|
||||
|
||||
|
||||
Debugger::~Debugger() {
|
||||
delete debugger_access_;
|
||||
debugger_access_ = 0;
|
||||
delete dispatch_handler_access_;
|
||||
dispatch_handler_access_ = 0;
|
||||
delete command_received_;
|
||||
|
@ -132,7 +132,7 @@ static Handle<Object> Invoke(bool construct,
|
||||
if (*has_pending_exception) {
|
||||
isolate->ReportPendingMessages();
|
||||
if (isolate->pending_exception() == Failure::OutOfMemoryException()) {
|
||||
if (!isolate->handle_scope_implementer()->ignore_out_of_memory()) {
|
||||
if (!isolate->ignore_out_of_memory()) {
|
||||
V8::FatalProcessOutOfMemory("JS", true);
|
||||
}
|
||||
}
|
||||
|
145
src/isolate.cc
145
src/isolate.cc
@ -76,6 +76,10 @@ int ThreadId::GetCurrentThreadId() {
|
||||
|
||||
ThreadLocalTop::ThreadLocalTop() {
|
||||
InitializeInternal();
|
||||
// This flag may be set using v8::V8::IgnoreOutOfMemoryException()
|
||||
// before an isolate is initialized. The initialize methods below do
|
||||
// not touch it to preserve its value.
|
||||
ignore_out_of_memory_ = false;
|
||||
}
|
||||
|
||||
|
||||
@ -382,7 +386,6 @@ void Isolate::EnsureDefaultIsolate() {
|
||||
if (Thread::GetThreadLocal(isolate_key_) == NULL) {
|
||||
Thread::SetThreadLocal(isolate_key_, default_isolate_);
|
||||
}
|
||||
CHECK(default_isolate_->PreInit());
|
||||
}
|
||||
|
||||
|
||||
@ -654,6 +657,7 @@ void Isolate::PrintStack() {
|
||||
incomplete_message_ = &accumulator;
|
||||
PrintStack(&accumulator);
|
||||
accumulator.OutputToStdOut();
|
||||
InitializeLoggingAndCounters();
|
||||
accumulator.Log();
|
||||
incomplete_message_ = NULL;
|
||||
stack_trace_nesting_level_ = 0;
|
||||
@ -1375,11 +1379,15 @@ Isolate::Isolate()
|
||||
bootstrapper_(NULL),
|
||||
runtime_profiler_(NULL),
|
||||
compilation_cache_(NULL),
|
||||
counters_(new Counters()),
|
||||
counters_(NULL),
|
||||
code_range_(NULL),
|
||||
// Must be initialized early to allow v8::SetResourceConstraints calls.
|
||||
break_access_(OS::CreateMutex()),
|
||||
logger_(new Logger()),
|
||||
stats_table_(new StatsTable()),
|
||||
debugger_initialized_(false),
|
||||
// Must be initialized early to allow v8::Debug calls.
|
||||
debugger_access_(OS::CreateMutex()),
|
||||
logger_(NULL),
|
||||
stats_table_(NULL),
|
||||
stub_cache_(NULL),
|
||||
deoptimizer_data_(NULL),
|
||||
capture_stack_trace_for_uncaught_exceptions_(false),
|
||||
@ -1510,7 +1518,7 @@ void Isolate::Deinit() {
|
||||
logger_->TearDown();
|
||||
|
||||
// The default isolate is re-initializable due to legacy API.
|
||||
state_ = PREINITIALIZED;
|
||||
state_ = UNINITIALIZED;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1592,58 +1600,6 @@ Isolate::~Isolate() {
|
||||
}
|
||||
|
||||
|
||||
bool Isolate::PreInit() {
|
||||
if (state_ != UNINITIALIZED) return true;
|
||||
|
||||
TRACE_ISOLATE(preinit);
|
||||
|
||||
ASSERT(Isolate::Current() == this);
|
||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||
debug_ = new Debug(this);
|
||||
debugger_ = new Debugger(this);
|
||||
#endif
|
||||
|
||||
memory_allocator_ = new MemoryAllocator();
|
||||
memory_allocator_->isolate_ = this;
|
||||
code_range_ = new CodeRange();
|
||||
code_range_->isolate_ = this;
|
||||
|
||||
// Safe after setting Heap::isolate_, initializing StackGuard and
|
||||
// ensuring that Isolate::Current() == this.
|
||||
heap_.SetStackLimits();
|
||||
|
||||
#ifdef DEBUG
|
||||
DisallowAllocationFailure disallow_allocation_failure;
|
||||
#endif
|
||||
|
||||
#define C(name) isolate_addresses_[Isolate::k_##name] = \
|
||||
reinterpret_cast<Address>(name());
|
||||
ISOLATE_ADDRESS_LIST(C)
|
||||
#undef C
|
||||
|
||||
string_tracker_ = new StringTracker();
|
||||
string_tracker_->isolate_ = this;
|
||||
compilation_cache_ = new CompilationCache(this);
|
||||
transcendental_cache_ = new TranscendentalCache();
|
||||
keyed_lookup_cache_ = new KeyedLookupCache();
|
||||
context_slot_cache_ = new ContextSlotCache();
|
||||
descriptor_lookup_cache_ = new DescriptorLookupCache();
|
||||
unicode_cache_ = new UnicodeCache();
|
||||
pc_to_code_cache_ = new PcToCodeCache(this);
|
||||
write_input_buffer_ = new StringInputBuffer();
|
||||
global_handles_ = new GlobalHandles(this);
|
||||
bootstrapper_ = new Bootstrapper();
|
||||
handle_scope_implementer_ = new HandleScopeImplementer(this);
|
||||
stub_cache_ = new StubCache(this);
|
||||
ast_sentinels_ = new AstSentinels();
|
||||
regexp_stack_ = new RegExpStack();
|
||||
regexp_stack_->isolate_ = this;
|
||||
|
||||
state_ = PREINITIALIZED;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Isolate::InitializeThreadLocal() {
|
||||
thread_local_top_.isolate_ = this;
|
||||
thread_local_top_.Initialize();
|
||||
@ -1680,19 +1636,71 @@ void Isolate::PropagatePendingExceptionToExternalTryCatch() {
|
||||
}
|
||||
|
||||
|
||||
void Isolate::InitializeLoggingAndCounters() {
|
||||
if (logger_ == NULL) {
|
||||
logger_ = new Logger;
|
||||
}
|
||||
if (counters_ == NULL) {
|
||||
counters_ = new Counters;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Isolate::InitializeDebugger() {
|
||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||
ScopedLock lock(debugger_access_);
|
||||
if (NoBarrier_Load(&debugger_initialized_)) return;
|
||||
InitializeLoggingAndCounters();
|
||||
debug_ = new Debug(this);
|
||||
debugger_ = new Debugger(this);
|
||||
Release_Store(&debugger_initialized_, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool Isolate::Init(Deserializer* des) {
|
||||
ASSERT(state_ != INITIALIZED);
|
||||
|
||||
ASSERT(Isolate::Current() == this);
|
||||
TRACE_ISOLATE(init);
|
||||
|
||||
bool create_heap_objects = des == NULL;
|
||||
|
||||
#ifdef DEBUG
|
||||
// The initialization process does not handle memory exhaustion.
|
||||
DisallowAllocationFailure disallow_allocation_failure;
|
||||
#endif
|
||||
|
||||
if (state_ == UNINITIALIZED && !PreInit()) return false;
|
||||
InitializeLoggingAndCounters();
|
||||
|
||||
InitializeDebugger();
|
||||
|
||||
memory_allocator_ = new MemoryAllocator(this);
|
||||
code_range_ = new CodeRange(this);
|
||||
|
||||
// Safe after setting Heap::isolate_, initializing StackGuard and
|
||||
// ensuring that Isolate::Current() == this.
|
||||
heap_.SetStackLimits();
|
||||
|
||||
#define C(name) isolate_addresses_[Isolate::k_##name] = \
|
||||
reinterpret_cast<Address>(name());
|
||||
ISOLATE_ADDRESS_LIST(C)
|
||||
#undef C
|
||||
|
||||
string_tracker_ = new StringTracker();
|
||||
string_tracker_->isolate_ = this;
|
||||
compilation_cache_ = new CompilationCache(this);
|
||||
transcendental_cache_ = new TranscendentalCache();
|
||||
keyed_lookup_cache_ = new KeyedLookupCache();
|
||||
context_slot_cache_ = new ContextSlotCache();
|
||||
descriptor_lookup_cache_ = new DescriptorLookupCache();
|
||||
unicode_cache_ = new UnicodeCache();
|
||||
pc_to_code_cache_ = new PcToCodeCache(this);
|
||||
write_input_buffer_ = new StringInputBuffer();
|
||||
global_handles_ = new GlobalHandles(this);
|
||||
bootstrapper_ = new Bootstrapper();
|
||||
handle_scope_implementer_ = new HandleScopeImplementer(this);
|
||||
stub_cache_ = new StubCache(this);
|
||||
ast_sentinels_ = new AstSentinels();
|
||||
regexp_stack_ = new RegExpStack();
|
||||
regexp_stack_->isolate_ = this;
|
||||
|
||||
// Enable logging before setting up the heap
|
||||
logger_->Setup();
|
||||
@ -1715,7 +1723,8 @@ bool Isolate::Init(Deserializer* des) {
|
||||
stack_guard_.InitThread(lock);
|
||||
}
|
||||
|
||||
// Setup the object heap
|
||||
// Setup the object heap.
|
||||
const bool create_heap_objects = (des == NULL);
|
||||
ASSERT(!heap_.HasBeenSetup());
|
||||
if (!heap_.Setup(create_heap_objects)) {
|
||||
V8::SetFatalError();
|
||||
@ -1775,6 +1784,16 @@ bool Isolate::Init(Deserializer* des) {
|
||||
}
|
||||
|
||||
|
||||
// Initialized lazily to allow early
|
||||
// v8::V8::SetAddHistogramSampleFunction calls.
|
||||
StatsTable* Isolate::stats_table() {
|
||||
if (stats_table_ == NULL) {
|
||||
stats_table_ = new StatsTable;
|
||||
}
|
||||
return stats_table_;
|
||||
}
|
||||
|
||||
|
||||
void Isolate::Enter() {
|
||||
Isolate* current_isolate = NULL;
|
||||
PerIsolateThreadData* current_data = CurrentPerIsolateThreadData();
|
||||
@ -1814,8 +1833,6 @@ void Isolate::Enter() {
|
||||
|
||||
SetIsolateThreadLocals(this, data);
|
||||
|
||||
CHECK(PreInit());
|
||||
|
||||
// In case it's the first time some thread enters the isolate.
|
||||
set_thread_id(data->thread_id());
|
||||
}
|
||||
|
@ -256,6 +256,9 @@ class ThreadLocalTop BASE_EMBEDDED {
|
||||
// Call back function to report unsafe JS accesses.
|
||||
v8::FailedAccessCheckCallback failed_access_check_callback_;
|
||||
|
||||
// Whether out of memory exceptions should be ignored.
|
||||
bool ignore_out_of_memory_;
|
||||
|
||||
private:
|
||||
void InitializeInternal();
|
||||
|
||||
@ -446,6 +449,13 @@ class Isolate {
|
||||
return reinterpret_cast<Isolate*>(Thread::GetThreadLocal(isolate_key_));
|
||||
}
|
||||
|
||||
// Usually called by Init(), but can be called early e.g. to allow
|
||||
// testing components that require logging but not the whole
|
||||
// isolate.
|
||||
//
|
||||
// Safe to call more than once.
|
||||
void InitializeLoggingAndCounters();
|
||||
|
||||
bool Init(Deserializer* des);
|
||||
|
||||
bool IsInitialized() { return state_ == INITIALIZED; }
|
||||
@ -498,10 +508,12 @@ class Isolate {
|
||||
// switched to non-legacy behavior).
|
||||
static void EnterDefaultIsolate();
|
||||
|
||||
// Debug.
|
||||
// Mutex for serializing access to break control structures.
|
||||
Mutex* break_access() { return break_access_; }
|
||||
|
||||
// Mutex for serializing access to debugger.
|
||||
Mutex* debugger_access() { return debugger_access_; }
|
||||
|
||||
Address get_address_from_id(AddressId id);
|
||||
|
||||
// Access to top context (where the current function object was created).
|
||||
@ -661,6 +673,12 @@ class Isolate {
|
||||
// Tells whether the current context has experienced an out of memory
|
||||
// exception.
|
||||
bool is_out_of_memory();
|
||||
bool ignore_out_of_memory() {
|
||||
return thread_local_top_.ignore_out_of_memory_;
|
||||
}
|
||||
void set_ignore_out_of_memory(bool value) {
|
||||
thread_local_top_.ignore_out_of_memory_ = value;
|
||||
}
|
||||
|
||||
void PrintCurrentStackTrace(FILE* out);
|
||||
void PrintStackTrace(FILE* out, char* thread_data);
|
||||
@ -769,14 +787,24 @@ class Isolate {
|
||||
#undef GLOBAL_CONTEXT_FIELD_ACCESSOR
|
||||
|
||||
Bootstrapper* bootstrapper() { return bootstrapper_; }
|
||||
Counters* counters() { return counters_; }
|
||||
Counters* counters() {
|
||||
// Call InitializeLoggingAndCounters() if logging is needed before
|
||||
// the isolate is fully initialized.
|
||||
ASSERT(counters_ != NULL);
|
||||
return counters_;
|
||||
}
|
||||
CodeRange* code_range() { return code_range_; }
|
||||
RuntimeProfiler* runtime_profiler() { return runtime_profiler_; }
|
||||
CompilationCache* compilation_cache() { return compilation_cache_; }
|
||||
Logger* logger() { return logger_; }
|
||||
Logger* logger() {
|
||||
// Call InitializeLoggingAndCounters() if logging is needed before
|
||||
// the isolate is fully initialized.
|
||||
ASSERT(logger_ != NULL);
|
||||
return logger_;
|
||||
}
|
||||
StackGuard* stack_guard() { return &stack_guard_; }
|
||||
Heap* heap() { return &heap_; }
|
||||
StatsTable* stats_table() { return stats_table_; }
|
||||
StatsTable* stats_table();
|
||||
StubCache* stub_cache() { return stub_cache_; }
|
||||
DeoptimizerData* deoptimizer_data() { return deoptimizer_data_; }
|
||||
ThreadLocalTop* thread_local_top() { return &thread_local_top_; }
|
||||
@ -877,8 +905,14 @@ class Isolate {
|
||||
void PreallocatedStorageInit(size_t size);
|
||||
|
||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||
Debugger* debugger() { return debugger_; }
|
||||
Debug* debug() { return debug_; }
|
||||
Debugger* debugger() {
|
||||
if (!NoBarrier_Load(&debugger_initialized_)) InitializeDebugger();
|
||||
return debugger_;
|
||||
}
|
||||
Debug* debug() {
|
||||
if (!NoBarrier_Load(&debugger_initialized_)) InitializeDebugger();
|
||||
return debug_;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline bool DebuggerHasBreakPoints();
|
||||
@ -1010,8 +1044,6 @@ class Isolate {
|
||||
static Isolate* default_isolate_;
|
||||
static ThreadDataTable* thread_data_table_;
|
||||
|
||||
bool PreInit();
|
||||
|
||||
void Deinit();
|
||||
|
||||
static void SetIsolateThreadLocals(Isolate* isolate,
|
||||
@ -1019,7 +1051,6 @@ class Isolate {
|
||||
|
||||
enum State {
|
||||
UNINITIALIZED, // Some components may not have been allocated.
|
||||
PREINITIALIZED, // Components have been allocated but not initialized.
|
||||
INITIALIZED // All components are fully initialized.
|
||||
};
|
||||
|
||||
@ -1063,6 +1094,8 @@ class Isolate {
|
||||
|
||||
void PropagatePendingExceptionToExternalTryCatch();
|
||||
|
||||
void InitializeDebugger();
|
||||
|
||||
int stack_trace_nesting_level_;
|
||||
StringStream* incomplete_message_;
|
||||
// The preallocated memory thread singleton.
|
||||
@ -1076,6 +1109,8 @@ class Isolate {
|
||||
Counters* counters_;
|
||||
CodeRange* code_range_;
|
||||
Mutex* break_access_;
|
||||
Atomic32 debugger_initialized_;
|
||||
Mutex* debugger_access_;
|
||||
Heap heap_;
|
||||
Logger* logger_;
|
||||
StackGuard stack_guard_;
|
||||
@ -1165,6 +1200,7 @@ class Isolate {
|
||||
friend class Simulator;
|
||||
friend class StackGuard;
|
||||
friend class ThreadId;
|
||||
friend class TestMemoryAllocatorScope;
|
||||
friend class v8::Isolate;
|
||||
friend class v8::Locker;
|
||||
friend class v8::Unlocker;
|
||||
|
@ -148,12 +148,12 @@ PageIterator::PageIterator(PagedSpace* space, Mode mode) : space_(space) {
|
||||
// CodeRange
|
||||
|
||||
|
||||
CodeRange::CodeRange()
|
||||
: code_range_(NULL),
|
||||
CodeRange::CodeRange(Isolate* isolate)
|
||||
: isolate_(isolate),
|
||||
code_range_(NULL),
|
||||
free_list_(0),
|
||||
allocation_list_(0),
|
||||
current_allocation_block_index_(0),
|
||||
isolate_(NULL) {
|
||||
current_allocation_block_index_(0) {
|
||||
}
|
||||
|
||||
|
||||
@ -279,8 +279,9 @@ void CodeRange::TearDown() {
|
||||
const int kEstimatedNumberOfChunks = 270;
|
||||
|
||||
|
||||
MemoryAllocator::MemoryAllocator()
|
||||
: capacity_(0),
|
||||
MemoryAllocator::MemoryAllocator(Isolate* isolate)
|
||||
: isolate_(isolate),
|
||||
capacity_(0),
|
||||
capacity_executable_(0),
|
||||
size_(0),
|
||||
size_executable_(0),
|
||||
@ -288,8 +289,7 @@ MemoryAllocator::MemoryAllocator()
|
||||
chunks_(kEstimatedNumberOfChunks),
|
||||
free_chunk_ids_(kEstimatedNumberOfChunks),
|
||||
max_nof_chunks_(0),
|
||||
top_(0),
|
||||
isolate_(NULL) {
|
||||
top_(0) {
|
||||
}
|
||||
|
||||
|
||||
|
22
src/spaces.h
22
src/spaces.h
@ -408,6 +408,8 @@ class Space : public Malloced {
|
||||
// manages a range of virtual memory.
|
||||
class CodeRange {
|
||||
public:
|
||||
explicit CodeRange(Isolate* isolate);
|
||||
|
||||
// Reserves a range of virtual memory, but does not commit any of it.
|
||||
// Can only be called once, at heap initialization time.
|
||||
// Returns false on failure.
|
||||
@ -417,9 +419,9 @@ class CodeRange {
|
||||
// manage it.
|
||||
void TearDown();
|
||||
|
||||
bool exists() { return code_range_ != NULL; }
|
||||
bool exists() { return this != NULL && code_range_ != NULL; }
|
||||
bool contains(Address address) {
|
||||
if (code_range_ == NULL) return false;
|
||||
if (this == NULL || code_range_ == NULL) return false;
|
||||
Address start = static_cast<Address>(code_range_->address());
|
||||
return start <= address && address < start + code_range_->size();
|
||||
}
|
||||
@ -432,7 +434,7 @@ class CodeRange {
|
||||
void FreeRawMemory(void* buf, size_t length);
|
||||
|
||||
private:
|
||||
CodeRange();
|
||||
Isolate* isolate_;
|
||||
|
||||
// The reserved range of virtual memory that all code objects are put in.
|
||||
VirtualMemory* code_range_;
|
||||
@ -466,10 +468,6 @@ class CodeRange {
|
||||
static int CompareFreeBlockAddress(const FreeBlock* left,
|
||||
const FreeBlock* right);
|
||||
|
||||
friend class Isolate;
|
||||
|
||||
Isolate* isolate_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CodeRange);
|
||||
};
|
||||
|
||||
@ -500,6 +498,8 @@ class CodeRange {
|
||||
|
||||
class MemoryAllocator {
|
||||
public:
|
||||
explicit MemoryAllocator(Isolate* isolate);
|
||||
|
||||
// Initializes its internal bookkeeping structures.
|
||||
// Max capacity of the total space and executable memory limit.
|
||||
bool Setup(intptr_t max_capacity, intptr_t capacity_executable);
|
||||
@ -657,10 +657,10 @@ class MemoryAllocator {
|
||||
#endif
|
||||
|
||||
private:
|
||||
MemoryAllocator();
|
||||
|
||||
static const int kChunkSize = kPagesPerChunk * Page::kPageSize;
|
||||
|
||||
Isolate* isolate_;
|
||||
|
||||
// Maximum space size in bytes.
|
||||
intptr_t capacity_;
|
||||
// Maximum subset of capacity_ that can be executable
|
||||
@ -753,10 +753,6 @@ class MemoryAllocator {
|
||||
Page* prev,
|
||||
Page** last_page_in_use);
|
||||
|
||||
friend class Isolate;
|
||||
|
||||
Isolate* isolate_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MemoryAllocator);
|
||||
};
|
||||
|
||||
|
@ -186,7 +186,9 @@ class Block {
|
||||
TEST(CodeRange) {
|
||||
const int code_range_size = 16*MB;
|
||||
OS::Setup();
|
||||
Isolate::Current()->code_range()->Setup(code_range_size);
|
||||
Isolate::Current()->InitializeLoggingAndCounters();
|
||||
CodeRange* code_range = new CodeRange(Isolate::Current());
|
||||
code_range->Setup(code_range_size);
|
||||
int current_allocated = 0;
|
||||
int total_allocated = 0;
|
||||
List<Block> blocks(1000);
|
||||
@ -198,8 +200,7 @@ TEST(CodeRange) {
|
||||
size_t requested = (Page::kPageSize << (Pseudorandom() % 6)) +
|
||||
Pseudorandom() % 5000 + 1;
|
||||
size_t allocated = 0;
|
||||
void* base = Isolate::Current()->code_range()->
|
||||
AllocateRawMemory(requested, &allocated);
|
||||
void* base = code_range->AllocateRawMemory(requested, &allocated);
|
||||
CHECK(base != NULL);
|
||||
blocks.Add(Block(base, static_cast<int>(allocated)));
|
||||
current_allocated += static_cast<int>(allocated);
|
||||
@ -207,8 +208,7 @@ TEST(CodeRange) {
|
||||
} else {
|
||||
// Free a block.
|
||||
int index = Pseudorandom() % blocks.length();
|
||||
Isolate::Current()->code_range()->FreeRawMemory(
|
||||
blocks[index].base, blocks[index].size);
|
||||
code_range->FreeRawMemory(blocks[index].base, blocks[index].size);
|
||||
current_allocated -= blocks[index].size;
|
||||
if (index < blocks.length() - 1) {
|
||||
blocks[index] = blocks.RemoveLast();
|
||||
@ -218,5 +218,6 @@ TEST(CodeRange) {
|
||||
}
|
||||
}
|
||||
|
||||
Isolate::Current()->code_range()->TearDown();
|
||||
code_range->TearDown();
|
||||
delete code_range;
|
||||
}
|
||||
|
@ -5844,6 +5844,7 @@ TEST(DebuggerDebugMessageDispatch) {
|
||||
|
||||
|
||||
TEST(DebuggerAgent) {
|
||||
v8::V8::Initialize();
|
||||
i::Debugger* debugger = i::Isolate::Current()->debugger();
|
||||
// Make sure these ports is not used by other tests to allow tests to run in
|
||||
// parallel.
|
||||
|
@ -291,8 +291,8 @@ TEST(LocalHandles) {
|
||||
|
||||
|
||||
TEST(GlobalHandles) {
|
||||
GlobalHandles* global_handles = Isolate::Current()->global_handles();
|
||||
InitializeVM();
|
||||
GlobalHandles* global_handles = Isolate::Current()->global_handles();
|
||||
|
||||
Handle<Object> h1;
|
||||
Handle<Object> h2;
|
||||
@ -339,8 +339,8 @@ static void TestWeakGlobalHandleCallback(v8::Persistent<v8::Value> handle,
|
||||
|
||||
|
||||
TEST(WeakGlobalHandlesScavenge) {
|
||||
GlobalHandles* global_handles = Isolate::Current()->global_handles();
|
||||
InitializeVM();
|
||||
GlobalHandles* global_handles = Isolate::Current()->global_handles();
|
||||
|
||||
WeakPointerCleared = false;
|
||||
|
||||
@ -377,8 +377,8 @@ TEST(WeakGlobalHandlesScavenge) {
|
||||
|
||||
|
||||
TEST(WeakGlobalHandlesMark) {
|
||||
GlobalHandles* global_handles = Isolate::Current()->global_handles();
|
||||
InitializeVM();
|
||||
GlobalHandles* global_handles = Isolate::Current()->global_handles();
|
||||
|
||||
WeakPointerCleared = false;
|
||||
|
||||
@ -416,8 +416,8 @@ TEST(WeakGlobalHandlesMark) {
|
||||
}
|
||||
|
||||
TEST(DeleteWeakGlobalHandle) {
|
||||
GlobalHandles* global_handles = Isolate::Current()->global_handles();
|
||||
InitializeVM();
|
||||
GlobalHandles* global_handles = Isolate::Current()->global_handles();
|
||||
|
||||
WeakPointerCleared = false;
|
||||
|
||||
|
@ -134,6 +134,8 @@ TEST(KeywordMatcher) {
|
||||
|
||||
|
||||
TEST(ScanHTMLEndComments) {
|
||||
v8::V8::Initialize();
|
||||
|
||||
// Regression test. See:
|
||||
// http://code.google.com/p/chromium/issues/detail?id=53548
|
||||
// Tests that --> is correctly interpreted as comment-to-end-of-line if there
|
||||
@ -263,6 +265,8 @@ TEST(Preparsing) {
|
||||
|
||||
|
||||
TEST(StandAlonePreParser) {
|
||||
v8::V8::Initialize();
|
||||
|
||||
int marker;
|
||||
i::Isolate::Current()->stack_guard()->SetStackLimit(
|
||||
reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
|
||||
@ -299,6 +303,8 @@ TEST(StandAlonePreParser) {
|
||||
|
||||
|
||||
TEST(RegressChromium62639) {
|
||||
v8::V8::Initialize();
|
||||
|
||||
int marker;
|
||||
i::Isolate::Current()->stack_guard()->SetStackLimit(
|
||||
reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
|
||||
@ -320,6 +326,8 @@ TEST(RegressChromium62639) {
|
||||
|
||||
|
||||
TEST(Regress928) {
|
||||
v8::V8::Initialize();
|
||||
|
||||
// Preparsing didn't consider the catch clause of a try statement
|
||||
// as with-content, which made it assume that a function inside
|
||||
// the block could be lazily compiled, and an extra, unexpected,
|
||||
@ -360,6 +368,8 @@ TEST(Regress928) {
|
||||
|
||||
|
||||
TEST(PreParseOverflow) {
|
||||
v8::V8::Initialize();
|
||||
|
||||
int marker;
|
||||
i::Isolate::Current()->stack_guard()->SetStackLimit(
|
||||
reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
|
||||
@ -610,6 +620,8 @@ void TestStreamScanner(i::UC16CharacterStream* stream,
|
||||
}
|
||||
|
||||
TEST(StreamScanner) {
|
||||
v8::V8::Initialize();
|
||||
|
||||
const char* str1 = "{ foo get for : */ <- \n\n /*foo*/ bib";
|
||||
i::Utf8ToUC16CharacterStream stream1(reinterpret_cast<const i::byte*>(str1),
|
||||
static_cast<unsigned>(strlen(str1)));
|
||||
@ -690,6 +702,8 @@ void TestScanRegExp(const char* re_source, const char* expected) {
|
||||
|
||||
|
||||
TEST(RegExpScanning) {
|
||||
v8::V8::Initialize();
|
||||
|
||||
// RegExp token with added garbage at the end. The scanner should only
|
||||
// scan the RegExp until the terminating slash just before "flipperwald".
|
||||
TestScanRegExp("/b/flipperwald", "b");
|
||||
|
@ -99,10 +99,10 @@ static int make_code(TypeCode type, int id) {
|
||||
|
||||
|
||||
TEST(ExternalReferenceEncoder) {
|
||||
OS::Setup();
|
||||
Isolate* isolate = i::Isolate::Current();
|
||||
isolate->stats_table()->SetCounterFunction(counter_function);
|
||||
HEAP->Setup(false);
|
||||
v8::V8::Initialize();
|
||||
|
||||
ExternalReferenceEncoder encoder;
|
||||
CHECK_EQ(make_code(BUILTIN, Builtins::kArrayCode),
|
||||
Encode(encoder, Builtins::kArrayCode));
|
||||
@ -139,10 +139,10 @@ TEST(ExternalReferenceEncoder) {
|
||||
|
||||
|
||||
TEST(ExternalReferenceDecoder) {
|
||||
OS::Setup();
|
||||
Isolate* isolate = i::Isolate::Current();
|
||||
isolate->stats_table()->SetCounterFunction(counter_function);
|
||||
HEAP->Setup(false);
|
||||
v8::V8::Initialize();
|
||||
|
||||
ExternalReferenceDecoder decoder;
|
||||
CHECK_EQ(AddressOf(Builtins::kArrayCode),
|
||||
decoder.Decode(make_code(BUILTIN, Builtins::kArrayCode)));
|
||||
|
@ -91,46 +91,74 @@ TEST(Page) {
|
||||
}
|
||||
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Temporarily sets a given allocator in an isolate.
|
||||
class TestMemoryAllocatorScope {
|
||||
public:
|
||||
TestMemoryAllocatorScope(Isolate* isolate, MemoryAllocator* allocator)
|
||||
: isolate_(isolate),
|
||||
old_allocator_(isolate->memory_allocator_) {
|
||||
isolate->memory_allocator_ = allocator;
|
||||
}
|
||||
|
||||
~TestMemoryAllocatorScope() {
|
||||
isolate_->memory_allocator_ = old_allocator_;
|
||||
}
|
||||
|
||||
private:
|
||||
Isolate* isolate_;
|
||||
MemoryAllocator* old_allocator_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(TestMemoryAllocatorScope);
|
||||
};
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
||||
|
||||
TEST(MemoryAllocator) {
|
||||
OS::Setup();
|
||||
Isolate* isolate = Isolate::Current();
|
||||
CHECK(HEAP->ConfigureHeapDefault());
|
||||
CHECK(isolate->memory_allocator()->Setup(HEAP->MaxReserved(),
|
||||
HEAP->MaxExecutableSize()));
|
||||
isolate->InitializeLoggingAndCounters();
|
||||
Heap* heap = isolate->heap();
|
||||
CHECK(heap->ConfigureHeapDefault());
|
||||
MemoryAllocator* memory_allocator = new MemoryAllocator(isolate);
|
||||
CHECK(memory_allocator->Setup(heap->MaxReserved(),
|
||||
heap->MaxExecutableSize()));
|
||||
TestMemoryAllocatorScope test_scope(isolate, memory_allocator);
|
||||
|
||||
OldSpace faked_space(HEAP,
|
||||
HEAP->MaxReserved(),
|
||||
OldSpace faked_space(heap,
|
||||
heap->MaxReserved(),
|
||||
OLD_POINTER_SPACE,
|
||||
NOT_EXECUTABLE);
|
||||
int total_pages = 0;
|
||||
int requested = MemoryAllocator::kPagesPerChunk;
|
||||
int allocated;
|
||||
// If we request n pages, we should get n or n - 1.
|
||||
Page* first_page =
|
||||
isolate->memory_allocator()->AllocatePages(
|
||||
requested, &allocated, &faked_space);
|
||||
Page* first_page = memory_allocator->AllocatePages(
|
||||
requested, &allocated, &faked_space);
|
||||
CHECK(first_page->is_valid());
|
||||
CHECK(allocated == requested || allocated == requested - 1);
|
||||
total_pages += allocated;
|
||||
|
||||
Page* last_page = first_page;
|
||||
for (Page* p = first_page; p->is_valid(); p = p->next_page()) {
|
||||
CHECK(isolate->memory_allocator()->IsPageInSpace(p, &faked_space));
|
||||
CHECK(memory_allocator->IsPageInSpace(p, &faked_space));
|
||||
last_page = p;
|
||||
}
|
||||
|
||||
// Again, we should get n or n - 1 pages.
|
||||
Page* others =
|
||||
isolate->memory_allocator()->AllocatePages(
|
||||
requested, &allocated, &faked_space);
|
||||
Page* others = memory_allocator->AllocatePages(
|
||||
requested, &allocated, &faked_space);
|
||||
CHECK(others->is_valid());
|
||||
CHECK(allocated == requested || allocated == requested - 1);
|
||||
total_pages += allocated;
|
||||
|
||||
isolate->memory_allocator()->SetNextPage(last_page, others);
|
||||
memory_allocator->SetNextPage(last_page, others);
|
||||
int page_count = 0;
|
||||
for (Page* p = first_page; p->is_valid(); p = p->next_page()) {
|
||||
CHECK(isolate->memory_allocator()->IsPageInSpace(p, &faked_space));
|
||||
CHECK(memory_allocator->IsPageInSpace(p, &faked_space));
|
||||
page_count++;
|
||||
}
|
||||
CHECK(total_pages == page_count);
|
||||
@ -141,34 +169,39 @@ TEST(MemoryAllocator) {
|
||||
// Freeing pages at the first chunk starting at or after the second page
|
||||
// should free the entire second chunk. It will return the page it was passed
|
||||
// (since the second page was in the first chunk).
|
||||
Page* free_return = isolate->memory_allocator()->FreePages(second_page);
|
||||
Page* free_return = memory_allocator->FreePages(second_page);
|
||||
CHECK(free_return == second_page);
|
||||
isolate->memory_allocator()->SetNextPage(first_page, free_return);
|
||||
memory_allocator->SetNextPage(first_page, free_return);
|
||||
|
||||
// Freeing pages in the first chunk starting at the first page should free
|
||||
// the first chunk and return an invalid page.
|
||||
Page* invalid_page = isolate->memory_allocator()->FreePages(first_page);
|
||||
Page* invalid_page = memory_allocator->FreePages(first_page);
|
||||
CHECK(!invalid_page->is_valid());
|
||||
|
||||
isolate->memory_allocator()->TearDown();
|
||||
memory_allocator->TearDown();
|
||||
delete memory_allocator;
|
||||
}
|
||||
|
||||
|
||||
TEST(NewSpace) {
|
||||
OS::Setup();
|
||||
CHECK(HEAP->ConfigureHeapDefault());
|
||||
CHECK(Isolate::Current()->memory_allocator()->Setup(
|
||||
HEAP->MaxReserved(), HEAP->MaxExecutableSize()));
|
||||
Isolate* isolate = Isolate::Current();
|
||||
isolate->InitializeLoggingAndCounters();
|
||||
Heap* heap = isolate->heap();
|
||||
CHECK(heap->ConfigureHeapDefault());
|
||||
MemoryAllocator* memory_allocator = new MemoryAllocator(isolate);
|
||||
CHECK(memory_allocator->Setup(heap->MaxReserved(),
|
||||
heap->MaxExecutableSize()));
|
||||
TestMemoryAllocatorScope test_scope(isolate, memory_allocator);
|
||||
|
||||
NewSpace new_space(HEAP);
|
||||
NewSpace new_space(heap);
|
||||
|
||||
void* chunk =
|
||||
Isolate::Current()->memory_allocator()->ReserveInitialChunk(
|
||||
4 * HEAP->ReservedSemiSpaceSize());
|
||||
memory_allocator->ReserveInitialChunk(4 * heap->ReservedSemiSpaceSize());
|
||||
CHECK(chunk != NULL);
|
||||
Address start = RoundUp(static_cast<Address>(chunk),
|
||||
2 * HEAP->ReservedSemiSpaceSize());
|
||||
CHECK(new_space.Setup(start, 2 * HEAP->ReservedSemiSpaceSize()));
|
||||
2 * heap->ReservedSemiSpaceSize());
|
||||
CHECK(new_space.Setup(start, 2 * heap->ReservedSemiSpaceSize()));
|
||||
CHECK(new_space.HasBeenSetup());
|
||||
|
||||
while (new_space.Available() >= Page::kMaxHeapObjectSize) {
|
||||
@ -178,28 +211,33 @@ TEST(NewSpace) {
|
||||
}
|
||||
|
||||
new_space.TearDown();
|
||||
Isolate::Current()->memory_allocator()->TearDown();
|
||||
memory_allocator->TearDown();
|
||||
delete memory_allocator;
|
||||
}
|
||||
|
||||
|
||||
TEST(OldSpace) {
|
||||
OS::Setup();
|
||||
CHECK(HEAP->ConfigureHeapDefault());
|
||||
CHECK(Isolate::Current()->memory_allocator()->Setup(
|
||||
HEAP->MaxReserved(), HEAP->MaxExecutableSize()));
|
||||
Isolate* isolate = Isolate::Current();
|
||||
isolate->InitializeLoggingAndCounters();
|
||||
Heap* heap = isolate->heap();
|
||||
CHECK(heap->ConfigureHeapDefault());
|
||||
MemoryAllocator* memory_allocator = new MemoryAllocator(isolate);
|
||||
CHECK(memory_allocator->Setup(heap->MaxReserved(),
|
||||
heap->MaxExecutableSize()));
|
||||
TestMemoryAllocatorScope test_scope(isolate, memory_allocator);
|
||||
|
||||
OldSpace* s = new OldSpace(HEAP,
|
||||
HEAP->MaxOldGenerationSize(),
|
||||
OldSpace* s = new OldSpace(heap,
|
||||
heap->MaxOldGenerationSize(),
|
||||
OLD_POINTER_SPACE,
|
||||
NOT_EXECUTABLE);
|
||||
CHECK(s != NULL);
|
||||
|
||||
void* chunk =
|
||||
Isolate::Current()->memory_allocator()->ReserveInitialChunk(
|
||||
4 * HEAP->ReservedSemiSpaceSize());
|
||||
void* chunk = memory_allocator->ReserveInitialChunk(
|
||||
4 * heap->ReservedSemiSpaceSize());
|
||||
CHECK(chunk != NULL);
|
||||
Address start = static_cast<Address>(chunk);
|
||||
size_t size = RoundUp(start, 2 * HEAP->ReservedSemiSpaceSize()) - start;
|
||||
size_t size = RoundUp(start, 2 * heap->ReservedSemiSpaceSize()) - start;
|
||||
|
||||
CHECK(s->Setup(start, size));
|
||||
|
||||
@ -209,13 +247,13 @@ TEST(OldSpace) {
|
||||
|
||||
s->TearDown();
|
||||
delete s;
|
||||
Isolate::Current()->memory_allocator()->TearDown();
|
||||
memory_allocator->TearDown();
|
||||
delete memory_allocator;
|
||||
}
|
||||
|
||||
|
||||
TEST(LargeObjectSpace) {
|
||||
OS::Setup();
|
||||
CHECK(HEAP->Setup(false));
|
||||
v8::V8::Initialize();
|
||||
|
||||
LargeObjectSpace* lo = HEAP->lo_space();
|
||||
CHECK(lo != NULL);
|
||||
@ -247,9 +285,4 @@ TEST(LargeObjectSpace) {
|
||||
CHECK(!lo->IsEmpty());
|
||||
|
||||
CHECK(lo->AllocateRaw(lo_size)->IsFailure());
|
||||
|
||||
lo->TearDown();
|
||||
delete lo;
|
||||
|
||||
Isolate::Current()->memory_allocator()->TearDown();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user