6bb73bd2e4
CHA::HasOverride skips non-finalized classes when looking for overrides which means that we will install incorrect code if some subclass with an override was finalized while compilation was in progress. To catch situations like this we record the number of finalized subclasses that class had when CHA made the first negative decision about it (e.g. that it has no subclasses or that it has no overrides for some function) and before installing the code we check that number of subclasses matches. Additionally renamed "leaf classes" to "guarded classes" because those classes are not necessarily leaf. R=fschneider@google.com BUG= Review URL: https://codereview.chromium.org/2002583002 .
100 lines
3.1 KiB
C++
100 lines
3.1 KiB
C++
// 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 "platform/assert.h"
|
|
#include "vm/cha.h"
|
|
#include "vm/class_finalizer.h"
|
|
#include "vm/globals.h"
|
|
#include "vm/symbols.h"
|
|
#include "vm/unit_test.h"
|
|
|
|
namespace dart {
|
|
|
|
|
|
TEST_CASE(ClassHierarchyAnalysis) {
|
|
const char* kScriptChars =
|
|
"class A {"
|
|
" foo() { }"
|
|
" bar() { }"
|
|
"}\n"
|
|
"class B extends A {"
|
|
"}\n"
|
|
"class C extends B {"
|
|
" foo() { }"
|
|
"}\n"
|
|
"class D extends A {"
|
|
" foo() { }"
|
|
" bar() { }"
|
|
"}\n";
|
|
|
|
TestCase::LoadTestScript(kScriptChars, NULL);
|
|
EXPECT(ClassFinalizer::ProcessPendingClasses());
|
|
const String& name = String::Handle(String::New(TestCase::url()));
|
|
const Library& lib = Library::Handle(Library::LookupLibrary(thread, name));
|
|
EXPECT(!lib.IsNull());
|
|
|
|
const Class& class_a = Class::Handle(
|
|
lib.LookupClass(String::Handle(Symbols::New(thread, "A"))));
|
|
EXPECT(!class_a.IsNull());
|
|
|
|
const Class& class_b = Class::Handle(
|
|
lib.LookupClass(String::Handle(Symbols::New(thread, "B"))));
|
|
EXPECT(!class_b.IsNull());
|
|
|
|
const Class& class_c = Class::Handle(
|
|
lib.LookupClass(String::Handle(Symbols::New(thread, "C"))));
|
|
EXPECT(!class_c.IsNull());
|
|
|
|
const Class& class_d = Class::Handle(
|
|
lib.LookupClass(String::Handle(Symbols::New(thread, "D"))));
|
|
EXPECT(!class_d.IsNull());
|
|
|
|
const String& function_foo_name = String::Handle(String::New("foo"));
|
|
const String& function_bar_name = String::Handle(String::New("bar"));
|
|
|
|
const Function& class_a_foo =
|
|
Function::Handle(class_a.LookupDynamicFunction(function_foo_name));
|
|
EXPECT(!class_a_foo.IsNull());
|
|
|
|
const Function& class_a_bar =
|
|
Function::Handle(class_a.LookupDynamicFunction(function_bar_name));
|
|
EXPECT(!class_a_bar.IsNull());
|
|
|
|
const Function& class_c_foo =
|
|
Function::Handle(class_c.LookupDynamicFunction(function_foo_name));
|
|
EXPECT(!class_c_foo.IsNull());
|
|
|
|
const Function& class_d_foo =
|
|
Function::Handle(class_d.LookupDynamicFunction(function_foo_name));
|
|
EXPECT(!class_d_foo.IsNull());
|
|
|
|
const Function& class_d_bar =
|
|
Function::Handle(class_d.LookupDynamicFunction(function_bar_name));
|
|
EXPECT(!class_d_bar.IsNull());
|
|
|
|
CHA cha(Thread::Current());
|
|
|
|
EXPECT(cha.HasSubclasses(kInstanceCid));
|
|
EXPECT(!cha.HasSubclasses(kSmiCid));
|
|
EXPECT(!cha.HasSubclasses(kNullCid));
|
|
|
|
EXPECT(CHA::HasSubclasses(class_a));
|
|
EXPECT(CHA::HasSubclasses(class_b));
|
|
EXPECT(!CHA::HasSubclasses(class_c));
|
|
cha.AddToGuardedClasses(class_c, /*subclass_count=*/0);
|
|
EXPECT(!CHA::HasSubclasses(class_d));
|
|
cha.AddToGuardedClasses(class_d, /*subclass_count=*/0);
|
|
|
|
EXPECT(!cha.IsGuardedClass(class_a.id()));
|
|
EXPECT(!cha.IsGuardedClass(class_b.id()));
|
|
EXPECT(cha.IsGuardedClass(class_c.id()));
|
|
EXPECT(cha.IsGuardedClass(class_d.id()));
|
|
|
|
const Class& closure_class =
|
|
Class::Handle(Isolate::Current()->object_store()->closure_class());
|
|
EXPECT(!cha.HasSubclasses(closure_class.id()));
|
|
}
|
|
|
|
} // namespace dart
|