}
+bool Heap::RootIsImmortalImmovable(int root_index) {
+ switch (root_index) {
+#define CASE(name) \
+ case Heap::k##name##RootIndex: \
+ return true;
+ IMMORTAL_IMMOVABLE_ROOT_LIST(CASE);
+#undef CASE
+ default:
+ return false;
+ }
+}
+
+
#ifdef VERIFY_HEAP
void Heap::Verify() {
CHECK(HasBeenSetUp());
SMI_ROOT_LIST(V) \
V(StringTable, string_table, StringTable)
-// Heap roots that are known to be immortal immovable, for which we can safely
-// skip write barriers.
-#define IMMORTAL_IMMOVABLE_ROOT_LIST(V) \
- V(byte_array_map) \
- V(free_space_map) \
- V(one_pointer_filler_map) \
- V(two_pointer_filler_map) \
- V(undefined_value) \
- V(the_hole_value) \
- V(null_value) \
- V(true_value) \
- V(false_value) \
- V(uninitialized_value) \
- V(cell_map) \
- V(global_property_cell_map) \
- V(shared_function_info_map) \
- V(meta_map) \
- V(heap_number_map) \
- V(mutable_heap_number_map) \
- V(native_context_map) \
- V(fixed_array_map) \
- V(code_map) \
- V(scope_info_map) \
- V(fixed_cow_array_map) \
- V(fixed_double_array_map) \
- V(constant_pool_array_map) \
- V(weak_cell_map) \
- V(no_interceptor_result_sentinel) \
- V(hash_table_map) \
- V(ordered_hash_table_map) \
- V(empty_fixed_array) \
- V(empty_byte_array) \
- V(empty_descriptor_array) \
- V(empty_constant_pool_array) \
- V(arguments_marker) \
- V(symbol_map) \
- V(sloppy_arguments_elements_map) \
- V(function_context_map) \
- V(catch_context_map) \
- V(with_context_map) \
- V(block_context_map) \
- V(module_context_map) \
- V(global_context_map) \
- V(undefined_map) \
- V(the_hole_map) \
- V(null_map) \
- V(boolean_map) \
- V(uninitialized_map) \
- V(message_object_map) \
- V(foreign_map) \
- V(neander_map)
-
#define INTERNALIZED_STRING_LIST(V) \
V(Object_string, "Object") \
V(proto_string, "__proto__") \
V(class_start_position_symbol) \
V(class_end_position_symbol)
+// Heap roots that are known to be immortal immovable, for which we can safely
+// skip write barriers. This list is not complete and has omissions.
+#define IMMORTAL_IMMOVABLE_ROOT_LIST(V) \
+ V(ByteArrayMap) \
+ V(FreeSpaceMap) \
+ V(OnePointerFillerMap) \
+ V(TwoPointerFillerMap) \
+ V(UndefinedValue) \
+ V(TheHoleValue) \
+ V(NullValue) \
+ V(TrueValue) \
+ V(FalseValue) \
+ V(UninitializedValue) \
+ V(CellMap) \
+ V(GlobalPropertyCellMap) \
+ V(SharedFunctionInfoMap) \
+ V(MetaMap) \
+ V(HeapNumberMap) \
+ V(MutableHeapNumberMap) \
+ V(NativeContextMap) \
+ V(FixedArrayMap) \
+ V(CodeMap) \
+ V(ScopeInfoMap) \
+ V(FixedCOWArrayMap) \
+ V(FixedDoubleArrayMap) \
+ V(ConstantPoolArrayMap) \
+ V(WeakCellMap) \
+ V(NoInterceptorResultSentinel) \
+ V(HashTableMap) \
+ V(OrderedHashTableMap) \
+ V(EmptyFixedArray) \
+ V(EmptyByteArray) \
+ V(EmptyDescriptorArray) \
+ V(EmptyConstantPoolArray) \
+ V(ArgumentsMarker) \
+ V(SymbolMap) \
+ V(SloppyArgumentsElementsMap) \
+ V(FunctionContextMap) \
+ V(CatchContextMap) \
+ V(WithContextMap) \
+ V(BlockContextMap) \
+ V(ModuleContextMap) \
+ V(GlobalContextMap) \
+ V(UndefinedMap) \
+ V(TheHoleMap) \
+ V(NullMap) \
+ V(BooleanMap) \
+ V(UninitializedMap) \
+ V(ArgumentsMarkerMap) \
+ V(JSMessageObjectMap) \
+ V(ForeignMap) \
+ V(NeanderMap) \
+ PRIVATE_SYMBOL_LIST(V)
+
// Forward declarations.
class HeapStats;
class Isolate;
return reinterpret_cast<Address*>(&roots_[kStoreBufferTopRootIndex]);
}
+ static bool RootIsImmortalImmovable(int root_index);
+
#ifdef VERIFY_HEAP
// Verify the heap is in its normal state before or after a GC.
void Verify();
kSmiRootsStart = kStringTableRootIndex + 1
};
+ Object* root(RootListIndex index) { return roots_[index]; }
+
STATIC_ASSERT(kUndefinedValueRootIndex ==
Internals::kUndefinedValueRootIndex);
STATIC_ASSERT(kNullValueRootIndex == Internals::kNullValueRootIndex);
DCHECK(!object_.IsKnownGlobal(heap->nan_value()));
return
#define IMMORTAL_IMMOVABLE_ROOT(name) \
- object_.IsKnownGlobal(heap->name()) ||
+ object_.IsKnownGlobal(heap->root(Heap::k##name##RootIndex)) ||
IMMORTAL_IMMOVABLE_ROOT_LIST(IMMORTAL_IMMOVABLE_ROOT)
#undef IMMORTAL_IMMOVABLE_ROOT
#define INTERNALIZED_STRING(name, value) \
object_.IsKnownGlobal(heap->name##_map()) ||
STRING_TYPE_LIST(STRING_TYPE)
#undef STRING_TYPE
-#define SYMBOL(name) object_.IsKnownGlobal(heap->name()) ||
- PRIVATE_SYMBOL_LIST(SYMBOL)
-#undef SYMBOL
false;
}
while (current < end && !(*current)->IsSmi()) {
HeapObject* current_contents = HeapObject::cast(*current);
int root_index = serializer_->root_index_map()->Lookup(current_contents);
- // Repeats are not subject to the write barrier so there are only some
- // objects that can be used in a repeat encoding. These are the early
- // ones in the root array that are never in new space.
+ // Repeats are not subject to the write barrier so we can only use
+ // immortal immovable root members. They are never in new space.
if (current != start && root_index != RootIndexMap::kInvalidRootIndex &&
- root_index < kRootArrayNumberOfConstantEncodings &&
+ Heap::RootIsImmortalImmovable(root_index) &&
current_contents == current[-1]) {
DCHECK(!serializer_->isolate()->heap()->InNewSpace(current_contents));
int repeat_count = 1;
// Large objects are allocated one-by-one when deserializing. We do not
// have to keep track of multiple chunks.
pending_chunk_[LO_SPACE] += size;
- return BackReference(LO_SPACE, 0, seen_large_objects_index_++);
+ return BackReference::LargeObjectReference(seen_large_objects_index_++);
}
}
uint32_t offset = pending_chunk_[space];
pending_chunk_[space] = new_chunk_size;
- return BackReference(space, completed_chunks_[space].length(), offset);
+ return BackReference::Reference(space, completed_chunks_[space].length(),
+ offset);
}
BackReference back_reference = back_reference_map_.Lookup(obj);
if (back_reference.is_valid()) {
- if (FLAG_trace_code_serializer) {
- PrintF(" Encoding back reference to: ");
- obj->ShortPrint();
- PrintF("\n");
+ if (back_reference.is_source()) {
+ DCHECK_EQ(source_, obj);
+ SerializeSourceObject(how_to_code, where_to_point);
+ } else {
+ if (FLAG_trace_code_serializer) {
+ PrintF(" Encoding back reference to: ");
+ obj->ShortPrint();
+ PrintF("\n");
+ }
+ SerializeBackReference(back_reference, how_to_code, where_to_point, skip);
}
- SerializeBackReference(back_reference, how_to_code, where_to_point, skip);
return;
}
UNREACHABLE();
}
- if (obj == source_) {
- SerializeSourceObject(how_to_code, where_to_point);
- return;
- }
-
// Past this point we should not see any (context-specific) maps anymore.
CHECK(!obj->IsMap());
// There should be no references to the global object embedded.
public:
explicit BackReference(uint32_t bitfield) : bitfield_(bitfield) {}
- BackReference(AllocationSpace space, uint32_t chunk_index,
- uint32_t chunk_offset) {
- DCHECK(IsAligned(chunk_offset, kObjectAlignment));
- bitfield_ = SpaceBits::encode(space) | ChunkIndexBits::encode(chunk_index) |
- ChunkOffsetBits::encode(chunk_offset >> kObjectAlignmentBits);
+ BackReference() : bitfield_(kInvalidValue) {}
+
+ static BackReference SourceReference() { return BackReference(kSourceValue); }
+
+ static BackReference LargeObjectReference(uint32_t index) {
+ return BackReference(SpaceBits::encode(LO_SPACE) |
+ ChunkOffsetBits::encode(index));
}
- BackReference() : bitfield_(kInvalidValue) {}
+ static BackReference Reference(AllocationSpace space, uint32_t chunk_index,
+ uint32_t chunk_offset) {
+ DCHECK(IsAligned(chunk_offset, kObjectAlignment));
+ DCHECK_NE(LO_SPACE, space);
+ return BackReference(
+ SpaceBits::encode(space) | ChunkIndexBits::encode(chunk_index) |
+ ChunkOffsetBits::encode(chunk_offset >> kObjectAlignmentBits));
+ }
bool is_valid() const { return bitfield_ != kInvalidValue; }
+ bool is_source() const { return bitfield_ == kSourceValue; }
AllocationSpace space() const {
DCHECK(is_valid());
private:
static const uint32_t kInvalidValue = 0xFFFFFFFF;
+ static const uint32_t kSourceValue = 0xFFFFFFFE;
static const int kChunkOffsetSize = kPageSizeBits - kObjectAlignmentBits;
static const int kChunkIndexSize = 32 - kChunkOffsetSize - kSpaceTagSize;
SetValue(entry, b.bitfield());
}
+ void AddSourceString(String* string) {
+ Add(string, BackReference::SourceReference());
+ }
+
private:
DisallowHeapAllocation no_allocation_;
HashMap* map_;
: Serializer(isolate, sink),
source_(source),
main_code_(main_code),
- num_internalized_strings_(0) {}
+ num_internalized_strings_(0) {
+ back_reference_map_.AddSourceString(source);
+ }
virtual void SerializeObject(HeapObject* o, HowToCode how_to_code,
WhereToPoint where_to_point, int skip);
CHECK_EQ(6 * 1000000, Handle<String>::cast(copy_result)->length());
CHECK(isolate->heap()->InSpace(HeapObject::cast(*copy_result), LO_SPACE));
+ // Make sure we do not serialize too much, e.g. include the source string.
+ CHECK_LT(cache->length(), 7000000);
delete cache;
source.Dispose();