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