66f1611fee
Sometimes compiler omits type checks for the 'await' and 'return from async' by relying on the fact that certain classes cannot hold instances of Future. In JIT mode, the property 'class-can-be-Future' may change when a new class is loaded dynamically (e.g. through IsolateMirror.loadUri). In such a case, the generated code assuming that certain class cannot be Future should be correctly deoptimized. This CL implements this deoptimization by adding such classes into the list of CHA guarded classes. TEST=runtime/tests/vm/dart/await_type_check_with_dynamic_loading_test.dart Change-Id: Ib3a3768d073e8562b794186e72cb9d61e9f496fa Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/309822 Reviewed-by: Martin Kustermann <kustermann@google.com> Commit-Queue: Alexander Markov <alexmarkov@google.com>
114 lines
4.1 KiB
C++
114 lines
4.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.
|
|
|
|
#ifndef RUNTIME_VM_COMPILER_CHA_H_
|
|
#define RUNTIME_VM_COMPILER_CHA_H_
|
|
|
|
#if defined(DART_PRECOMPILED_RUNTIME)
|
|
#error "AOT runtime should not use compiler sources (including header files)"
|
|
#endif // defined(DART_PRECOMPILED_RUNTIME)
|
|
|
|
#include "vm/allocation.h"
|
|
#include "vm/growable_array.h"
|
|
#include "vm/thread.h"
|
|
|
|
namespace dart {
|
|
|
|
class Class;
|
|
class CompileType;
|
|
class Function;
|
|
template <typename T>
|
|
class ZoneGrowableArray;
|
|
class String;
|
|
|
|
class CHA : public ValueObject {
|
|
public:
|
|
explicit CHA(Thread* thread)
|
|
: thread_(thread), guarded_classes_(thread->zone(), 1) {}
|
|
|
|
// Returns true if the class has subclasses.
|
|
static bool HasSubclasses(const Class& cls);
|
|
bool HasSubclasses(intptr_t cid) const;
|
|
|
|
// Collect the concrete subclasses of 'cls' into 'class_ids'. Return true if
|
|
// the result is valid (may be invalid because we don't track the subclasses
|
|
// of classes allocated in the VM isolate or class Object).
|
|
static bool ConcreteSubclasses(const Class& cls,
|
|
GrowableArray<intptr_t>* class_ids);
|
|
|
|
// Return true if the class is implemented by some other class that is not a
|
|
// subclass.
|
|
static bool IsImplemented(const Class& cls);
|
|
|
|
// Return true if there is only one concrete class that implements
|
|
// 'interface'.
|
|
static bool HasSingleConcreteImplementation(const Class& interface,
|
|
intptr_t* implementation_cid);
|
|
|
|
// Return true if variable of static type based on [cls] may hold
|
|
// a Future instance.
|
|
static bool ClassCanBeFuture(const Class& cls);
|
|
|
|
// Returns true if any subclass of 'cls' contains the function.
|
|
// If no override was found subclass_count would contain total count of
|
|
// finalized subclasses that CHA looked at.
|
|
// This count will be used to validate CHA decision before installing
|
|
// optimized code compiled in background.
|
|
bool HasOverride(const Class& cls,
|
|
const String& function_name,
|
|
intptr_t* subclass_count);
|
|
|
|
// Adds class 'cls' to the list of guarded classes.
|
|
// Deoptimization occurs if any of those classes gets subclassed or
|
|
// implemented through later loaded/finalized libraries. Only classes that
|
|
// were used for CHA optimizations are added.
|
|
void AddToGuardedClassesForSubclassCount(const Class& cls,
|
|
intptr_t subclass_count);
|
|
void AddToGuardedClassesForImplementorCid(const Class& cls,
|
|
intptr_t implementor_cid);
|
|
void AddToGuardedClassesToTrackFuture(const Class& cls);
|
|
|
|
// When compiling in background we need to check that no new finalized
|
|
// subclasses were added to guarded classes.
|
|
bool IsConsistentWithCurrentHierarchy() const;
|
|
|
|
void RegisterDependencies(const Code& code) const;
|
|
|
|
// Used for testing.
|
|
bool IsGuardedClass(intptr_t cid) const;
|
|
|
|
private:
|
|
void AddToGuardedClasses(const Class& cls,
|
|
intptr_t subclass_count,
|
|
intptr_t implementor_cid,
|
|
bool track_future);
|
|
|
|
Thread* thread_;
|
|
|
|
struct GuardedClassInfo {
|
|
Class* cls;
|
|
|
|
// Number of finalized subclasses that this class had at the moment
|
|
// when CHA made the first decision based on this class.
|
|
// Used to validate correctness of background compilation: if
|
|
// any subclasses were added we will discard compiled code.
|
|
intptr_t subclass_count;
|
|
|
|
// Value of implementor_cid that this class had at the moment
|
|
// when CHA made the first decision based on this class.
|
|
// Used to validate correctness of background compilation: if
|
|
// any implementors were added we will discard compiled code.
|
|
intptr_t implementor_cid;
|
|
|
|
// Whether we should track that this class cannot be future.
|
|
bool track_future;
|
|
};
|
|
|
|
GrowableArray<GuardedClassInfo> guarded_classes_;
|
|
};
|
|
|
|
} // namespace dart
|
|
|
|
#endif // RUNTIME_VM_COMPILER_CHA_H_
|