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