You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

203 lines
7.9 KiB

/* Copyright (C) 2017 The Android Open Source Project
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This file implements interfaces from the file jvmti.h. This implementation
* is licensed under the same terms as the file jvmti.h. The
* copyright and license information for the file jvmti.h follows.
*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#ifndef ART_OPENJDKJVMTI_DEOPT_MANAGER_H_
#define ART_OPENJDKJVMTI_DEOPT_MANAGER_H_
#include <atomic>
#include <iosfwd>
#include <unordered_map>
#include "base/mutex.h"
#include "runtime_callbacks.h"
#include <jvmti.h>
namespace art {
class ArtMethod;
class ScopedObjectAccessUnchecked;
namespace mirror {
class Class;
} // namespace mirror
} // namespace art
namespace openjdkjvmti {
class DeoptManager;
struct JvmtiMethodInspectionCallback : public art::MethodInspectionCallback {
public:
explicit JvmtiMethodInspectionCallback(DeoptManager* manager) : manager_(manager) {}
bool IsMethodBeingInspected(art::ArtMethod* method)
override REQUIRES_SHARED(art::Locks::mutator_lock_);
bool IsMethodSafeToJit(art::ArtMethod* method)
override REQUIRES_SHARED(art::Locks::mutator_lock_);
bool MethodNeedsDebugVersion(art::ArtMethod* method)
override REQUIRES_SHARED(art::Locks::mutator_lock_);
private:
DeoptManager* manager_;
};
class ScopedDeoptimizationContext;
class DeoptManager {
public:
DeoptManager();
void Setup();
void Shutdown();
void DumpDeoptInfo(art::Thread* self, std::ostream& stream);
void RemoveDeoptimizationRequester() REQUIRES(!deoptimization_status_lock_,
!art::Roles::uninterruptible_);
void AddDeoptimizationRequester() REQUIRES(!deoptimization_status_lock_,
!art::Roles::uninterruptible_);
bool MethodHasBreakpoints(art::ArtMethod* method)
REQUIRES(!deoptimization_status_lock_);
void RemoveMethodBreakpoint(art::ArtMethod* method)
REQUIRES(!deoptimization_status_lock_, !art::Roles::uninterruptible_)
REQUIRES_SHARED(art::Locks::mutator_lock_);
void AddMethodBreakpoint(art::ArtMethod* method)
REQUIRES(!deoptimization_status_lock_, !art::Roles::uninterruptible_)
REQUIRES_SHARED(art::Locks::mutator_lock_);
void AddDeoptimizeAllMethods()
REQUIRES(!deoptimization_status_lock_, !art::Roles::uninterruptible_)
REQUIRES_SHARED(art::Locks::mutator_lock_);
void RemoveDeoptimizeAllMethods()
REQUIRES(!deoptimization_status_lock_, !art::Roles::uninterruptible_)
REQUIRES_SHARED(art::Locks::mutator_lock_);
jvmtiError AddDeoptimizeThreadMethods(art::ScopedObjectAccessUnchecked& soa, jthread thread)
REQUIRES(!deoptimization_status_lock_, !art::Roles::uninterruptible_)
REQUIRES_SHARED(art::Locks::mutator_lock_);
jvmtiError RemoveDeoptimizeThreadMethods(art::ScopedObjectAccessUnchecked& soa, jthread thread)
REQUIRES(!deoptimization_status_lock_, !art::Roles::uninterruptible_)
REQUIRES_SHARED(art::Locks::mutator_lock_);
void DeoptimizeThread(art::Thread* target)
REQUIRES(!art::Locks::thread_list_lock_)
REQUIRES_SHARED(art::Locks::mutator_lock_);
void DeoptimizeAllThreads() REQUIRES_SHARED(art::Locks::mutator_lock_);
void FinishSetup()
REQUIRES(!deoptimization_status_lock_, !art::Roles::uninterruptible_)
REQUIRES(art::Locks::mutator_lock_);
static DeoptManager* Get();
bool HaveLocalsChanged() const {
return set_local_variable_called_.load();
}
void SetLocalsUpdated() {
set_local_variable_called_.store(true);
}
private:
bool MethodHasBreakpointsLocked(art::ArtMethod* method)
REQUIRES(breakpoint_status_lock_);
// Wait until nothing is currently in the middle of deoptimizing/undeoptimizing something. This is
// needed to ensure that everything is synchronized since threads need to drop the
// deoptimization_status_lock_ while deoptimizing methods.
void WaitForDeoptimizationToFinish(art::Thread* self)
RELEASE(deoptimization_status_lock_) REQUIRES(!art::Locks::mutator_lock_);
void WaitForDeoptimizationToFinishLocked(art::Thread* self)
REQUIRES(deoptimization_status_lock_, !art::Locks::mutator_lock_);
void AddDeoptimizeAllMethodsLocked(art::Thread* self)
RELEASE(deoptimization_status_lock_)
REQUIRES(!art::Roles::uninterruptible_, !art::Locks::mutator_lock_);
void RemoveDeoptimizeAllMethodsLocked(art::Thread* self)
RELEASE(deoptimization_status_lock_)
REQUIRES(!art::Roles::uninterruptible_, !art::Locks::mutator_lock_);
void PerformGlobalDeoptimization(art::Thread* self)
RELEASE(deoptimization_status_lock_)
REQUIRES(!art::Roles::uninterruptible_, !art::Locks::mutator_lock_);
void PerformGlobalUndeoptimization(art::Thread* self)
RELEASE(deoptimization_status_lock_)
REQUIRES(!art::Roles::uninterruptible_, !art::Locks::mutator_lock_);
void PerformLimitedDeoptimization(art::Thread* self, art::ArtMethod* method)
RELEASE(deoptimization_status_lock_)
REQUIRES(!art::Roles::uninterruptible_, !art::Locks::mutator_lock_);
void PerformLimitedUndeoptimization(art::Thread* self, art::ArtMethod* method)
RELEASE(deoptimization_status_lock_)
REQUIRES(!art::Roles::uninterruptible_, !art::Locks::mutator_lock_);
static constexpr const char* kDeoptManagerInstrumentationKey = "JVMTI_DeoptManager";
art::Mutex deoptimization_status_lock_ ACQUIRED_BEFORE(art::Locks::classlinker_classes_lock_);
art::ConditionVariable deoptimization_condition_ GUARDED_BY(deoptimization_status_lock_);
bool performing_deoptimization_ GUARDED_BY(deoptimization_status_lock_);
// Number of times we have gotten requests to deopt everything.
uint32_t global_deopt_count_ GUARDED_BY(deoptimization_status_lock_);
// Number of users of deoptimization there currently are.
uint32_t deopter_count_ GUARDED_BY(deoptimization_status_lock_);
// A mutex that just protects the breakpoint-status map. This mutex should always be at the
// bottom of the lock hierarchy. Nothing more should be locked if we hold this.
art::Mutex breakpoint_status_lock_ ACQUIRED_BEFORE(art::Locks::abort_lock_);
// A map from methods to the number of breakpoints in them from all envs.
std::unordered_map<art::ArtMethod*, uint32_t> breakpoint_status_
GUARDED_BY(breakpoint_status_lock_);
// The MethodInspectionCallback we use to tell the runtime if we care about particular methods.
JvmtiMethodInspectionCallback inspection_callback_;
// Set to true if anything calls SetLocalVariables on any thread since we need to be careful about
// OSR after this.
std::atomic<bool> set_local_variable_called_;
// Helper for setting up/tearing-down for deoptimization.
friend class ScopedDeoptimizationContext;
};
} // namespace openjdkjvmti
#endif // ART_OPENJDKJVMTI_DEOPT_MANAGER_H_