/* * 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::AppendDependentInfos(JSThread *thread, const JSHandle jsFunc, const DependentStateCollection collection, const JSHandle info) { JSHandle first = jsFunc; JSHandle second(thread, JSTaggedValue(collection)); JSHandle newVec1 = WeakVector::Append(thread, JSHandle::Cast(info), first, ElementType::WEAK); JSHandle newVec2 = WeakVector::Append(thread, newVec1, second); return JSHandle(newVec2); } // static void DependentInfos::TraceLazyDeoptReason(JSThread *thread, JSHandle func, DependentStateCollection collection) { if (!thread->GetEcmaVM()->GetJSOptions().IsEnableLazyDeoptTrace()) { return; } JSTaggedValue funcName = JSFunction::NameGetter(thread, JSHandle::Cast(func)); std::string funNameS = "Lazy Deoptimization occurred on"; funNameS += " function: \"" + EcmaStringAccessor(funcName).ToStdString(thread) + "\""; LOG_TRACE(INFO) << funNameS; // Get the lowbit of collection. uint32_t value = (static_cast(collection) & (-static_cast(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; } // static void DependentInfos::TriggerLazyDeoptimization(JSHandle dependentInfos, JSThread *thread, DependentStateCollection collection) { bool hasDeoptMethod = false; for (uint32_t i = 0; i < dependentInfos->GetEnd(); i += SLOT_PER_ENTRY) { DependentStateCollection depCollection = static_cast( 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 func(thread, rawValue); if (func->IsCompiledCode()) { hasDeoptMethod = true; JSHandle method(thread, func->GetMethod(thread)); // When lazy deopt happened, the deopt method cannot call as jit any more. Deoptimizier::ClearCompiledCodeStatusWhenDeopt(thread, func.GetObject(), method.GetObject(), kungfu::DeoptType::LAZYDEOPT); TraceLazyDeoptReason(thread, func, (depCollection & collection)); } } if (hasDeoptMethod) { // Replace return address Deoptimizier::PrepareForLazyDeopt(thread); } } } // namespace panda::ecmascript