Reset most ICs by returning to the canonical empty data arrays.

We can't do this for the binary operators because they must be writable and not shared for the fast Smi op stubs to record invocation counts.

Suspected to help avoid races, see Issue #26946.

Also remove some dead code and avoid TLS.

R=fschneider@google.com

Review URL: https://codereview.chromium.org/2217733002 .
This commit is contained in:
Ryan Macnak 2016-08-04 17:41:03 -07:00
parent ba0f803fbe
commit 19716b351a
4 changed files with 53 additions and 54 deletions

View file

@ -1366,8 +1366,12 @@ ObjectStore* IsolateReloadContext::object_store() {
void IsolateReloadContext::ResetUnoptimizedICsOnStack() {
Code& code = Code::Handle();
Function& function = Function::Handle();
Thread* thread = Thread::Current();
StackZone stack_zone(thread);
Zone* zone = stack_zone.GetZone();
Code& code = Code::Handle(zone);
Function& function = Function::Handle(zone);
DartFrameIterator iterator;
StackFrame* frame = iterator.NextFrame();
while (frame != NULL) {
@ -1379,9 +1383,9 @@ void IsolateReloadContext::ResetUnoptimizedICsOnStack() {
function = code.function();
code = function.unoptimized_code();
ASSERT(!code.IsNull());
code.ResetICDatas();
code.ResetICDatas(zone);
} else {
code.ResetICDatas();
code.ResetICDatas(zone);
}
frame = iterator.NextFrame();
}
@ -1400,13 +1404,15 @@ void IsolateReloadContext::ResetMegamorphicCaches() {
class MarkFunctionsForRecompilation : public ObjectVisitor {
public:
MarkFunctionsForRecompilation(Isolate* isolate,
IsolateReloadContext* reload_context)
IsolateReloadContext* reload_context,
Zone* zone)
: ObjectVisitor(),
handle_(Object::Handle()),
owning_class_(Class::Handle()),
owning_lib_(Library::Handle()),
code_(Code::Handle()),
reload_context_(reload_context) {
handle_(Object::Handle(zone)),
owning_class_(Class::Handle(zone)),
owning_lib_(Library::Handle(zone)),
code_(Code::Handle(zone)),
reload_context_(reload_context),
zone_(zone) {
}
virtual void VisitObject(RawObject* obj) {
@ -1460,7 +1466,7 @@ class MarkFunctionsForRecompilation : public ObjectVisitor {
ASSERT(!code_.IsNull());
// We are preserving the unoptimized code, fill all ICData arrays with
// the sentinel values so that we have no stale type feedback.
code_.ResetICDatas();
code_.ResetICDatas(zone_);
}
bool IsFromDirtyLibrary(const Function& func) {
@ -1474,15 +1480,19 @@ class MarkFunctionsForRecompilation : public ObjectVisitor {
Library& owning_lib_;
Code& code_;
IsolateReloadContext* reload_context_;
Zone* zone_;
};
void IsolateReloadContext::MarkAllFunctionsForRecompilation() {
TIMELINE_SCOPE(MarkAllFunctionsForRecompilation);
TIR_Print("---- MARKING ALL FUNCTIONS FOR RECOMPILATION\n");
Thread* thread = Thread::Current();
StackZone stack_zone(thread);
Zone* zone = stack_zone.GetZone();
NoSafepointScope no_safepoint;
HeapIterationScope heap_iteration_scope;
MarkFunctionsForRecompilation visitor(isolate_, this);
MarkFunctionsForRecompilation visitor(isolate_, this, zone);
isolate_->heap()->VisitObjects(&visitor);
}

View file

@ -12973,10 +12973,6 @@ void ICData::DebugDump() const {
}
void ICData::ValidateSentinelLocations() const {
}
void ICData::AddReceiverCheck(intptr_t receiver_class_id,
const Function& target,
intptr_t count) const {
@ -13416,12 +13412,10 @@ RawArray* ICData::NewNonCachedEmptyICDataArray(intptr_t num_args_tested) {
}
RawArray* ICData::NewEmptyICDataArray(intptr_t num_args_tested) {
RawArray* ICData::CachedEmptyICDataArray(intptr_t num_args_tested) {
ASSERT(num_args_tested >= 0);
if (num_args_tested < kCachedICDataArrayCount) {
return cached_icdata_arrays_[num_args_tested];
}
return NewNonCachedEmptyICDataArray(num_args_tested);
ASSERT(num_args_tested < kCachedICDataArrayCount);
return cached_icdata_arrays_[num_args_tested];
}
@ -13468,16 +13462,6 @@ bool ICData::IsImmutable() const {
}
void ICData::ResetData() const {
// Number of array elements in one test entry.
intptr_t len = TestEntryLength();
// IC data array must be null terminated (sentinel entry).
const Array& ic_data = Array::Handle(Array::New(len, Heap::kOld));
set_ic_data_array(ic_data);
WriteSentinel(ic_data, len);
}
RawICData* ICData::New() {
ICData& result = ICData::Handle();
{
@ -13513,7 +13497,7 @@ RawICData* ICData::New(const Function& owner,
num_args_tested,
is_static_call));
result.set_ic_data_array(
Array::Handle(zone, NewEmptyICDataArray(num_args_tested)));
Array::Handle(zone, CachedEmptyICDataArray(num_args_tested)));
return result.raw();
}

View file

@ -1853,8 +1853,7 @@ class ICData : public Object {
bool IsImmutable() const;
void Reset() const;
void ResetData() const;
void Reset(Zone* zone) const;
// Note: only deopts with reasons before Unknown in this list are recorded in
// the ICData. All other reasons are used purely for informational messages
@ -1960,7 +1959,6 @@ class ICData : public Object {
RawArray* FindFreeIndex(intptr_t* index) const;
void DebugDump() const;
void ValidateSentinelLocations() const;
// Returns true if this is a two arg smi operation.
bool AddSmiSmiCheckForFastSmiStubs() const;
@ -2133,7 +2131,7 @@ class ICData : public Object {
intptr_t TestEntryLength() const;
static RawArray* NewNonCachedEmptyICDataArray(intptr_t num_args_tested);
static RawArray* NewEmptyICDataArray(intptr_t num_args_tested);
static RawArray* CachedEmptyICDataArray(intptr_t num_args_tested);
static RawICData* NewDescriptor(Zone* zone,
const Function& owner,
const String& target_name,
@ -4504,7 +4502,7 @@ class Code : public Object {
// Used during reloading (see object_reload.cc). Calls Reset on all ICDatas
// that are embedded inside the Code object.
void ResetICDatas() const;
void ResetICDatas(Zone* zone) const;
TokenPosition GetTokenPositionAt(intptr_t offset) const;

View file

@ -57,7 +57,7 @@ void Function::ZeroEdgeCounters() const {
}
void Code::ResetICDatas() const {
void Code::ResetICDatas(Zone* zone) const {
// Iterate over the Code's object pool and reset all ICDatas.
#ifdef TARGET_ARCH_IA32
// IA32 does not have an object pool, but, we can iterate over all
@ -65,10 +65,10 @@ void Code::ResetICDatas() const {
if (!is_alive()) {
return;
}
const Instructions& instrs = Instructions::Handle(instructions());
const Instructions& instrs = Instructions::Handle(zone, instructions());
ASSERT(!instrs.IsNull());
uword base_address = instrs.EntryPoint();
Object& object = Object::Handle();
Object& object = Object::Handle(zone);
intptr_t offsets_length = pointer_offsets_length();
const int32_t* offsets = raw_ptr()->data();
for (intptr_t i = 0; i < offsets_length; i++) {
@ -85,8 +85,8 @@ void Code::ResetICDatas() const {
}
}
#else
const ObjectPool& pool = ObjectPool::Handle(object_pool());
Object& object = Object::Handle();
const ObjectPool& pool = ObjectPool::Handle(zone, object_pool());
Object& object = Object::Handle(zone);
ASSERT(!pool.IsNull());
for (intptr_t i = 0; i < pool.Length(); i++) {
ObjectPool::EntryType entry_type = pool.InfoAt(i);
@ -95,7 +95,7 @@ void Code::ResetICDatas() const {
}
object = pool.ObjectAt(i);
if (object.IsICData()) {
ICData::Cast(object).Reset();
ICData::Cast(object).Reset(zone);
}
}
#endif
@ -679,24 +679,24 @@ void Library::CheckReload(const Library& replacement,
static const Function* static_call_target = NULL;
void ICData::Reset() const {
void ICData::Reset(Zone* zone) const {
if (is_static_call()) {
const Function& old_target = Function::Handle(GetTargetAt(0));
const Function& old_target = Function::Handle(zone, GetTargetAt(0));
if (old_target.IsNull()) {
FATAL("old_target is NULL.\n");
}
static_call_target = &old_target;
const String& selector = String::Handle(old_target.name());
Function& new_target = Function::Handle();
const String& selector = String::Handle(zone, old_target.name());
Function& new_target = Function::Handle(zone);
if (!old_target.is_static()) {
if (old_target.kind() == RawFunction::kConstructor) {
return; // Super constructor call.
}
Function& caller = Function::Handle();
Function& caller = Function::Handle(zone);
caller ^= Owner();
ASSERT(!caller.is_static());
Class& cls = Class::Handle(caller.Owner());
Class& cls = Class::Handle(zone, caller.Owner());
if (cls.raw() == old_target.Owner()) {
// Dispatcher.
if (caller.IsImplicitClosureFunction()) {
@ -707,7 +707,7 @@ void ICData::Reset() const {
return;
}
const Function& caller_parent =
Function::Handle(caller.parent_function());
Function::Handle(zone, caller.parent_function());
if (!caller_parent.IsNull()) {
if (caller_parent.kind() == RawFunction::kInvokeFieldDispatcher) {
return; // Call-through-getter.
@ -730,23 +730,30 @@ void ICData::Reset() const {
}
} else {
// This can be incorrect if the call site was an unqualified invocation.
const Class& cls = Class::Handle(old_target.Owner());
const Class& cls = Class::Handle(zone, old_target.Owner());
new_target = cls.LookupStaticFunction(selector);
}
const Array& args_desc_array = Array::Handle(arguments_descriptor());
const Array& args_desc_array = Array::Handle(zone, arguments_descriptor());
ArgumentsDescriptor args_desc(args_desc_array);
if (new_target.IsNull() ||
!new_target.AreValidArguments(args_desc, NULL)) {
// TODO(rmacnak): Patch to a NSME stub.
VTIR_Print("Cannot rebind static call to %s from %s\n",
old_target.ToCString(),
Object::Handle(Owner()).ToCString());
Object::Handle(zone, Owner()).ToCString());
return;
}
ClearAndSetStaticTarget(new_target);
} else {
ClearWithSentinel();
intptr_t num_args = NumArgsTested();
if (num_args == 2) {
ClearWithSentinel();
} else {
const Array& data_array =
Array::Handle(zone, CachedEmptyICDataArray(num_args));
set_ic_data_array(data_array);
}
}
}