// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #include "vm/cha.h" #include "vm/class_table.h" #include "vm/flags.h" #include "vm/freelist.h" #include "vm/object.h" #include "vm/raw_object.h" #include "vm/visitor.h" namespace dart { bool CHA::HasSubclasses(intptr_t cid) { ASSERT(cid >= kInstanceCid); const ClassTable& class_table = *Isolate::Current()->class_table(); const Class& cls = Class::Handle(class_table.At(cid)); ASSERT(!cls.IsNull()); if (cls.IsObjectClass()) { // Class Object has subclasses, although we do not keep track of them. return true; } const GrowableObjectArray& cls_direct_subclasses = GrowableObjectArray::Handle(cls.direct_subclasses()); return !cls_direct_subclasses.IsNull() && (cls_direct_subclasses.Length() > 0); } // Returns true if the given array of cids contains the given cid. static bool ContainsCid(ZoneGrowableArray* cids, intptr_t cid) { for (intptr_t i = 0; i < cids->length(); i++) { if ((*cids)[i] == cid) { return true; } } return false; } // Recursively collect direct and indirect subclass ids of cls. static void CollectSubclassIds(ZoneGrowableArray* cids, const Class& cls) { const GrowableObjectArray& cls_direct_subclasses = GrowableObjectArray::Handle(cls.direct_subclasses()); if (cls_direct_subclasses.IsNull()) { return; } Class& direct_subclass = Class::Handle(); for (intptr_t i = 0; i < cls_direct_subclasses.Length(); i++) { direct_subclass ^= cls_direct_subclasses.At(i); intptr_t direct_subclass_id = direct_subclass.id(); if (!ContainsCid(cids, direct_subclass_id)) { cids->Add(direct_subclass_id); CollectSubclassIds(cids, direct_subclass); } } } ZoneGrowableArray* CHA::GetSubclassIdsOf(intptr_t cid) { ASSERT(cid > kInstanceCid); const ClassTable& class_table = *Isolate::Current()->class_table(); const Class& cls = Class::Handle(class_table.At(cid)); ASSERT(!cls.IsNull()); ZoneGrowableArray* ids = new ZoneGrowableArray(); CollectSubclassIds(ids, cls); return ids; } bool CHA::HasOverride(const Class& cls, const String& function_name) { const GrowableObjectArray& cls_direct_subclasses = GrowableObjectArray::Handle(cls.direct_subclasses()); // Subclasses of Object are not tracked by CHA. Safely assume that overrides // exist. if (cls.IsObjectClass()) return true; if (cls_direct_subclasses.IsNull()) { return false; } Class& direct_subclass = Class::Handle(); for (intptr_t i = 0; i < cls_direct_subclasses.Length(); i++) { direct_subclass ^= cls_direct_subclasses.At(i); // Unfinalized classes are treated as non-existent for CHA purposes, // as that means that no instance of that class exists at runtime. if (direct_subclass.is_finalized() && (direct_subclass.LookupDynamicFunction(function_name) != Function::null())) { return true; } if (HasOverride(direct_subclass, function_name)) { return true; } } return false; } ZoneGrowableArray* CHA::GetNamedInstanceFunctionsOf( const ZoneGrowableArray& cids, const String& function_name) { ASSERT(!function_name.IsNull()); const ClassTable& class_table = *Isolate::Current()->class_table(); ZoneGrowableArray* functions = new ZoneGrowableArray(); Class& cls = Class::Handle(); Function& cls_function = Function::Handle(); for (intptr_t i = 0; i < cids.length(); i++) { const intptr_t cid = cids[i]; ASSERT(cid > kInstanceCid); cls = class_table.At(cid); cls_function = cls.LookupDynamicFunction(function_name); if (!cls_function.IsNull()) { functions->Add(&Function::ZoneHandle(cls_function.raw())); } } return functions; } ZoneGrowableArray* CHA::GetOverridesOf(const Function& function) { ASSERT(!function.IsNull()); ASSERT(function.IsDynamicFunction()); const Class& function_owner = Class::Handle(function.Owner()); const String& function_name = String::Handle(function.name()); ZoneGrowableArray* cids = new ZoneGrowableArray(); CollectSubclassIds(cids, function_owner); return GetNamedInstanceFunctionsOf(*cids, function_name); } } // namespace dart