* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/dependent_infos.h"
#include "ecmascript/deoptimizer/deoptimizer.h"
#include "ecmascript/js_function.h"
#include "ecmascript/js_tagged_value.h"
#include "ecmascript/dfx/stackinfo/js_stackinfo.h"
namespace panda::ecmascript {
JSHandle<DependentInfos> DependentInfos::AppendDependentInfos(JSThread *thread,
const JSHandle<JSTaggedValue> jsFunc,
const DependentStateCollection collection,
const JSHandle<DependentInfos> info)
{
JSHandle<JSTaggedValue> first = jsFunc;
JSHandle<JSTaggedValue> second(thread, JSTaggedValue(collection));
JSHandle<WeakVector> newVec1 = WeakVector::Append(thread,
JSHandle<WeakVector>::Cast(info), first, ElementType::WEAK);
JSHandle<WeakVector> newVec2 = WeakVector::Append(thread, newVec1, second);
return JSHandle<DependentInfos>(newVec2);
}
void DependentInfos::TraceLazyDeoptReason(JSThread *thread, JSHandle<JSFunction> func,
DependentStateCollection collection)
{
if (!thread->GetEcmaVM()->GetJSOptions().IsEnableLazyDeoptTrace()) {
return;
}
JSTaggedValue funcName = JSFunction::NameGetter(thread, JSHandle<JSObject>::Cast(func));
std::string funNameS = "Lazy Deoptimization occurred on";
funNameS += " function: \"" + EcmaStringAccessor(funcName).ToStdString(thread) + "\"";
LOG_TRACE(INFO) << funNameS;
uint32_t value = (static_cast<uint32_t>(collection) & (-static_cast<uint32_t>(collection)));
std::string reason;
switch (value) {
#define LAZY_DEOPT_TYPE_CASE(name, value) \
case (value): { \
reason = #name; \
break; \
}
LAZY_DEOPT_TYPE_LIST(LAZY_DEOPT_TYPE_CASE)
#undef LAZY_DEOPT_TYPE_CASE
default:
reason = "Unknown";
}
LOG_TRACE(INFO) << "Lazy Deoptimize reason: " << reason;
std::string data = JsStackInfo::BuildJsStackTrace(thread, true);
LOG_COMPILER(INFO) << "Lazy Deoptimize" << data;
}
void DependentInfos::TriggerLazyDeoptimization(JSHandle<DependentInfos> dependentInfos,
JSThread *thread, DependentStateCollection collection)
{
bool hasDeoptMethod = false;
for (uint32_t i = 0; i < dependentInfos->GetEnd(); i += SLOT_PER_ENTRY) {
DependentStateCollection depCollection =
static_cast<DependentStateCollection>(
dependentInfos->GetPrimitive(i + COLLECTION_SLOT_OFFSET).GetInt());
if (!CheckCollectionEffect(depCollection, collection)) {
continue;
}
JSTaggedValue rawValue = dependentInfos->Get(thread, i + FUNCTION_SLOT_OFFSET).GetWeakRawValue();
if (!rawValue.IsHeapObject()) {
continue;
}
JSHandle<JSFunction> func(thread, rawValue);
if (func->IsCompiledCode()) {
hasDeoptMethod = true;
JSHandle<Method> method(thread, func->GetMethod(thread));
Deoptimizier::ClearCompiledCodeStatusWhenDeopt(thread,
func.GetObject<JSFunction>(),
method.GetObject<Method>(),
kungfu::DeoptType::LAZYDEOPT,
false);
TraceLazyDeoptReason(thread, func, (depCollection & collection));
}
}
if (hasDeoptMethod) {
Deoptimizier::PrepareForLazyDeopt(thread);
}
}
}