1 /*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecmascript/dependent_infos.h"
17
18 #include "ecmascript/deoptimizer/deoptimizer.h"
19 #include "ecmascript/js_function.h"
20 #include "ecmascript/js_tagged_value.h"
21 #include "ecmascript/dfx/stackinfo/js_stackinfo.h"
22
23 namespace panda::ecmascript {
24
AppendDependentInfos(JSThread * thread,const JSHandle<JSTaggedValue> jsFunc,const DependentStateCollection collection,const JSHandle<DependentInfos> info)25 JSHandle<DependentInfos> DependentInfos::AppendDependentInfos(JSThread *thread,
26 const JSHandle<JSTaggedValue> jsFunc,
27 const DependentStateCollection collection,
28 const JSHandle<DependentInfos> info)
29 {
30 JSHandle<JSTaggedValue> first = jsFunc;
31 JSHandle<JSTaggedValue> second(thread, JSTaggedValue(collection));
32 JSHandle<WeakVector> newVec1 = WeakVector::Append(thread,
33 JSHandle<WeakVector>::Cast(info), first, ElementType::WEAK);
34 JSHandle<WeakVector> newVec2 = WeakVector::Append(thread, newVec1, second);
35 return JSHandle<DependentInfos>(newVec2);
36 }
37
38 // static
TraceLazyDeoptReason(JSThread * thread,JSHandle<JSFunction> func,DependentStateCollection collection)39 void DependentInfos::TraceLazyDeoptReason(JSThread *thread, JSHandle<JSFunction> func,
40 DependentStateCollection collection)
41 {
42 if (!thread->GetEcmaVM()->GetJSOptions().IsEnableLazyDeoptTrace()) {
43 return;
44 }
45 JSTaggedValue funcName = JSFunction::NameGetter(thread, JSHandle<JSObject>::Cast(func));
46 std::string funNameS = "Lazy Deoptimization occurred on";
47 funNameS += " function: \"" + EcmaStringAccessor(funcName).ToStdString(thread) + "\"";
48 LOG_TRACE(INFO) << funNameS;
49 // Get the lowbit of collection.
50 uint32_t value = (static_cast<uint32_t>(collection) & (-static_cast<uint32_t>(collection)));
51 std::string reason;
52 switch (value) {
53 #define LAZY_DEOPT_TYPE_CASE(name, value) \
54 case (value): { \
55 reason = #name; \
56 break; \
57 }
58 LAZY_DEOPT_TYPE_LIST(LAZY_DEOPT_TYPE_CASE)
59 #undef LAZY_DEOPT_TYPE_CASE
60 default:
61 reason = "Unknown";
62 }
63 LOG_TRACE(INFO) << "Lazy Deoptimize reason: " << reason;
64 std::string data = JsStackInfo::BuildJsStackTrace(thread, true);
65 LOG_COMPILER(INFO) << "Lazy Deoptimize" << data;
66 }
67
68 // static
TriggerLazyDeoptimization(JSHandle<DependentInfos> dependentInfos,JSThread * thread,DependentStateCollection collection)69 void DependentInfos::TriggerLazyDeoptimization(JSHandle<DependentInfos> dependentInfos,
70 JSThread *thread, DependentStateCollection collection)
71 {
72 bool hasDeoptMethod = false;
73 for (uint32_t i = 0; i < dependentInfos->GetEnd(); i += SLOT_PER_ENTRY) {
74 DependentStateCollection depCollection =
75 static_cast<DependentStateCollection>(
76 dependentInfos->GetPrimitive(i + COLLECTION_SLOT_OFFSET).GetInt());
77 if (!CheckCollectionEffect(depCollection, collection)) {
78 continue;
79 }
80 JSTaggedValue rawValue = dependentInfos->Get(thread, i + FUNCTION_SLOT_OFFSET).GetWeakRawValue();
81 if (!rawValue.IsHeapObject()) {
82 continue;
83 }
84 JSHandle<JSFunction> func(thread, rawValue);
85 if (func->IsCompiledCode()) {
86 hasDeoptMethod = true;
87 JSHandle<Method> method(thread, func->GetMethod(thread));
88 // When lazy deopt happened, the deopt method cannot call as jit any more.
89 Deoptimizier::ClearCompiledCodeStatusWhenDeopt(thread,
90 func.GetObject<JSFunction>(),
91 method.GetObject<Method>(),
92 kungfu::DeoptType::LAZYDEOPT);
93 TraceLazyDeoptReason(thread, func, (depCollection & collection));
94 }
95 }
96 if (hasDeoptMethod) {
97 // Replace return address
98 Deoptimizier::PrepareForLazyDeopt(thread);
99 }
100 }
101 } // namespace panda::ecmascript
102