1 /*
2 * Copyright (c) 2023 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/debugger/dropframe_manager.h"
17
18 #include "ecmascript/frames.h"
19 #include "ecmascript/global_env.h"
20 #include "ecmascript/global_handle_collection.h"
21 #include "ecmascript/interpreter/frame_handler.h"
22 #include "ecmascript/interpreter/interpreter-inl.h"
23
24 namespace panda::ecmascript::tooling {
IsNewlexenvOpcode(BytecodeInstruction::Opcode op)25 bool DropframeManager::IsNewlexenvOpcode(BytecodeInstruction::Opcode op)
26 {
27 switch (op) {
28 case BytecodeInstruction::Opcode::NEWLEXENV_IMM8:
29 case BytecodeInstruction::Opcode::NEWLEXENVWITHNAME_IMM8_ID16:
30 case BytecodeInstruction::Opcode::WIDE_NEWLEXENV_PREF_IMM16:
31 case BytecodeInstruction::Opcode::WIDE_NEWLEXENVWITHNAME_PREF_IMM16_ID16:
32 return true;
33 default:
34 break;
35 }
36 return false;
37 }
38
IsStlexvarOpcode(BytecodeInstruction::Opcode op)39 bool DropframeManager::IsStlexvarOpcode(BytecodeInstruction::Opcode op)
40 {
41 switch (op) {
42 case BytecodeInstruction::Opcode::STLEXVAR_IMM4_IMM4:
43 case BytecodeInstruction::Opcode::STLEXVAR_IMM8_IMM8:
44 case BytecodeInstruction::Opcode::WIDE_STLEXVAR_PREF_IMM16_IMM16:
45 return true;
46 default:
47 break;
48 }
49 return false;
50 }
51
ReadStlexvarParams(const uint8_t * pc,BytecodeInstruction::Opcode op)52 std::pair<uint16_t, uint16_t> DropframeManager::ReadStlexvarParams(const uint8_t *pc, BytecodeInstruction::Opcode op)
53 {
54 uint16_t level = 0;
55 uint16_t slot = 0;
56 switch (op) {
57 case BytecodeInstruction::Opcode::STLEXVAR_IMM4_IMM4:
58 level = READ_INST_4_0();
59 slot = READ_INST_4_1();
60 break;
61 case BytecodeInstruction::Opcode::STLEXVAR_IMM8_IMM8:
62 level = READ_INST_8_0();
63 slot = READ_INST_8_1();
64 break;
65 case BytecodeInstruction::Opcode::WIDE_STLEXVAR_PREF_IMM16_IMM16:
66 level = READ_INST_16_1();
67 slot = READ_INST_16_3();
68 break;
69 default:
70 break;
71 }
72 return std::make_pair(level, slot);
73 }
74
MethodEntry(JSThread * thread,JSHandle<Method> method)75 void DropframeManager::MethodEntry(JSThread *thread, JSHandle<Method> method)
76 {
77 uint32_t codeSize = method->GetCodeSize();
78 uint16_t newEnvCount = 0;
79 FrameHandler frameHandler(thread);
80 std::set<std::pair<uint16_t, uint16_t>> modifiedLexVarPos;
81 NewLexModifyRecordLevel();
82 auto bcIns = BytecodeInstruction(method->GetBytecodeArray());
83 auto bcInsLast = bcIns.JumpTo(codeSize);
84 while (bcIns.GetAddress() != bcInsLast.GetAddress()) {
85 BytecodeInstruction::Opcode op = bcIns.GetOpcode();
86 if (IsNewlexenvOpcode(op)) {
87 newEnvCount++;
88 } else if (IsStlexvarOpcode(op)) {
89 std::pair<uint16_t, uint16_t> lexVarPos = ReadStlexvarParams(bcIns.GetAddress(), op);
90 uint16_t level;
91 uint16_t slot;
92 std::tie(level, slot) = lexVarPos;
93 JSTaggedValue env = frameHandler.GetEnv();
94 for (uint16_t i = 0; ; i++) {
95 if ((level < newEnvCount || i >= level - newEnvCount) &&
96 slot < LexicalEnv::Cast(env.GetTaggedObject())->GetLength() - LexicalEnv::RESERVED_ENV_LENGTH &&
97 !modifiedLexVarPos.count({i, slot})) {
98 JSTaggedValue value = LexicalEnv::Cast(env.GetTaggedObject())->GetProperties(slot);
99 EmplaceLexModifyRecord(thread, env, slot, value);
100 modifiedLexVarPos.insert({i, slot});
101 }
102 if (i >= level) {
103 break;
104 }
105 JSTaggedValue taggedParentEnv = LexicalEnv::Cast(env.GetTaggedObject())->GetParentEnv();
106 if (taggedParentEnv.IsUndefined()) {
107 break;
108 }
109 env = taggedParentEnv;
110 }
111 }
112 bcIns = bcIns.GetNext();
113 }
114 }
115
MethodExit(JSThread * thread,JSHandle<Method> method)116 void DropframeManager::MethodExit(JSThread *thread, [[maybe_unused]] JSHandle<Method> method)
117 {
118 MergeLexModifyRecordOfTopFrame(thread);
119 }
120
DropLastFrame(JSThread * thread)121 void DropframeManager::DropLastFrame(JSThread *thread)
122 {
123 std::vector<std::tuple<JSHandle<JSTaggedValue>, uint16_t, JSHandle<JSTaggedValue>>> lexModifyRecord;
124 lexModifyRecord = GetLexModifyRecordOfTopFrame();
125 for (const auto &item : lexModifyRecord) {
126 JSHandle<JSTaggedValue> envHandle;
127 uint16_t slot;
128 JSHandle<JSTaggedValue> valueHandle;
129 std::tie(envHandle, slot, valueHandle) = item;
130 JSTaggedValue env = envHandle.GetTaggedValue();
131 ASSERT(slot < LexicalEnv::Cast(env.GetTaggedObject())->GetLength() - LexicalEnv::RESERVED_ENV_LENGTH);
132 LexicalEnv::Cast(env.GetTaggedObject())->SetProperties(thread, slot, valueHandle.GetTaggedValue());
133 }
134 RemoveLexModifyRecordOfTopFrame(thread);
135
136 JSTaggedType *sp = const_cast<JSTaggedType *>(thread->GetCurrentSPFrame());
137 InterpretedFrame *state = InterpretedFrame::GetFrameFromSp(sp);
138 JSTaggedType *prevSp = state->base.prev;
139 thread->SetCurrentSPFrame(prevSp);
140 thread->SetFrameDroppedBit();
141 }
142
NewLexModifyRecordLevel()143 void DropframeManager::NewLexModifyRecordLevel()
144 {
145 modifiedLexVar_.push(std::vector<std::tuple<JSHandle<JSTaggedValue>, uint16_t, JSHandle<JSTaggedValue>>>());
146 }
147
EmplaceLexModifyRecord(JSThread * thread,JSTaggedValue env,uint16_t slot,JSTaggedValue value)148 void DropframeManager::EmplaceLexModifyRecord(JSThread *thread, JSTaggedValue env, uint16_t slot, JSTaggedValue value)
149 {
150 GlobalHandleCollection globalHandleCollection(thread);
151 for (const auto &item : modifiedLexVar_.top()) {
152 JSHandle<JSTaggedValue> envHandleRecord = std::get<0>(item);
153 uint16_t slotRecord = std::get<1>(item);
154 if (envHandleRecord.GetTaggedType() == env.GetRawData() && slotRecord == slot) {
155 return;
156 }
157 }
158 JSHandle<JSTaggedValue> envHandle = globalHandleCollection.NewHandle<JSTaggedValue>(env.GetRawData());
159 JSHandle<JSTaggedValue> valueHandle = globalHandleCollection.NewHandle<JSTaggedValue>(value.GetRawData());
160 modifiedLexVar_.top().emplace_back(envHandle, slot, valueHandle);
161 }
162
GetLexModifyRecordLevel()163 uint32_t DropframeManager::GetLexModifyRecordLevel()
164 {
165 return modifiedLexVar_.size();
166 }
167
168 std::vector<std::tuple<JSHandle<JSTaggedValue>, uint16_t, JSHandle<JSTaggedValue>>>
GetLexModifyRecordOfTopFrame()169 DropframeManager::GetLexModifyRecordOfTopFrame()
170 {
171 if (modifiedLexVar_.empty()) {
172 return std::vector<std::tuple<JSHandle<JSTaggedValue>, uint16_t, JSHandle<JSTaggedValue>>>();
173 }
174 return modifiedLexVar_.top();
175 }
176
RemoveLexModifyRecordOfTopFrame(JSThread * thread)177 void DropframeManager::RemoveLexModifyRecordOfTopFrame(JSThread *thread)
178 {
179 if (modifiedLexVar_.empty()) {
180 return;
181 }
182 GlobalHandleCollection globalHandleCollection(thread);
183 for (const auto &item : modifiedLexVar_.top()) {
184 JSHandle<JSTaggedValue> envHandle = std::get<0>(item);
185 JSHandle<JSTaggedValue> valueHandle = std::get<2>(item); // 2:get the third item of the tuple
186 globalHandleCollection.Dispose(envHandle);
187 globalHandleCollection.Dispose(valueHandle);
188 }
189 modifiedLexVar_.pop();
190 }
191
MergeLexModifyRecordOfTopFrame(JSThread * thread)192 void DropframeManager::MergeLexModifyRecordOfTopFrame(JSThread *thread)
193 {
194 if (modifiedLexVar_.empty()) {
195 return;
196 }
197 GlobalHandleCollection globalHandleCollection(thread);
198 std::vector<std::tuple<JSHandle<JSTaggedValue>, uint16_t, JSHandle<JSTaggedValue>>> lexModifyRecord;
199 lexModifyRecord = modifiedLexVar_.top();
200 modifiedLexVar_.pop();
201 for (const auto &item : lexModifyRecord) {
202 JSHandle<JSTaggedValue> envHandle;
203 uint16_t slot;
204 JSHandle<JSTaggedValue> valueHandle;
205 std::tie(envHandle, slot, valueHandle) = item;
206 bool existRecord = false;
207 if (!modifiedLexVar_.empty()) {
208 for (const auto &itemLast : modifiedLexVar_.top()) {
209 JSHandle<JSTaggedValue> envHandleRecord = std::get<0>(itemLast);
210 uint16_t slotRecord = std::get<1>(itemLast);
211 if (envHandleRecord.GetTaggedType() == envHandle.GetTaggedType() && slotRecord == slot) {
212 existRecord = true;
213 break;
214 }
215 }
216 }
217 if (modifiedLexVar_.empty() || existRecord) {
218 globalHandleCollection.Dispose(envHandle);
219 globalHandleCollection.Dispose(valueHandle);
220 } else {
221 modifiedLexVar_.top().emplace_back(envHandle, slot, valueHandle);
222 }
223 }
224 }
225 }