• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }