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}
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;
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;
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();
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];
// 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);
}
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
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);
}
}
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);
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);
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();
using i::Heap::AllocateJSObjectFromMap;
using i::Heap::AllocateMap;
using i::Heap::CopyCode;
+ using i::Heap::kInitialNumberStringCacheSize;
};
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");
}
+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();
"(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.
{