Version 3.31.39 (based on 7ec1c3616e6d67efa7bef3124596f321d2800b76)
Performance and stability improvements on all platforms.
Cr-Commit-Position: refs/heads/candidates@{#25314}
diff --git a/ChangeLog b/ChangeLog
index 37c0069..5b45ea6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2014-12-03: Version 3.31.39
+
+ Performance and stability improvements on all platforms.
+
+
2014-12-03: Version 3.31.38
Stage ES6 classes and object literal extensions (issue 3330).
diff --git a/src/compiler/machine-operator-reducer.cc b/src/compiler/machine-operator-reducer.cc
index 00c998d..f8555da 100644
--- a/src/compiler/machine-operator-reducer.cc
+++ b/src/compiler/machine-operator-reducer.cc
@@ -779,13 +779,37 @@
Int32BinopMatcher mleft(m.left().node());
if (mleft.right().HasValue() &&
(mleft.right().Value() & m.right().Value()) == mleft.right().Value()) {
- // (x + K) & K => (x & K) + K
+ // (x + (K << L)) & (-1 << L) => (x & (-1 << L)) + (K << L)
return Replace(graph()->NewNode(
machine()->Int32Add(),
graph()->NewNode(machine()->Word32And(), mleft.left().node(),
m.right().node()),
mleft.right().node()));
}
+ if (mleft.left().IsWord32Shl()) {
+ Int32BinopMatcher mleftleft(mleft.left().node());
+ if (mleftleft.right().Is(
+ base::bits::CountTrailingZeros32(m.right().Value()))) {
+ // (y << L + x) & (-1 << L) => (x & (-1 << L)) + y << L
+ return Replace(graph()->NewNode(
+ machine()->Int32Add(),
+ graph()->NewNode(machine()->Word32And(), mleft.right().node(),
+ m.right().node()),
+ mleftleft.node()));
+ }
+ }
+ if (mleft.right().IsWord32Shl()) {
+ Int32BinopMatcher mleftright(mleft.right().node());
+ if (mleftright.right().Is(
+ base::bits::CountTrailingZeros32(m.right().Value()))) {
+ // (x + y << L) & (-1 << L) => (x & (-1 << L)) + y << L
+ return Replace(graph()->NewNode(
+ machine()->Int32Add(),
+ graph()->NewNode(machine()->Word32And(), mleft.left().node(),
+ m.right().node()),
+ mleftright.node()));
+ }
+ }
}
return NoChange();
}
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index c16d56c..4d9b2b2 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -488,7 +488,7 @@
DEFINE_BOOL(serialize_toplevel, true, "enable caching of toplevel scripts")
DEFINE_BOOL(serialize_inner, false, "enable caching of inner functions")
-DEFINE_BOOL(trace_code_serializer, false, "print code serializer trace")
+DEFINE_BOOL(trace_serializer, false, "print code serializer trace")
// compiler.cc
DEFINE_INT(min_preparse_length, 1024,
diff --git a/src/heap/heap.cc b/src/heap/heap.cc
index fa32764..8c489bd 100644
--- a/src/heap/heap.cc
+++ b/src/heap/heap.cc
@@ -120,6 +120,7 @@
min_in_mutator_(kMaxInt),
marking_time_(0.0),
sweeping_time_(0.0),
+ last_idle_notification_time_(0.0),
mark_compact_collector_(this),
store_buffer_(this),
marking_(this),
@@ -4530,6 +4531,7 @@
}
double current_time = MonotonicallyIncreasingTimeInMs();
+ last_idle_notification_time_ = current_time;
double deadline_difference = deadline_in_ms - current_time;
if (deadline_difference >= 0) {
@@ -4564,6 +4566,13 @@
}
+bool Heap::RecentIdleNotifcationHappened() {
+ return (last_idle_notification_time_ +
+ GCIdleTimeHandler::kMaxFrameRenderingIdleTime) >
+ MonotonicallyIncreasingTimeInMs();
+}
+
+
#ifdef DEBUG
void Heap::Print() {
diff --git a/src/heap/heap.h b/src/heap/heap.h
index 09a0678..9fa9497 100644
--- a/src/heap/heap.h
+++ b/src/heap/heap.h
@@ -1295,6 +1295,8 @@
int gc_count() const { return gc_count_; }
+ bool RecentIdleNotifcationHappened();
+
// Completely clear the Instanceof cache (to stop it keeping objects alive
// around a GC).
inline void CompletelyClearInstanceofCache();
@@ -2057,6 +2059,9 @@
// Cumulative GC time spent in sweeping
double sweeping_time_;
+ // Last time an idle notification happened
+ double last_idle_notification_time_;
+
MarkCompactCollector mark_compact_collector_;
StoreBuffer store_buffer_;
diff --git a/src/heap/incremental-marking.cc b/src/heap/incremental-marking.cc
index 7ab3bf8..08f11c6 100644
--- a/src/heap/incremental-marking.cc
+++ b/src/heap/incremental-marking.cc
@@ -880,6 +880,12 @@
return 0;
}
+ // If an idle notification happened recently, we delay marking steps.
+ if (marking == DO_NOT_FORCE_MARKING &&
+ heap_->RecentIdleNotifcationHappened()) {
+ return 0;
+ }
+
if (state_ == MARKING && no_marking_scope_depth_ > 0) return 0;
intptr_t bytes_processed = 0;
diff --git a/src/serialize.cc b/src/serialize.cc
index fab9775..e6aae7f 100644
--- a/src/serialize.cc
+++ b/src/serialize.cc
@@ -794,10 +794,24 @@
}
-Object* Deserializer::ProcessBackRefInSerializedCode(Object* obj) {
- if (obj->IsInternalizedString()) {
- return String::cast(obj)->GetForwardedInternalizedString();
+HeapObject* Deserializer::GetBackReferencedObject(int space) {
+ HeapObject* obj;
+ if (space == LO_SPACE) {
+ uint32_t index = source_->GetInt();
+ obj = deserialized_large_objects_[index];
+ } else {
+ BackReference back_reference(source_->GetInt());
+ DCHECK(space < kNumberOfPreallocatedSpaces);
+ uint32_t chunk_index = back_reference.chunk_index();
+ DCHECK_LE(chunk_index, current_chunk_[space]);
+ uint32_t chunk_offset = back_reference.chunk_offset();
+ obj = HeapObject::FromAddress(reservations_[space][chunk_index].start +
+ chunk_offset);
}
+ if (deserializing_user_code() && obj->IsInternalizedString()) {
+ obj = String::cast(obj)->GetForwardedInternalizedString();
+ }
+ hot_objects_.Add(obj);
return obj;
}
@@ -904,7 +918,7 @@
source_space != CODE_SPACE &&
source_space != OLD_DATA_SPACE);
while (current < limit) {
- int data = source_->Get();
+ byte data = source_->Get();
switch (data) {
#define CASE_STATEMENT(where, how, within, space_number) \
case where + how + within + space_number: \
@@ -945,9 +959,6 @@
} else if (where == kBackref) { \
emit_write_barrier = (space_number == NEW_SPACE); \
new_object = GetBackReferencedObject(data & kSpaceMask); \
- if (deserializing_user_code()) { \
- new_object = ProcessBackRefInSerializedCode(new_object); \
- } \
} else if (where == kBuiltin) { \
DCHECK(deserializing_user_code()); \
int builtin_id = source_->GetInt(); \
@@ -968,9 +979,6 @@
reinterpret_cast<Address>(current) + skip); \
emit_write_barrier = (space_number == NEW_SPACE); \
new_object = GetBackReferencedObject(data & kSpaceMask); \
- if (deserializing_user_code()) { \
- new_object = ProcessBackRefInSerializedCode(new_object); \
- } \
} \
if (within == kInnerPointer) { \
if (space_number != CODE_SPACE || new_object->IsCode()) { \
@@ -1111,7 +1119,7 @@
break;
}
- case kRepeat: {
+ case kVariableRepeat: {
int repeats = source_->GetInt();
Object* object = current[-1];
DCHECK(!isolate->heap()->InNewSpace(object));
@@ -1122,11 +1130,13 @@
STATIC_ASSERT(kRootArrayNumberOfConstantEncodings ==
Heap::kOldSpaceRoots);
- STATIC_ASSERT(kMaxRepeats == 13);
- case kConstantRepeat:
- FOUR_CASES(kConstantRepeat + 1)
- FOUR_CASES(kConstantRepeat + 5)
- FOUR_CASES(kConstantRepeat + 9) {
+ STATIC_ASSERT(kMaxFixedRepeats == 15);
+ FOUR_CASES(kFixedRepeat)
+ FOUR_CASES(kFixedRepeat + 4)
+ FOUR_CASES(kFixedRepeat + 8)
+ case kFixedRepeat + 12:
+ case kFixedRepeat + 13:
+ case kFixedRepeat + 14: {
int repeats = RepeatsForCode(data);
Object* object = current[-1];
DCHECK(!isolate->heap()->InNewSpace(object));
@@ -1261,6 +1271,27 @@
break;
}
+ FOUR_CASES(kHotObjectWithSkip)
+ FOUR_CASES(kHotObjectWithSkip + 4) {
+ int skip = source_->GetInt();
+ current = reinterpret_cast<Object**>(
+ reinterpret_cast<Address>(current) + skip);
+ // Fall through.
+ }
+ FOUR_CASES(kHotObject)
+ FOUR_CASES(kHotObject + 4) {
+ int index = data & kHotObjectIndexMask;
+ *current = hot_objects_.Get(index);
+ if (write_barrier_needed && isolate->heap()->InNewSpace(*current)) {
+ Address current_address = reinterpret_cast<Address>(current);
+ isolate->heap()->RecordWrite(
+ current_object_address,
+ static_cast<int>(current_address - current_object_address));
+ }
+ current++;
+ break;
+ }
+
case kSynchronize: {
// If we get here then that indicates that you have a mismatch between
// the number of GC roots when serializing and deserializing.
@@ -1324,7 +1355,7 @@
sink_->Put(kSkip, "Skip");
sink_->PutInt(kPointerSize, "SkipOneWord");
} else if ((*current)->IsSmi()) {
- sink_->Put(kRawData + 1, "Smi");
+ sink_->Put(kOnePointerRawData, "Smi");
for (int i = 0; i < kPointerSize; i++) {
sink_->Put(reinterpret_cast<byte*>(current)[i], "Byte");
}
@@ -1352,7 +1383,7 @@
void Serializer::VisitPointers(Object** start, Object** end) {
for (Object** current = start; current < end; current++) {
if ((*current)->IsSmi()) {
- sink_->Put(kRawData + 1, "Smi");
+ sink_->Put(kOnePointerRawData, "Smi");
for (int i = 0; i < kPointerSize; i++) {
sink_->Put(reinterpret_cast<byte*>(current)[i], "Byte");
}
@@ -1426,24 +1457,61 @@
}
-// Encode the location of an already deserialized object in order to write its
-// location into a later object. We can encode the location as an offset from
-// the start of the deserialized objects or as an offset backwards from the
-// current allocation pointer.
-void Serializer::SerializeBackReference(BackReference back_reference,
- HowToCode how_to_code,
- WhereToPoint where_to_point, int skip) {
- AllocationSpace space = back_reference.space();
- if (skip == 0) {
- sink_->Put(kBackref + how_to_code + where_to_point + space, "BackRefSer");
- } else {
- sink_->Put(kBackrefWithSkip + how_to_code + where_to_point + space,
- "BackRefSerWithSkip");
- sink_->PutInt(skip, "BackRefSkipDistance");
+bool Serializer::SerializeKnownObject(HeapObject* obj, HowToCode how_to_code,
+ WhereToPoint where_to_point, int skip) {
+ if (how_to_code == kPlain && where_to_point == kStartOfObject) {
+ // Encode a reference to a hot object by its index in the working set.
+ int index = hot_objects_.Find(obj);
+ if (index != HotObjectsList::kNotFound) {
+ DCHECK(index >= 0 && index <= kMaxHotObjectIndex);
+ if (FLAG_trace_serializer) {
+ PrintF(" Encoding hot object %d:", index);
+ obj->ShortPrint();
+ PrintF("\n");
+ }
+ if (skip != 0) {
+ sink_->Put(kHotObjectWithSkip + index, "HotObjectWithSkip");
+ sink_->PutInt(skip, "HotObjectSkipDistance");
+ } else {
+ sink_->Put(kHotObject + index, "HotObject");
+ }
+ return true;
+ }
}
+ BackReference back_reference = back_reference_map_.Lookup(obj);
+ if (back_reference.is_valid()) {
+ // Encode the location of an already deserialized object in order to write
+ // its location into a later object. We can encode the location as an
+ // offset fromthe start of the deserialized objects or as an offset
+ // backwards from thecurrent allocation pointer.
+ if (back_reference.is_source()) {
+ FlushSkip(skip);
+ if (FLAG_trace_serializer) PrintF(" Encoding source object\n");
+ DCHECK(how_to_code == kPlain && where_to_point == kStartOfObject);
+ sink_->Put(kAttachedReference + how_to_code + where_to_point, "Source");
+ sink_->PutInt(kSourceObjectReference, "kSourceObjectIndex");
+ } else {
+ if (FLAG_trace_serializer) {
+ PrintF(" Encoding back reference to: ");
+ obj->ShortPrint();
+ PrintF("\n");
+ }
- sink_->PutInt(back_reference.reference(),
- (space == LO_SPACE) ? "large object index" : "allocation");
+ AllocationSpace space = back_reference.space();
+ if (skip == 0) {
+ sink_->Put(kBackref + how_to_code + where_to_point + space, "BackRef");
+ } else {
+ sink_->Put(kBackrefWithSkip + how_to_code + where_to_point + space,
+ "BackRefWithSkip");
+ sink_->PutInt(skip, "BackRefSkipDistance");
+ }
+ sink_->PutInt(back_reference.reference(), "BackRefValue");
+
+ hot_objects_.Add(obj);
+ }
+ return true;
+ }
+ return false;
}
@@ -1460,16 +1528,9 @@
return;
}
- BackReference back_reference = back_reference_map_.Lookup(obj);
- if (back_reference.is_valid()) {
- SerializeBackReference(back_reference, how_to_code, where_to_point, skip);
- return;
- }
+ if (SerializeKnownObject(obj, how_to_code, where_to_point, skip)) return;
- if (skip != 0) {
- sink_->Put(kSkip, "FlushPendingSkip");
- sink_->PutInt(skip, "SkipDistance");
- }
+ FlushSkip(skip);
// Object has not yet been serialized. Serialize it here.
ObjectSerializer object_serializer(this, obj, sink_, how_to_code,
@@ -1479,7 +1540,7 @@
void StartupSerializer::SerializeWeakReferences() {
- // This phase comes right after the partial serialization (of the snapshot).
+ // This phase comes right after the serialization (of the snapshot).
// After we have done the partial serialization the partial snapshot cache
// will contain some references needed to decode the partial snapshot. We
// add one entry with 'undefined' which is the sentinel that the deserializer
@@ -1496,6 +1557,12 @@
SerializerDeserializer::HowToCode how_to_code,
SerializerDeserializer::WhereToPoint where_to_point,
int skip) {
+ if (FLAG_trace_serializer) {
+ PrintF(" Encoding root %d:", root_index);
+ object->ShortPrint();
+ PrintF("\n");
+ }
+
if (how_to_code == kPlain &&
where_to_point == kStartOfObject &&
root_index < kRootArrayNumberOfConstantEncodings &&
@@ -1509,10 +1576,7 @@
sink_->PutInt(skip, "SkipInPutRoot");
}
} else {
- if (skip != 0) {
- sink_->Put(kSkip, "SkipFromPutRoot");
- sink_->PutInt(skip, "SkipFromPutRootDistance");
- }
+ FlushSkip(skip);
sink_->Put(kRootArray + how_to_code + where_to_point, "RootSerialization");
sink_->PutInt(root_index, "root_index");
}
@@ -1534,10 +1598,7 @@
}
if (ShouldBeInThePartialSnapshotCache(obj)) {
- if (skip != 0) {
- sink_->Put(kSkip, "SkipFromSerializeObject");
- sink_->PutInt(skip, "SkipDistanceFromSerializeObject");
- }
+ FlushSkip(skip);
int cache_index = PartialSnapshotCacheIndex(obj);
sink_->Put(kPartialSnapshotCache + how_to_code + where_to_point,
@@ -1554,16 +1615,10 @@
// either in the root table or in the partial snapshot cache.
DCHECK(!obj->IsInternalizedString());
- BackReference back_reference = back_reference_map_.Lookup(obj);
- if (back_reference.is_valid()) {
- SerializeBackReference(back_reference, how_to_code, where_to_point, skip);
- return;
- }
+ if (SerializeKnownObject(obj, how_to_code, where_to_point, skip)) return;
- if (skip != 0) {
- sink_->Put(kSkip, "SkipFromSerializeObject");
- sink_->PutInt(skip, "SkipDistanceFromSerializeObject");
- }
+ FlushSkip(skip);
+
// Object has not yet been serialized. Serialize it here.
ObjectSerializer serializer(this, obj, sink_, how_to_code, where_to_point);
serializer.Serialize();
@@ -1584,8 +1639,8 @@
BackReference back_reference;
if (space == LO_SPACE) {
sink_->Put(kNewObject + reference_representation_ + space,
- "new large object");
- sink_->PutInt(size >> kObjectAlignmentBits, "Size in words");
+ "NewLargeObject");
+ sink_->PutInt(size >> kObjectAlignmentBits, "ObjectSizeInWords");
if (object_->IsCode()) {
sink_->Put(EXECUTABLE, "executable large object");
} else {
@@ -1596,14 +1651,14 @@
if (object_->NeedsToEnsureDoubleAlignment()) {
// Add wriggle room for double alignment padding.
back_reference = serializer_->Allocate(space, size + kPointerSize);
- sink_->PutInt(kDoubleAlignmentSentinel, "double align");
+ sink_->PutInt(kDoubleAlignmentSentinel, "DoubleAlignSentinel");
} else {
back_reference = serializer_->Allocate(space, size);
}
- sink_->Put(kNewObject + reference_representation_ + space, "new object");
+ sink_->Put(kNewObject + reference_representation_ + space, "NewObject");
int encoded_size = size >> kObjectAlignmentBits;
DCHECK_NE(kDoubleAlignmentSentinel, encoded_size);
- sink_->PutInt(encoded_size, "Size in words");
+ sink_->PutInt(encoded_size, "ObjectSizeInWords");
}
// Mark this object as already serialized.
@@ -1677,6 +1732,12 @@
void Serializer::ObjectSerializer::Serialize() {
+ if (FLAG_trace_serializer) {
+ PrintF(" Encoding heap object: ");
+ object_->ShortPrint();
+ PrintF("\n");
+ }
+
if (object_->IsExternalString()) {
Heap* heap = serializer_->isolate()->heap();
if (object_->map() != heap->native_source_string_map()) {
@@ -1727,8 +1788,8 @@
}
current += repeat_count;
bytes_processed_so_far_ += repeat_count * kPointerSize;
- if (repeat_count > kMaxRepeats) {
- sink_->Put(kRepeat, "SerializeRepeats");
+ if (repeat_count > kMaxFixedRepeats) {
+ sink_->Put(kVariableRepeat, "SerializeRepeats");
sink_->PutInt(repeat_count, "SerializeRepeats");
} else {
sink_->Put(CodeForRepeats(repeat_count), "SerializeRepeats");
@@ -1957,8 +2018,8 @@
if (new_chunk_size > max_chunk_size(space)) {
// The new chunk size would not fit onto a single page. Complete the
// current chunk and start a new one.
- sink_->Put(kNextChunk, "move to next chunk");
- sink_->Put(space, "space of next chunk");
+ sink_->Put(kNextChunk, "NextChunk");
+ sink_->Put(space, "NextChunkSpace");
completed_chunks_[space].Add(pending_chunk_[space]);
pending_chunk_[space] = 0;
new_chunk_size = size;
@@ -1990,7 +2051,7 @@
Handle<String> source) {
base::ElapsedTimer timer;
if (FLAG_profile_deserialization) timer.Start();
- if (FLAG_trace_code_serializer) {
+ if (FLAG_trace_serializer) {
PrintF("[Serializing from");
Object* script = info->script();
if (script->IsScript()) Script::cast(script)->name()->ShortPrint();
@@ -2030,33 +2091,13 @@
WhereToPoint where_to_point, int skip) {
int root_index = root_index_map_.Lookup(obj);
if (root_index != RootIndexMap::kInvalidRootIndex) {
- if (FLAG_trace_code_serializer) {
- PrintF(" Encoding root: %d\n", root_index);
- }
PutRoot(root_index, obj, how_to_code, where_to_point, skip);
return;
}
- BackReference back_reference = back_reference_map_.Lookup(obj);
- if (back_reference.is_valid()) {
- 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);
- }
- return;
- }
+ if (SerializeKnownObject(obj, how_to_code, where_to_point, skip)) return;
- if (skip != 0) {
- sink_->Put(kSkip, "SkipFromSerializeObject");
- sink_->PutInt(skip, "SkipDistanceFromSerializeObject");
- }
+ FlushSkip(skip);
if (obj->IsCode()) {
Code* code_object = Code::cast(obj);
@@ -2109,12 +2150,6 @@
void CodeSerializer::SerializeGeneric(HeapObject* heap_object,
HowToCode how_to_code,
WhereToPoint where_to_point) {
- if (FLAG_trace_code_serializer) {
- PrintF(" Encoding heap object: ");
- heap_object->ShortPrint();
- PrintF("\n");
- }
-
if (heap_object->IsInternalizedString()) num_internalized_strings_++;
// Object has not yet been serialized. Serialize it here.
@@ -2132,7 +2167,7 @@
DCHECK_LT(builtin_index, Builtins::builtin_count);
DCHECK_LE(0, builtin_index);
- if (FLAG_trace_code_serializer) {
+ if (FLAG_trace_serializer) {
PrintF(" Encoding builtin: %s\n",
isolate()->builtins()->name(builtin_index));
}
@@ -2152,7 +2187,7 @@
int index = AddCodeStubKey(stub_key) + kCodeStubsBaseIndex;
- if (FLAG_trace_code_serializer) {
+ if (FLAG_trace_serializer) {
PrintF(" Encoding code stub %s as %d\n",
CodeStub::MajorName(CodeStub::MajorKeyFromKey(stub_key), false),
index);
@@ -2168,7 +2203,7 @@
// The IC may be implemented as a stub.
uint32_t stub_key = ic->stub_key();
if (stub_key != CodeStub::NoCacheKey()) {
- if (FLAG_trace_code_serializer) {
+ if (FLAG_trace_serializer) {
PrintF(" %s is a code stub\n", Code::Kind2String(ic->kind()));
}
SerializeCodeStub(stub_key, how_to_code, where_to_point);
@@ -2182,7 +2217,7 @@
Builtins::Name name = static_cast<Builtins::Name>(builtin_index);
Code* builtin = isolate()->builtins()->builtin(name);
if (builtin == ic) {
- if (FLAG_trace_code_serializer) {
+ if (FLAG_trace_serializer) {
PrintF(" %s is a builtin\n", Code::Kind2String(ic->kind()));
}
DCHECK(ic->kind() == Code::KEYED_LOAD_IC ||
@@ -2193,7 +2228,7 @@
}
// The IC may also just be a piece of code kept in the non_monomorphic_cache.
// In that case, just serialize as a normal code object.
- if (FLAG_trace_code_serializer) {
+ if (FLAG_trace_serializer) {
PrintF(" %s has no special handling\n", Code::Kind2String(ic->kind()));
}
DCHECK(ic->kind() == Code::LOAD_IC || ic->kind() == Code::STORE_IC);
@@ -2215,7 +2250,7 @@
void CodeSerializer::SerializeSourceObject(HowToCode how_to_code,
WhereToPoint where_to_point) {
- if (FLAG_trace_code_serializer) PrintF(" Encoding source object\n");
+ if (FLAG_trace_serializer) PrintF(" Encoding source object\n");
DCHECK(how_to_code == kPlain && where_to_point == kStartOfObject);
sink_->Put(kAttachedReference + how_to_code + where_to_point, "Source");
diff --git a/src/serialize.h b/src/serialize.h
index 3bb0e1a..43a01e4 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -285,6 +285,43 @@
};
+class HotObjectsList {
+ public:
+ HotObjectsList() : index_(0) {
+ for (int i = 0; i < kSize; i++) circular_queue_[i] = NULL;
+ }
+
+ void Add(HeapObject* object) {
+ circular_queue_[index_] = object;
+ index_ = (index_ + 1) & kSizeMask;
+ }
+
+ HeapObject* Get(int index) {
+ DCHECK_NE(NULL, circular_queue_[index]);
+ return circular_queue_[index];
+ }
+
+ static const int kNotFound = -1;
+
+ int Find(HeapObject* object) {
+ for (int i = 0; i < kSize; i++) {
+ if (circular_queue_[i] == object) return i;
+ }
+ return kNotFound;
+ }
+
+ static const int kSize = 8;
+
+ private:
+ STATIC_ASSERT(IS_POWER_OF_TWO(kSize));
+ static const int kSizeMask = kSize - 1;
+ HeapObject* circular_queue_[kSize];
+ int index_;
+
+ DISALLOW_COPY_AND_ASSIGN(HotObjectsList);
+};
+
+
// The Serializer/Deserializer class is a common superclass for Serializer and
// Deserializer which is used to store common constants and methods used by
// both.
@@ -303,6 +340,7 @@
enum Where {
kNewObject = 0, // Object is next in snapshot.
// 1-7 One per space.
+ // 0x8 Unused.
kRootArray = 0x9, // Object is found in root array.
kPartialSnapshotCache = 0xa, // Object is in the cache.
kExternalReference = 0xb, // Pointer to an external reference.
@@ -346,38 +384,58 @@
// entire code in one memcpy, then fix up stuff with kSkip and other byte
// codes that overwrite data.
static const int kRawData = 0x20;
- // Some common raw lengths: 0x21-0x3f. These autoadvance the current pointer.
- // A tag emitted at strategic points in the snapshot to delineate sections.
- // If the deserializer does not find these at the expected moments then it
- // is an indication that the snapshot and the VM do not fit together.
- // Examine the build process for architecture, version or configuration
- // mismatches.
- static const int kSynchronize = 0x70;
- // Used for the source code of the natives, which is in the executable, but
- // is referred to from external strings in the snapshot.
- static const int kNativesStringResource = 0x71;
- static const int kRepeat = 0x72;
- static const int kConstantRepeat = 0x73;
- // 0x73-0x7f Repeat last word (subtract 0x72 to get the count).
- static const int kMaxRepeats = 0x7f - 0x72;
+ // Some common raw lengths: 0x21-0x3f.
+ // These autoadvance the current pointer.
+ static const int kOnePointerRawData = 0x21;
+
+ static const int kVariableRepeat = 0x60;
+ // 0x61-0x6f Repeat last word
+ static const int kFixedRepeat = 0x61;
+ static const int kFixedRepeatBase = kFixedRepeat - 1;
+ static const int kLastFixedRepeat = 0x6f;
+ static const int kMaxFixedRepeats = kLastFixedRepeat - kFixedRepeatBase;
static int CodeForRepeats(int repeats) {
- DCHECK(repeats >= 1 && repeats <= kMaxRepeats);
- return 0x72 + repeats;
+ DCHECK(repeats >= 1 && repeats <= kMaxFixedRepeats);
+ return kFixedRepeatBase + repeats;
}
static int RepeatsForCode(int byte_code) {
- DCHECK(byte_code >= kConstantRepeat && byte_code <= 0x7f);
- return byte_code - 0x72;
+ DCHECK(byte_code > kFixedRepeatBase && byte_code <= kLastFixedRepeat);
+ return byte_code - kFixedRepeatBase;
}
+
+ // Hot objects are a small set of recently seen or back-referenced objects.
+ // They are represented by a single opcode to save space.
+ // We use 0x70..0x77 for 8 hot objects, and 0x78..0x7f to add skip.
+ static const int kHotObject = 0x70;
+ static const int kMaxHotObjectIndex = 0x77 - kHotObject;
+ static const int kHotObjectWithSkip = 0x78;
+ STATIC_ASSERT(HotObjectsList::kSize == kMaxHotObjectIndex + 1);
+ STATIC_ASSERT(0x7f - kHotObjectWithSkip == kMaxHotObjectIndex);
+ static const int kHotObjectIndexMask = 0x7;
+
static const int kRootArrayConstants = 0xa0;
- // 0xa0-0xbf Things from the first 32 elements of the root array.
+ // 0xa0-0xbf Things from the first 32 elements of the root array.
static const int kRootArrayNumberOfConstantEncodings = 0x20;
static int RootArrayConstantFromByteCode(int byte_code) {
return byte_code & 0x1f;
}
- static const int kNop = 0xf; // Do nothing, used for padding.
+ // Do nothing, used for padding.
+ static const int kNop = 0xf;
- static const int kNextChunk = 0x4f; // Move to next reserved chunk.
+ // Move to next reserved chunk.
+ static const int kNextChunk = 0x4f;
+
+ // A tag emitted at strategic points in the snapshot to delineate sections.
+ // If the deserializer does not find these at the expected moments then it
+ // is an indication that the snapshot and the VM do not fit together.
+ // Examine the build process for architecture, version or configuration
+ // mismatches.
+ static const int kSynchronize = 0x8f;
+
+ // Used for the source code of the natives, which is in the executable, but
+ // is referred to from external strings in the snapshot.
+ static const int kNativesStringResource = 0xcf;
static const int kAnyOldSpace = -1;
@@ -387,6 +445,11 @@
// Sentinel after a new object to indicate that double alignment is needed.
static const int kDoubleAlignmentSentinel = 0;
+
+ // Used as index for the attached reference representing the source object.
+ static const int kSourceObjectReference = 0;
+
+ HotObjectsList hot_objects_;
};
@@ -449,24 +512,10 @@
// Special handling for serialized code like hooking up internalized strings.
HeapObject* ProcessNewObjectFromSerializedCode(HeapObject* obj);
- Object* ProcessBackRefInSerializedCode(Object* obj);
// This returns the address of an object that has been described in the
// snapshot by chunk index and offset.
- HeapObject* GetBackReferencedObject(int space) {
- if (space == LO_SPACE) {
- uint32_t index = source_->GetInt();
- return deserialized_large_objects_[index];
- } else {
- BackReference back_reference(source_->GetInt());
- DCHECK(space < kNumberOfPreallocatedSpaces);
- uint32_t chunk_index = back_reference.chunk_index();
- DCHECK_LE(chunk_index, current_chunk_[space]);
- uint32_t chunk_offset = back_reference.chunk_offset();
- return HeapObject::FromAddress(reservations_[space][chunk_index].start +
- chunk_offset);
- }
- }
+ HeapObject* GetBackReferencedObject(int space);
// Cached current isolate.
Isolate* isolate_;
@@ -576,9 +625,17 @@
void PutRoot(int index, HeapObject* object, HowToCode how, WhereToPoint where,
int skip);
- void SerializeBackReference(BackReference back_reference,
- HowToCode how_to_code,
- WhereToPoint where_to_point, int skip);
+ // Returns true if the object was successfully serialized.
+ bool SerializeKnownObject(HeapObject* obj, HowToCode how_to_code,
+ WhereToPoint where_to_point, int skip);
+
+ inline void FlushSkip(int skip) {
+ if (skip != 0) {
+ sink_->Put(kSkip, "SkipFromSerializeObject");
+ sink_->PutInt(skip, "SkipDistanceFromSerializeObject");
+ }
+ }
+
void InitializeAllocators();
// This will return the space for an object.
static AllocationSpace SpaceOfObject(HeapObject* object);
@@ -716,6 +773,8 @@
Isolate* isolate, ScriptData* cached_data, Handle<String> source);
static const int kSourceObjectIndex = 0;
+ STATIC_ASSERT(kSourceObjectReference == kSourceObjectIndex);
+
static const int kCodeStubsBaseIndex = 1;
String* source() const {
diff --git a/src/snapshot-source-sink.h b/src/snapshot-source-sink.h
index 68901a1..398276f 100644
--- a/src/snapshot-source-sink.h
+++ b/src/snapshot-source-sink.h
@@ -24,7 +24,7 @@
bool HasMore() { return position_ < length_; }
- int Get() {
+ byte Get() {
DCHECK(position_ < length_);
return data_[position_++];
}
diff --git a/src/version.cc b/src/version.cc
index 67ba712..7fdf033 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,7 +34,7 @@
// system so their names cannot be changed without changing the scripts.
#define MAJOR_VERSION 3
#define MINOR_VERSION 31
-#define BUILD_NUMBER 38
+#define BUILD_NUMBER 39
#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc
index 0939e08..2aa4eaf 100644
--- a/test/cctest/test-parsing.cc
+++ b/test/cctest/test-parsing.cc
@@ -1673,16 +1673,9 @@
CcTest::i_isolate()->stack_guard()->SetStackLimit(
i::GetCurrentStackPosition() - 128 * 1024);
+ // Experimental feature flags should not go here; pass the flags as
+ // always_true_flags if the test needs them.
static const ParserFlag default_flags[] = {
- kAllowHarmonyArrowFunctions,
- kAllowHarmonyClasses,
- kAllowHarmonyNumericLiterals,
- kAllowHarmonyObjectLiterals,
- kAllowHarmonyScoping,
- kAllowHarmonyModules,
- kAllowHarmonyTemplates,
- kAllowHarmonySloppy,
- kAllowHarmonyUnicode,
kAllowLazy,
kAllowNatives,
};
@@ -1691,13 +1684,10 @@
flags = default_flags;
flags_len = arraysize(default_flags);
if (always_true_flags != NULL || always_false_flags != NULL) {
- // Remove always_true/false_flags from default_flags.
+ // Remove always_true/false_flags from default_flags (if present).
CHECK((always_true_flags != NULL) == (always_true_len > 0));
CHECK((always_false_flags != NULL) == (always_false_len > 0));
- CHECK(always_true_flags == NULL || always_true_len < flags_len);
- CHECK(always_false_flags == NULL || always_false_len < flags_len);
- generated_flags =
- new ParserFlag[flags_len - always_true_len - always_false_len];
+ generated_flags = new ParserFlag[flags_len + always_true_len];
int flag_index = 0;
for (int i = 0; i < flags_len; ++i) {
bool use_flag = true;
@@ -1709,7 +1699,6 @@
}
if (use_flag) generated_flags[flag_index++] = flags[i];
}
- CHECK(flag_index == flags_len - always_true_len - always_false_len);
flags_len = flag_index;
flags = generated_flags;
}
@@ -1899,14 +1888,8 @@
NULL
};
- static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
- RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags,
- arraysize(always_flags));
-
- static const ParserFlag classes_flags[] = {
- kAllowHarmonyArrowFunctions, kAllowHarmonyClasses, kAllowHarmonyScoping};
- RunParserSyncTest(context_data, statement_data, kError, NULL, 0,
- classes_flags, arraysize(classes_flags));
+ RunParserSyncTest(context_data, statement_data, kError);
+ RunParserSyncTest(context_data, statement_data, kError);
}
diff --git a/test/unittests/compiler/machine-operator-reducer-unittest.cc b/test/unittests/compiler/machine-operator-reducer-unittest.cc
index 5f9f113..3e47ce8 100644
--- a/test/unittests/compiler/machine-operator-reducer-unittest.cc
+++ b/test/unittests/compiler/machine-operator-reducer-unittest.cc
@@ -532,9 +532,10 @@
TEST_F(MachineOperatorReducerTest, Word32AndWithInt32AddAndConstant) {
Node* const p0 = Parameter(0);
+ Node* const p1 = Parameter(1);
- TRACED_FOREACH(int32_t, k, kInt32Values) {
- TRACED_FORRANGE(int32_t, l, 1, 31) {
+ TRACED_FORRANGE(int32_t, l, 1, 31) {
+ TRACED_FOREACH(int32_t, k, kInt32Values) {
// (x + (K << L)) & (-1 << L) => (x & (-1 << L)) + (K << L)
Reduction const r = Reduce(graph()->NewNode(
machine()->Word32And(),
@@ -545,6 +546,24 @@
IsInt32Add(IsWord32And(p0, IsInt32Constant(-1 << l)),
IsInt32Constant(k << l)));
}
+
+ Node* s1 = graph()->NewNode(machine()->Word32Shl(), p1, Int32Constant(l));
+
+ // (y << L + x) & (-1 << L) => (x & (-1 << L)) + y << L
+ Reduction const r1 = Reduce(graph()->NewNode(
+ machine()->Word32And(), graph()->NewNode(machine()->Int32Add(), s1, p0),
+ Int32Constant(-1 << l)));
+ ASSERT_TRUE(r1.Changed());
+ EXPECT_THAT(r1.replacement(),
+ IsInt32Add(IsWord32And(p0, IsInt32Constant(-1 << l)), s1));
+
+ // (x + y << L) & (-1 << L) => (x & (-1 << L)) + y << L
+ Reduction const r2 = Reduce(graph()->NewNode(
+ machine()->Word32And(), graph()->NewNode(machine()->Int32Add(), p0, s1),
+ Int32Constant(-1 << l)));
+ ASSERT_TRUE(r2.Changed());
+ EXPECT_THAT(r2.replacement(),
+ IsInt32Add(IsWord32And(p0, IsInt32Constant(-1 << l)), s1));
}
}