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}
This commit is contained in:
parent
1a5db24e6b
commit
22e6958d63
@ -2791,10 +2791,9 @@ Genesis::Genesis(Isolate* isolate,
|
||||
if (!InstallExperimentalNatives()) return;
|
||||
InitializeExperimentalGlobal();
|
||||
|
||||
// We can't (de-)serialize typed arrays currently, but we are lucky: The state
|
||||
// of the random number generator needs no initialization during snapshot
|
||||
// creation time and we don't need trigonometric functions then.
|
||||
if (!isolate->serializer_enabled()) {
|
||||
// The serializer cannot serialize typed arrays. Reset those typed arrays
|
||||
// for each new context.
|
||||
{
|
||||
// Initially seed the per-context random number generator using the
|
||||
// per-isolate random number generator.
|
||||
const int num_elems = 2;
|
||||
|
@ -2149,12 +2149,6 @@ void Factory::SetNumberStringCache(Handle<Object> number,
|
||||
if (number_string_cache()->get(hash * 2) != *undefined_value()) {
|
||||
int full_size = isolate()->heap()->FullSizeNumberStringCacheLength();
|
||||
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);
|
||||
isolate()->heap()->set_number_string_cache(*new_cache);
|
||||
return;
|
||||
|
@ -1486,6 +1486,10 @@ class Heap {
|
||||
MUST_USE_RESULT AllocationResult
|
||||
AllocateFixedArray(int length, PretenureFlag pretenure = NOT_TENURED);
|
||||
|
||||
static const int kInitialStringTableSize = 2048;
|
||||
static const int kInitialEvalCacheSize = 64;
|
||||
static const int kInitialNumberStringCacheSize = 256;
|
||||
|
||||
private:
|
||||
Heap();
|
||||
|
||||
@ -2043,10 +2047,6 @@ class Heap {
|
||||
inline void UpdateAllocationsHash(uint32_t value);
|
||||
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
|
||||
size_t object_counts_[OBJECT_STATS_COUNT];
|
||||
size_t object_counts_last_time_[OBJECT_STATS_COUNT];
|
||||
|
@ -6186,7 +6186,7 @@ void JSFunction::set_function_bindings(FixedArray* bindings) {
|
||||
// Bound function literal may be initialized to the empty fixed array
|
||||
// before the bindings are set.
|
||||
DCHECK(bindings == GetHeap()->empty_fixed_array() ||
|
||||
bindings->map() == GetHeap()->fixed_cow_array_map());
|
||||
bindings->map() == GetHeap()->fixed_array_map());
|
||||
set_literals_or_bindings(bindings);
|
||||
}
|
||||
|
||||
|
@ -435,8 +435,7 @@ RUNTIME_FUNCTION(Runtime_FunctionBindArguments) {
|
||||
for (int j = 0; j < argc; j++, i++) {
|
||||
new_bindings->set(i, *arguments[j + 1]);
|
||||
}
|
||||
new_bindings->set_map_no_write_barrier(
|
||||
isolate->heap()->fixed_cow_array_map());
|
||||
new_bindings->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
|
||||
bound_function->set_function_bindings(*new_bindings);
|
||||
|
||||
// Update length. Have to remove the prototype first so that map migration
|
||||
@ -462,8 +461,8 @@ RUNTIME_FUNCTION(Runtime_BoundFunctionGetBindings) {
|
||||
if (callable->IsJSFunction()) {
|
||||
Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
|
||||
if (function->shared()->bound()) {
|
||||
RUNTIME_ASSERT(function->function_bindings()->IsFixedArray());
|
||||
Handle<FixedArray> bindings(function->function_bindings());
|
||||
RUNTIME_ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
|
||||
return *isolate->factory()->NewJSArrayWithElements(bindings);
|
||||
}
|
||||
}
|
||||
|
@ -63,6 +63,8 @@ bool Runtime::SetupArrayBufferAllocatingData(Isolate* isolate,
|
||||
bool initialize) {
|
||||
void* data;
|
||||
CHECK(V8::ArrayBufferAllocator() != NULL);
|
||||
// Prevent creating array buffers when serializing.
|
||||
DCHECK(!isolate->serializer_enabled());
|
||||
if (allocated_length != 0) {
|
||||
if (initialize) {
|
||||
data = V8::ArrayBufferAllocator()->Allocate(allocated_length);
|
||||
|
@ -1665,6 +1665,9 @@ void PartialSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
|
||||
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);
|
||||
if (root_index != RootIndexMap::kInvalidRootIndex) {
|
||||
PutRoot(root_index, obj, how_to_code, where_to_point, skip);
|
||||
@ -1832,6 +1835,9 @@ void Serializer::ObjectSerializer::Serialize() {
|
||||
PrintF("\n");
|
||||
}
|
||||
|
||||
// We cannot serialize typed array objects correctly.
|
||||
DCHECK(!object_->IsJSTypedArray());
|
||||
|
||||
if (object_->IsScript()) {
|
||||
// Clear cached line ends.
|
||||
Object* undefined = serializer_->isolate()->heap()->undefined_value();
|
||||
|
@ -99,6 +99,7 @@ class TestHeap : public i::Heap {
|
||||
using i::Heap::AllocateJSObjectFromMap;
|
||||
using i::Heap::AllocateMap;
|
||||
using i::Heap::CopyCode;
|
||||
using i::Heap::kInitialNumberStringCacheSize;
|
||||
};
|
||||
|
||||
|
||||
|
@ -261,7 +261,7 @@ TEST(BoundFunctionInSnapshot) {
|
||||
GetProperty(f, v8::HeapGraphEdge::kInternal, "bindings");
|
||||
CHECK_NE(NULL, bindings);
|
||||
CHECK_EQ(v8::HeapGraphNode::kArray, bindings->GetType());
|
||||
CHECK_EQ(4, bindings->GetChildrenCount());
|
||||
CHECK_EQ(3, bindings->GetChildrenCount());
|
||||
|
||||
const v8::HeapGraphNode* bound_this = GetProperty(
|
||||
f, v8::HeapGraphEdge::kShortcut, "bound_this");
|
||||
|
@ -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
|
||||
TEST(PathTracer) {
|
||||
CcTest::InitializeVM();
|
||||
|
@ -565,7 +565,9 @@ UNINITIALIZED_TEST(CustomContextSerialization) {
|
||||
"(function() {"
|
||||
" 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.
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user