#define V8_MAJOR_VERSION 4
#define V8_MINOR_VERSION 4
#define V8_BUILD_NUMBER 63
-#define V8_PATCH_LEVEL 26
+#define V8_PATCH_LEVEL 30
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
size_t idle_time_in_ms, size_t new_space_size, size_t used_new_space_size,
size_t scavenge_speed_in_bytes_per_ms,
size_t new_space_allocation_throughput_in_bytes_per_ms) {
+ if (idle_time_in_ms >= kMinBackgroundIdleTime) {
+ // It is better to do full GC for the background tab.
+ return false;
+ }
size_t new_space_allocation_limit =
kMaxScheduledIdleTime * scavenge_speed_in_bytes_per_ms;
}
-GCIdleTimeAction GCIdleTimeHandler::NothingOrDone() {
+GCIdleTimeAction GCIdleTimeHandler::NothingOrDone(double idle_time_in_ms) {
+ if (idle_time_in_ms >= kMinBackgroundIdleTime) {
+ return GCIdleTimeAction::Nothing();
+ }
if (idle_times_which_made_no_progress_per_mode_ >=
kMaxNoProgressIdleTimesPerMode) {
return GCIdleTimeAction::Done();
HeapState heap_state) {
Mode next_mode = NextMode(heap_state);
+ // Immediately go from reduce latency to reduce memory mode in
+ // background tab.
+ if (next_mode == kReduceLatency &&
+ idle_time_in_ms >= kMinBackgroundIdleTime) {
+ next_mode = kReduceMemory;
+ }
+
if (next_mode != mode_) {
mode_ = next_mode;
ResetCounters();
if (heap_state.sweeping_completed) {
return GCIdleTimeAction::FinalizeSweeping();
} else {
- return NothingOrDone();
+ return NothingOrDone(idle_time_in_ms);
}
}
if (heap_state.incremental_marking_stopped &&
!heap_state.can_start_incremental_marking && !reduce_memory) {
- return NothingOrDone();
+ return NothingOrDone(idle_time_in_ms);
}
size_t step_size = EstimateMarkingStepSize(
size_t scavenger_speed_in_bytes_per_ms,
size_t new_space_allocation_throughput_in_bytes_per_ms);
+ bool ShouldGrowHeapSlowly() {
+ return mode() == kDone;
+ }
+
enum Mode { kReduceLatency, kReduceMemory, kDone };
Mode mode() { return mode_; }
Mode NextMode(const HeapState& heap_state);
GCIdleTimeAction Action(double idle_time_in_ms, const HeapState& heap_state,
bool reduce_memory);
- GCIdleTimeAction NothingOrDone();
+ GCIdleTimeAction NothingOrDone(double idle_time_in_ms);
int idle_mark_compacts_;
int mark_compacts_;
factor = min_factor;
}
+ const double kConservativeHeapGrowingFactor = 1.3;
+ if (gc_idle_time_handler_.ShouldGrowHeapSlowly()) {
+ factor = Min(factor, kConservativeHeapGrowingFactor);
+ }
+
+
idle_factor = Min(factor, idle_max_factor);
old_generation_allocation_limit_ =
HValue* object_size_constant = Add<HConstant>(initial_map->instance_size());
PretenureFlag pretenure_flag = NOT_TENURED;
- Handle<AllocationSite> current_site(*site_context->current(), isolate());
+ Handle<AllocationSite> top_site(*site_context->top(), isolate());
if (FLAG_allocation_site_pretenuring) {
- pretenure_flag = current_site->GetPretenureMode();
- top_info()->dependencies()->AssumeTenuringDecision(current_site);
+ pretenure_flag = top_site->GetPretenureMode();
}
+ Handle<AllocationSite> current_site(*site_context->current(), isolate());
+ if (*top_site == *current_site) {
+ // We install a dependency for pretenuring only on the outermost literal.
+ top_info()->dependencies()->AssumeTenuringDecision(top_site);
+ }
top_info()->dependencies()->AssumeTransitionStable(current_site);
HInstruction* object = Add<HAllocate>(
- object_size_constant, type, pretenure_flag, instance_type, current_site);
+ object_size_constant, type, pretenure_flag, instance_type, top_site);
// If allocation folding reaches Page::kMaxRegularHeapObjectSize the
// elements array may not get folded into the object. Hence, we set the
HValue* object_elements_size = Add<HConstant>(elements_size);
InstanceType instance_type = boilerplate_object->HasFastDoubleElements()
? FIXED_DOUBLE_ARRAY_TYPE : FIXED_ARRAY_TYPE;
- object_elements =
- Add<HAllocate>(object_elements_size, HType::HeapObject(),
- pretenure_flag, instance_type, current_site);
+ object_elements = Add<HAllocate>(object_elements_size, HType::HeapObject(),
+ pretenure_flag, instance_type, top_site);
BuildEmitElements(boilerplate_object, elements, object_elements,
site_context);
Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
if (representation.IsDouble()) {
// Allocate a HeapNumber box and store the value into it.
HValue* heap_number_constant = Add<HConstant>(HeapNumber::kSize);
- // This heap number alloc does not have a corresponding
- // AllocationSite. That is okay because
- // 1) it's a child object of another object with a valid allocation site
- // 2) we can just use the mode of the parent object for pretenuring
HInstruction* double_box =
Add<HAllocate>(heap_number_constant, HType::HeapObject(),
pretenure_flag, MUTABLE_HEAP_NUMBER_TYPE);
}
}
- int inobject_props = object->map()->inobject_properties();
+ Handle<Map> old_map(object->map(), isolate);
+
+ int inobject_props = old_map->inobject_properties();
// Allocate new map.
- Handle<Map> new_map = Map::CopyDropDescriptors(handle(object->map()));
+ Handle<Map> new_map = Map::CopyDropDescriptors(old_map);
new_map->set_dictionary_map(false);
- if (object->map()->is_prototype_map()) {
+ if (old_map->is_prototype_map() && FLAG_track_prototype_users) {
DCHECK(new_map->is_prototype_map());
- new_map->set_prototype_info(object->map()->prototype_info());
- object->map()->set_prototype_info(Smi::FromInt(0));
+
+ Object* maybe_old_prototype = old_map->prototype();
+ if (maybe_old_prototype->IsJSObject()) {
+ Handle<JSObject> old_prototype(JSObject::cast(maybe_old_prototype));
+ bool was_registered =
+ JSObject::UnregisterPrototypeUser(old_prototype, old_map);
+ if (was_registered) {
+ JSObject::LazyRegisterPrototypeUser(new_map, isolate);
+ }
+ }
+ new_map->set_prototype_info(old_map->prototype_info());
+ old_map->set_prototype_info(Smi::FromInt(0));
if (FLAG_trace_prototype_users) {
PrintF("Moving prototype_info %p from map %p to map %p.\n",
reinterpret_cast<void*>(new_map->prototype_info()),
- reinterpret_cast<void*>(object->map()),
+ reinterpret_cast<void*>(*old_map),
reinterpret_cast<void*>(*new_map));
}
}
#if TRACE_MAPS
if (FLAG_trace_maps) {
PrintF("[TraceMaps: SlowToFast from= %p to= %p reason= %s ]\n",
- reinterpret_cast<void*>(object->map()),
- reinterpret_cast<void*>(*new_map), reason);
+ reinterpret_cast<void*>(*old_map), reinterpret_cast<void*>(*new_map),
+ reason);
}
#endif
(v8::base::TimeTicks::HighResolutionNow().ToInternalValue() /
static_cast<double>(v8::base::Time::kMicrosecondsPerSecond)) +
IdlePauseInSeconds);
+ if (CcTest::heap()->mark_compact_collector()->sweeping_in_progress()) {
+ CcTest::heap()->mark_compact_collector()->EnsureSweepingCompleted();
+ }
}
intptr_t final_size = CcTest::heap()->SizeOfObjects();
CHECK(finished);
--- /dev/null
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Parent() {}
+
+function Child() {}
+Child.prototype = new Parent();
+var child = new Child();
+
+function crash() {
+ return child.__proto__;
+}
+
+crash();
+crash();
+
+// Trigger a fast->slow->fast dance of Parent.prototype's map...
+Parent.prototype.__defineSetter__("foo", function() { print("A"); });
+Parent.prototype.__defineSetter__("foo", function() { print("B"); });
+// ...and collect more type feedback.
+crash();
+
+// Now modify the prototype chain. The right cell fails to get invalidated.
+delete Object.prototype.__proto__;
+crash();