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 = GetGlobalValue(vm, name);
100 if (!value.IsEmpty()) {
101 return value;
102 }
103
104 return Local<JSValueRef>();
105 }
106
SetValue(const EcmaVM * vm,FrameHandler * frameHandler,Local<StringRef> name,Local<JSValueRef> value)107 bool DebuggerExecutor::SetValue(const EcmaVM *vm, FrameHandler *frameHandler,
108 Local<StringRef> name, Local<JSValueRef> value)
109 {
110 if (SetLocalValue(vm, frameHandler, name, value)) {
111 return true;
112 }
113 if (SetLexicalValue(vm, frameHandler, name, value)) {
114 return true;
115 }
116 if (SetGlobalValue(vm, name, value)) {
117 return true;
118 }
119
120 return false;
121 }
122
ThrowException(const EcmaVM * vm,const std::string & error)123 void DebuggerExecutor::ThrowException(const EcmaVM *vm, const std::string &error)
124 {
125 Local<StringRef> msg = StringRef::NewFromUtf8(vm, error.c_str());
126 Local<JSValueRef> exception = Exception::ReferenceError(vm, msg);
127 JSNApi::ThrowException(vm, exception);
128 }
129
GetLocalValue(const EcmaVM * vm,const FrameHandler * frameHandler,Local<StringRef> name)130 Local<JSValueRef> DebuggerExecutor::GetLocalValue(const EcmaVM *vm, const FrameHandler *frameHandler,
131 Local<StringRef> name)
132 {
133 Local<JSValueRef> result;
134
135 int32_t index = DebuggerApi::GetVregIndex(frameHandler, name->ToString());
136 if (index == -1) {
137 return result;
138 }
139
140 result = DebuggerApi::GetVRegValue(vm, frameHandler, index);
141 return result;
142 }
143
SetLocalValue(const EcmaVM * vm,FrameHandler * frameHandler,Local<StringRef> name,Local<JSValueRef> value)144 bool DebuggerExecutor::SetLocalValue(const EcmaVM *vm, FrameHandler *frameHandler,
145 Local<StringRef> name, Local<JSValueRef> value)
146 {
147 std::string varName = name->ToString();
148 int32_t index = DebuggerApi::GetVregIndex(frameHandler, varName);
149 if (index == -1) {
150 return false;
151 }
152
153 DebuggerApi::SetVRegValue(frameHandler, index, value);
154 vm->GetJsDebuggerManager()->NotifyLocalScopeUpdated(varName, value);
155 return true;
156 }
157
GetLexicalValue(const EcmaVM * vm,const FrameHandler * frameHandler,Local<StringRef> name)158 Local<JSValueRef> DebuggerExecutor::GetLexicalValue(const EcmaVM *vm, const FrameHandler *frameHandler,
159 Local<StringRef> name)
160 {
161 Local<JSValueRef> result;
162
163 auto [level, slot] = DebuggerApi::GetLevelSlot(frameHandler, name->ToString());
164 if (level == -1) {
165 return result;
166 }
167
168 result = DebuggerApi::GetProperties(vm, frameHandler, level, slot);
169 return result;
170 }
171
SetLexicalValue(const EcmaVM * vm,const FrameHandler * frameHandler,Local<StringRef> name,Local<JSValueRef> value)172 bool DebuggerExecutor::SetLexicalValue(const EcmaVM *vm, const FrameHandler *frameHandler,
173 Local<StringRef> name, Local<JSValueRef> value)
174 {
175 std::string varName = name->ToString();
176 auto [level, slot] = DebuggerApi::GetLevelSlot(frameHandler, varName);
177 if (level == -1) {
178 return false;
179 }
180
181 DebuggerApi::SetProperties(vm, frameHandler, level, slot, value);
182 vm->GetJsDebuggerManager()->NotifyLocalScopeUpdated(varName, value);
183 return true;
184 }
185
GetGlobalValue(const EcmaVM * vm,Local<StringRef> name)186 Local<JSValueRef> DebuggerExecutor::GetGlobalValue(const EcmaVM *vm, Local<StringRef> name)
187 {
188 return DebuggerApi::GetGlobalValue(vm, name);
189 }
190
SetGlobalValue(const EcmaVM * vm,Local<StringRef> name,Local<JSValueRef> value)191 bool DebuggerExecutor::SetGlobalValue(const EcmaVM *vm, Local<StringRef> name, Local<JSValueRef> value)
192 {
193 return DebuggerApi::SetGlobalValue(vm, name, value);
194 }
195 } // namespace panda::ecmascript::tooling
196