Commit 22e6958d authored by yangguo's avatar yangguo Committed by Commit bot

Fix remaining issues in the custom snapshot.

Math functions:
Some Math functions require typed arrays for their implementation. The embedded
script may call those Math functions. The serializer needs to deal with this.
Added assertion to make sure no other typed array is created when snapshotting.

Number-string cache:
We assume that the initial snapshot does not expand the number-string cache.
This is no longer true for custom heap snapshots.

Bound functions:
Bound functions store the bound arguments in a COW fixed array, including the
bindee function. COW arrays are serialized into the startup snapshot and
referenced in the partial snapshot via partial snapshot cache. However, the
bindee function is context-dependent and must not be part of the startup
snapshot. There is no need for bound functions to use a COW array though.

R=jochen@chromium.org

Review URL: https://codereview.chromium.org/851073002

Cr-Commit-Position: refs/heads/master@{#26072}
parent 1a5db24e
...@@ -2791,10 +2791,9 @@ Genesis::Genesis(Isolate* isolate, ...@@ -2791,10 +2791,9 @@ Genesis::Genesis(Isolate* isolate,
if (!InstallExperimentalNatives()) return; if (!InstallExperimentalNatives()) return;
InitializeExperimentalGlobal(); InitializeExperimentalGlobal();
// We can't (de-)serialize typed arrays currently, but we are lucky: The state // The serializer cannot serialize typed arrays. Reset those typed arrays
// of the random number generator needs no initialization during snapshot // for each new context.
// creation time and we don't need trigonometric functions then. {
if (!isolate->serializer_enabled()) {
// Initially seed the per-context random number generator using the // Initially seed the per-context random number generator using the
// per-isolate random number generator. // per-isolate random number generator.
const int num_elems = 2; const int num_elems = 2;
......
...@@ -2149,12 +2149,6 @@ void Factory::SetNumberStringCache(Handle<Object> number, ...@@ -2149,12 +2149,6 @@ void Factory::SetNumberStringCache(Handle<Object> number,
if (number_string_cache()->get(hash * 2) != *undefined_value()) { if (number_string_cache()->get(hash * 2) != *undefined_value()) {
int full_size = isolate()->heap()->FullSizeNumberStringCacheLength(); int full_size = isolate()->heap()->FullSizeNumberStringCacheLength();
if (number_string_cache()->length() != full_size) { if (number_string_cache()->length() != full_size) {
// The first time we have a hash collision, we move to the full sized
// number string cache. The idea is to have a small number string
// cache in the snapshot to keep boot-time memory usage down.
// If we expand the number string cache already while creating
// the snapshot then that didn't work out.
DCHECK(!isolate()->serializer_enabled());
Handle<FixedArray> new_cache = NewFixedArray(full_size, TENURED); Handle<FixedArray> new_cache = NewFixedArray(full_size, TENURED);
isolate()->heap()->set_number_string_cache(*new_cache); isolate()->heap()->set_number_string_cache(*new_cache);
return; return;
......
...@@ -1486,6 +1486,10 @@ class Heap { ...@@ -1486,6 +1486,10 @@ class Heap {
MUST_USE_RESULT AllocationResult MUST_USE_RESULT AllocationResult
AllocateFixedArray(int length, PretenureFlag pretenure = NOT_TENURED); AllocateFixedArray(int length, PretenureFlag pretenure = NOT_TENURED);
static const int kInitialStringTableSize = 2048;
static const int kInitialEvalCacheSize = 64;
static const int kInitialNumberStringCacheSize = 256;
private: private:
Heap(); Heap();
...@@ -2043,10 +2047,6 @@ class Heap { ...@@ -2043,10 +2047,6 @@ class Heap {
inline void UpdateAllocationsHash(uint32_t value); inline void UpdateAllocationsHash(uint32_t value);
inline void PrintAlloctionsHash(); inline void PrintAlloctionsHash();
static const int kInitialStringTableSize = 2048;
static const int kInitialEvalCacheSize = 64;
static const int kInitialNumberStringCacheSize = 256;
// Object counts and used memory by InstanceType // Object counts and used memory by InstanceType
size_t object_counts_[OBJECT_STATS_COUNT]; size_t object_counts_[OBJECT_STATS_COUNT];
size_t object_counts_last_time_[OBJECT_STATS_COUNT]; size_t object_counts_last_time_[OBJECT_STATS_COUNT];
......
...@@ -6186,7 +6186,7 @@ void JSFunction::set_function_bindings(FixedArray* bindings) { ...@@ -6186,7 +6186,7 @@ void JSFunction::set_function_bindings(FixedArray* bindings) {
// Bound function literal may be initialized to the empty fixed array // Bound function literal may be initialized to the empty fixed array
// before the bindings are set. // before the bindings are set.
DCHECK(bindings == GetHeap()->empty_fixed_array() || DCHECK(bindings == GetHeap()->empty_fixed_array() ||
bindings->map() == GetHeap()->fixed_cow_array_map()); bindings->map() == GetHeap()->fixed_array_map());
set_literals_or_bindings(bindings); set_literals_or_bindings(bindings);
} }
......
...@@ -435,8 +435,7 @@ RUNTIME_FUNCTION(Runtime_FunctionBindArguments) { ...@@ -435,8 +435,7 @@ RUNTIME_FUNCTION(Runtime_FunctionBindArguments) {
for (int j = 0; j < argc; j++, i++) { for (int j = 0; j < argc; j++, i++) {
new_bindings->set(i, *arguments[j + 1]); new_bindings->set(i, *arguments[j + 1]);
} }
new_bindings->set_map_no_write_barrier( new_bindings->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
isolate->heap()->fixed_cow_array_map());
bound_function->set_function_bindings(*new_bindings); bound_function->set_function_bindings(*new_bindings);
// Update length. Have to remove the prototype first so that map migration // Update length. Have to remove the prototype first so that map migration
...@@ -462,8 +461,8 @@ RUNTIME_FUNCTION(Runtime_BoundFunctionGetBindings) { ...@@ -462,8 +461,8 @@ RUNTIME_FUNCTION(Runtime_BoundFunctionGetBindings) {
if (callable->IsJSFunction()) { if (callable->IsJSFunction()) {
Handle<JSFunction> function = Handle<JSFunction>::cast(callable); Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
if (function->shared()->bound()) { if (function->shared()->bound()) {
RUNTIME_ASSERT(function->function_bindings()->IsFixedArray());
Handle<FixedArray> bindings(function->function_bindings()); Handle<FixedArray> bindings(function->function_bindings());
RUNTIME_ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
return *isolate->factory()->NewJSArrayWithElements(bindings); return *isolate->factory()->NewJSArrayWithElements(bindings);
} }
} }
......
...@@ -63,6 +63,8 @@ bool Runtime::SetupArrayBufferAllocatingData(Isolate* isolate, ...@@ -63,6 +63,8 @@ bool Runtime::SetupArrayBufferAllocatingData(Isolate* isolate,
bool initialize) { bool initialize) {
void* data; void* data;
CHECK(V8::ArrayBufferAllocator() != NULL); CHECK(V8::ArrayBufferAllocator() != NULL);
// Prevent creating array buffers when serializing.
DCHECK(!isolate->serializer_enabled());
if (allocated_length != 0) { if (allocated_length != 0) {
if (initialize) { if (initialize) {
data = V8::ArrayBufferAllocator()->Allocate(allocated_length); data = V8::ArrayBufferAllocator()->Allocate(allocated_length);
......
...@@ -1665,6 +1665,9 @@ void PartialSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code, ...@@ -1665,6 +1665,9 @@ void PartialSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
DCHECK(Map::cast(obj)->code_cache() == obj->GetHeap()->empty_fixed_array()); DCHECK(Map::cast(obj)->code_cache() == obj->GetHeap()->empty_fixed_array());
} }
// Replace typed arrays by undefined.
if (obj->IsJSTypedArray()) obj = isolate_->heap()->undefined_value();
int root_index = root_index_map_.Lookup(obj); int root_index = root_index_map_.Lookup(obj);
if (root_index != RootIndexMap::kInvalidRootIndex) { if (root_index != RootIndexMap::kInvalidRootIndex) {
PutRoot(root_index, obj, how_to_code, where_to_point, skip); PutRoot(root_index, obj, how_to_code, where_to_point, skip);
...@@ -1832,6 +1835,9 @@ void Serializer::ObjectSerializer::Serialize() { ...@@ -1832,6 +1835,9 @@ void Serializer::ObjectSerializer::Serialize() {
PrintF("\n"); PrintF("\n");
} }
// We cannot serialize typed array objects correctly.
DCHECK(!object_->IsJSTypedArray());
if (object_->IsScript()) { if (object_->IsScript()) {
// Clear cached line ends. // Clear cached line ends.
Object* undefined = serializer_->isolate()->heap()->undefined_value(); Object* undefined = serializer_->isolate()->heap()->undefined_value();
......
...@@ -99,6 +99,7 @@ class TestHeap : public i::Heap { ...@@ -99,6 +99,7 @@ class TestHeap : public i::Heap {
using i::Heap::AllocateJSObjectFromMap; using i::Heap::AllocateJSObjectFromMap;
using i::Heap::AllocateMap; using i::Heap::AllocateMap;
using i::Heap::CopyCode; using i::Heap::CopyCode;
using i::Heap::kInitialNumberStringCacheSize;
}; };
......
...@@ -261,7 +261,7 @@ TEST(BoundFunctionInSnapshot) { ...@@ -261,7 +261,7 @@ TEST(BoundFunctionInSnapshot) {
GetProperty(f, v8::HeapGraphEdge::kInternal, "bindings"); GetProperty(f, v8::HeapGraphEdge::kInternal, "bindings");
CHECK_NE(NULL, bindings); CHECK_NE(NULL, bindings);
CHECK_EQ(v8::HeapGraphNode::kArray, bindings->GetType()); CHECK_EQ(v8::HeapGraphNode::kArray, bindings->GetType());
CHECK_EQ(4, bindings->GetChildrenCount()); CHECK_EQ(3, bindings->GetChildrenCount());
const v8::HeapGraphNode* bound_this = GetProperty( const v8::HeapGraphNode* bound_this = GetProperty(
f, v8::HeapGraphEdge::kShortcut, "bound_this"); f, v8::HeapGraphEdge::kShortcut, "bound_this");
......
...@@ -5089,6 +5089,16 @@ TEST(Regress442710) { ...@@ -5089,6 +5089,16 @@ TEST(Regress442710) {
} }
TEST(NumberStringCacheSize) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
Heap* heap = isolate->heap();
// Test that the number-string cache has not been resized.
CHECK_EQ(TestHeap::kInitialNumberStringCacheSize * 2,
heap->number_string_cache()->length());
}
#ifdef DEBUG #ifdef DEBUG
TEST(PathTracer) { TEST(PathTracer) {
CcTest::InitializeVM(); CcTest::InitializeVM();
......
...@@ -565,7 +565,9 @@ UNINITIALIZED_TEST(CustomContextSerialization) { ...@@ -565,7 +565,9 @@ UNINITIALIZED_TEST(CustomContextSerialization) {
"(function() {" "(function() {"
" e = function(s) { eval (s); }" " e = function(s) { eval (s); }"
"})();" "})();"
"var o = this;"); "var o = this;"
"var r = Math.random();"
"var f = (function(a, b) {}).bind(1, 2, 3);");
} }
// Make sure all builtin scripts are cached. // Make sure all builtin scripts are cached.
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment