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