1 /*
2 * Copyright (c) 2021-2022 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 "backend/debugger_executor.h"
17
18 #include "ecmascript/debugger/debugger_api.h"
19 #include "ecmascript/debugger/js_debugger_manager.h"
20 #include "tooling/base/pt_types.h"
21
22 namespace panda::ecmascript::tooling {
Initialize(const EcmaVM *vm)23 void DebuggerExecutor::Initialize(const EcmaVM *vm)
24 {
25 [[maybe_unused]] EcmaHandleScope handleScope(vm->GetJSThread());
26 Local<ObjectRef> globalObj = JSNApi::GetGlobalObject(vm);
27 globalObj->Set(vm, StringRef::NewFromUtf8(vm, "debuggerSetValue"), FunctionRef::New(
28 const_cast<panda::EcmaVM*>(vm), DebuggerExecutor::DebuggerSetValue));
29 globalObj->Set(vm, StringRef::NewFromUtf8(vm, "debuggerGetValue"), FunctionRef::New(
30 const_cast<panda::EcmaVM*>(vm), DebuggerExecutor::DebuggerGetValue));
31 }
32
DebuggerGetValue(JsiRuntimeCallInfo *runtimeCallInfo)33 Local<JSValueRef> DebuggerExecutor::DebuggerGetValue(JsiRuntimeCallInfo *runtimeCallInfo)
34 {
35 EcmaVM *vm = runtimeCallInfo->GetVM();
36 uint32_t argc = runtimeCallInfo->GetArgsNumber();
37 if (argc != NUM_ARGS) {
38 return JSValueRef::Undefined(vm);
39 }
40 Local<JSValueRef> name = runtimeCallInfo->GetCallArgRef(0);
41 if (!name->IsString(vm)) {
42 return JSValueRef::Undefined(vm);
43 }
44 Local<JSValueRef> isThrow = runtimeCallInfo->GetCallArgRef(1);
45
46 auto &frameHandler = vm->GetJsDebuggerManager()->GetEvalFrameHandler();
47 ASSERT(frameHandler);
48
49 Local<JSValueRef> value = GetValue(vm, frameHandler.get(), Local<StringRef>(name));
50 if (!value.IsEmpty()) {
51 return value;
52 }
53
54 if (!isThrow->ToBoolean(vm)->Value()) {
55 DebuggerApi::ClearException(vm);
56 return JSValueRef::Undefined(vm);
57 }
58
59 std::string varName = Local<StringRef>(name)->ToString(vm);
60 ThrowException(vm, varName + " is not defined");
61 return Local<JSValueRef>();
62 }
63
DebuggerSetValue(JsiRuntimeCallInfo *runtimeCallInfo)64 Local<JSValueRef> DebuggerExecutor::DebuggerSetValue(JsiRuntimeCallInfo *runtimeCallInfo)
65 {
66 EcmaVM *vm = runtimeCallInfo->GetVM();
67 uint32_t argc = runtimeCallInfo->GetArgsNumber();
68 if (argc != NUM_ARGS) {
69 return JSValueRef::Undefined(vm);
70 }
71 Local<JSValueRef> name = runtimeCallInfo->GetCallArgRef(0);
72 if (!name->IsString(vm)) {
73 return JSValueRef::Undefined(vm);
74 }
75 Local<JSValueRef> value = runtimeCallInfo->GetCallArgRef(1);
76
77 auto &frameHandler = vm->GetJsDebuggerManager()->GetEvalFrameHandler();
78 ASSERT(frameHandler);
79
80 if (SetValue(vm, frameHandler.get(), Local<StringRef>(name), value)) {
81 return value;
82 }
83
84 std::string varName = StringRef::Cast(*name)->ToString(vm);
85 ThrowException(vm, varName + " is not defined");
86 return Local<JSValueRef>();
87 }
88
GetValue(const EcmaVM *vm, const FrameHandler *frameHandler, Local<StringRef> name)89 Local<JSValueRef> DebuggerExecutor::GetValue(const EcmaVM *vm, const FrameHandler *frameHandler, Local<StringRef> name)
90 {
91 Local<JSValueRef> value;
92 value = GetLocalValue(vm, frameHandler, name);
93 if (!value.IsEmpty()) {
94 return value;
95 }
96 value = GetLexicalValue(vm, frameHandler, name);
97 if (!value.IsEmpty()) {
98 return value;
99 }
100 value = GetModuleValue(vm, frameHandler, name);
101 if (!value.IsEmpty()) {
102 return value;
103 }
104 value = GetGlobalValue(vm, name);
105 if (!value.IsEmpty()) {
106 return value;
107 }
108
109 return Local<JSValueRef>();
110 }
111
SetValue(const EcmaVM *vm, FrameHandler *frameHandler, Local<StringRef> name, Local<JSValueRef> value)112 bool DebuggerExecutor::SetValue(const EcmaVM *vm, FrameHandler *frameHandler,
113 Local<StringRef> name, Local<JSValueRef> value)
114 {
115 if (SetLocalValue(vm, frameHandler, name, value)) {
116 return true;
117 }
118 if (SetLexicalValue(vm, frameHandler, name, value)) {
119 return true;
120 }
121 if (SetModuleValue(vm, frameHandler, name, value)) {
122 return true;
123 }
124 if (SetGlobalValue(vm, name, value)) {
125 return true;
126 }
127
128 return false;
129 }
130
ThrowException(const EcmaVM *vm, const std::string &error)131 void DebuggerExecutor::ThrowException(const EcmaVM *vm, const std::string &error)
132 {
133 Local<StringRef> msg = StringRef::NewFromUtf8(vm, error.c_str());
134 Local<JSValueRef> exception = Exception::ReferenceError(vm, msg);
135 JSNApi::ThrowException(vm, exception);
136 }
137
GetLocalValue(const EcmaVM *vm, const FrameHandler *frameHandler, Local<StringRef> name)138 Local<JSValueRef> DebuggerExecutor::GetLocalValue(const EcmaVM *vm, const FrameHandler *frameHandler,
139 Local<StringRef> name)
140 {
141 Local<JSValueRef> result;
142
143 int32_t index = DebuggerApi::GetVregIndex(frameHandler, name->ToString(vm));
144 if (index == -1) {
145 return result;
146 }
147
148 result = DebuggerApi::GetVRegValue(vm, frameHandler, index);
149 return result;
150 }
151
SetLocalValue(const EcmaVM *vm, FrameHandler *frameHandler, Local<StringRef> name, Local<JSValueRef> value)152 bool DebuggerExecutor::SetLocalValue(const EcmaVM *vm, FrameHandler *frameHandler,
153 Local<StringRef> name, Local<JSValueRef> value)
154 {
155 std::string varName = name->ToString(vm);
156 int32_t index = DebuggerApi::GetVregIndex(frameHandler, varName);
157 if (index == -1) {
158 return false;
159 }
160
161 DebuggerApi::SetVRegValue(frameHandler, index, value);
162 vm->GetJsDebuggerManager()->NotifyScopeUpdated(varName, value, Scope::Type::Local());
163 return true;
164 }
165
GetLexicalValue(const EcmaVM *vm, const FrameHandler *frameHandler, Local<StringRef> name)166 Local<JSValueRef> DebuggerExecutor::GetLexicalValue(const EcmaVM *vm, const FrameHandler *frameHandler,
167 Local<StringRef> name)
168 {
169 Local<JSValueRef> result;
170
171 auto [level, slot] = DebuggerApi::GetLevelSlot(frameHandler, name->ToString(vm));
172 if (level == -1) {
173 return result;
174 }
175
176 result = DebuggerApi::GetProperties(vm, frameHandler, level, slot);
177 return result;
178 }
179
SetLexicalValue(const EcmaVM *vm, const FrameHandler *frameHandler, Local<StringRef> name, Local<JSValueRef> value)180 bool DebuggerExecutor::SetLexicalValue(const EcmaVM *vm, const FrameHandler *frameHandler,
181 Local<StringRef> name, Local<JSValueRef> value)
182 {
183 std::string varName = name->ToString(vm);
184 auto [level, slot] = DebuggerApi::GetLevelSlot(frameHandler, varName);
185 if (level == -1) {
186 return false;
187 }
188
189 DebuggerApi::SetProperties(vm, frameHandler, level, slot, value);
190 vm->GetJsDebuggerManager()->NotifyScopeUpdated(varName, value, Scope::Type::Closure());
191 return true;
192 }
193
GetGlobalValue(const EcmaVM *vm, Local<StringRef> name)194 Local<JSValueRef> DebuggerExecutor::GetGlobalValue(const EcmaVM *vm, Local<StringRef> name)
195 {
196 return DebuggerApi::GetGlobalValue(vm, name);
197 }
198
SetGlobalValue(const EcmaVM *vm, Local<StringRef> name, Local<JSValueRef> value)199 bool DebuggerExecutor::SetGlobalValue(const EcmaVM *vm, Local<StringRef> name, Local<JSValueRef> value)
200 {
201 std::string varName = name->ToString(vm);
202 vm->GetJsDebuggerManager()->NotifyScopeUpdated(varName, value, Scope::Type::Global());
203 return DebuggerApi::SetGlobalValue(vm, name, value);
204 }
205
GetModuleValue(const EcmaVM *vm, const FrameHandler *frameHandler, Local<StringRef> name)206 Local<JSValueRef> DebuggerExecutor::GetModuleValue(const EcmaVM *vm, const FrameHandler *frameHandler,
207 Local<StringRef> name)
208 {
209 Local<JSValueRef> result;
210 std::string varName = name->ToString(vm);
211 Method *method = DebuggerApi::GetMethod(frameHandler);
212 const JSPandaFile *jsPandaFile = method->GetJSPandaFile();
213 if (jsPandaFile != nullptr && (jsPandaFile->IsBundlePack() || !jsPandaFile->IsNewVersion())) {
214 return result;
215 }
216 JSThread *thread = vm->GetJSThread();
217 JSHandle<JSTaggedValue> currentModule(thread, DebuggerApi::GetCurrentModule(vm));
218 if (currentModule->IsSourceTextModule()) {
219 result = DebuggerApi::GetModuleValue(vm, currentModule, varName);
220 }
221 return result;
222 }
223
SetModuleValue(const EcmaVM *vm, const FrameHandler *frameHandler, Local<StringRef> name, Local<JSValueRef> value)224 bool DebuggerExecutor::SetModuleValue(const EcmaVM *vm, const FrameHandler *frameHandler,
225 Local<StringRef> name, Local<JSValueRef> value)
226 {
227 std::string varName = name->ToString(vm);
228 Method *method = DebuggerApi::GetMethod(frameHandler);
229 const JSPandaFile *jsPandaFile = method->GetJSPandaFile();
230 if (jsPandaFile != nullptr && (jsPandaFile->IsBundlePack() || !jsPandaFile->IsNewVersion())) {
231 return false;
232 }
233 JSThread *thread = vm->GetJSThread();
234 JSHandle<JSTaggedValue> currentModule(thread, DebuggerApi::GetCurrentModule(vm));
235 if (currentModule->IsSourceTextModule()) {
236 DebuggerApi::SetModuleValue(vm, currentModule, varName, value);
237 vm->GetJsDebuggerManager()->NotifyScopeUpdated(varName, value, Scope::Type::Module());
238 }
239 return true;
240 }
241 } // namespace panda::ecmascript::tooling
242