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 "ecmascript/tooling/backend/debugger_executor.h"
17
18 #include "ecmascript/tooling/backend/debugger_api.h"
19 #include "ecmascript/tooling/interface/js_debugger_manager.h"
20 #include "libpandabase/utils/logger.h"
21
22 namespace panda::ecmascript::tooling {
Initialize(const EcmaVM * vm)23 void DebuggerExecutor::Initialize(const EcmaVM *vm)
24 {
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, nullptr));
28 globalObj->Set(vm, StringRef::NewFromUtf8(vm, "debuggerGetValue"), FunctionRef::New(
29 const_cast<panda::EcmaVM*>(vm), DebuggerExecutor::DebuggerGetValue, nullptr));
30 }
31
DebuggerGetValue(EcmaVM * vm,Local<JSValueRef> thisArg,const Local<JSValueRef> * argv,int32_t length,void * data)32 Local<JSValueRef> DebuggerExecutor::DebuggerGetValue(EcmaVM *vm, [[maybe_unused]] Local<JSValueRef> thisArg,
33 const Local<JSValueRef> *argv,
34 int32_t length, [[maybe_unused]] void *data)
35 {
36 if (length != NUM_ARGS) {
37 return JSValueRef::Undefined(vm);
38 }
39 Local<JSValueRef> name = argv[0];
40 if (!name->IsString()) {
41 return JSValueRef::Undefined(vm);
42 }
43 Local<JSValueRef> isThrow = argv[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() && !value->IsException()) {
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 JSValueRef::Exception(vm);
61 }
62
DebuggerSetValue(EcmaVM * vm,Local<JSValueRef> thisArg,const Local<JSValueRef> * argv,int32_t length,void * data)63 Local<JSValueRef> DebuggerExecutor::DebuggerSetValue(EcmaVM *vm, [[maybe_unused]] Local<JSValueRef> thisArg,
64 const Local<JSValueRef> *argv,
65 int32_t length, [[maybe_unused]] void *data)
66 {
67 if (length != NUM_ARGS) {
68 return JSValueRef::Undefined(vm);
69 }
70 Local<JSValueRef> name = argv[0];
71 if (!name->IsString()) {
72 return JSValueRef::Undefined(vm);
73 }
74 Local<JSValueRef> value = argv[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 JSValueRef::Exception(vm);
86 }
87
GetValue(const EcmaVM * vm,const InterpretedFrameHandler * frameHandler,Local<StringRef> name)88 Local<JSValueRef> DebuggerExecutor::GetValue(const EcmaVM *vm, const InterpretedFrameHandler *frameHandler,
89 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 = GetGlobalValue(vm, name);
101 if (!value.IsEmpty() && !value->IsException()) {
102 return value;
103 }
104
105 return Local<JSValueRef>();
106 }
107
SetValue(const EcmaVM * vm,InterpretedFrameHandler * frameHandler,Local<StringRef> name,Local<JSValueRef> value)108 bool DebuggerExecutor::SetValue(const EcmaVM *vm, InterpretedFrameHandler *frameHandler,
109 Local<StringRef> name, Local<JSValueRef> value)
110 {
111 if (SetLocalValue(vm, frameHandler, name, value)) {
112 return true;
113 }
114 if (SetLexicalValue(vm, frameHandler, name, value)) {
115 return true;
116 }
117 if (SetGlobalValue(vm, name, value)) {
118 return true;
119 }
120
121 return false;
122 }
123
ThrowException(const EcmaVM * vm,const std::string & error)124 void DebuggerExecutor::ThrowException(const EcmaVM *vm, const std::string &error)
125 {
126 Local<StringRef> msg = StringRef::NewFromUtf8(vm, error.c_str());
127 Local<JSValueRef> exception = Exception::ReferenceError(vm, msg);
128 JSNApi::ThrowException(vm, exception);
129 }
130
GetLocalValue(const EcmaVM * vm,const InterpretedFrameHandler * frameHandler,Local<StringRef> name)131 Local<JSValueRef> DebuggerExecutor::GetLocalValue(const EcmaVM *vm, const InterpretedFrameHandler *frameHandler,
132 Local<StringRef> name)
133 {
134 Local<JSValueRef> result;
135
136 int32_t index = DebuggerApi::GetVregIndex(frameHandler, name->ToString());
137 if (index == -1) {
138 return result;
139 }
140
141 result = DebuggerApi::GetVRegValue(vm, frameHandler, index);
142 return result;
143 }
144
SetLocalValue(const EcmaVM * vm,InterpretedFrameHandler * frameHandler,Local<StringRef> name,Local<JSValueRef> value)145 bool DebuggerExecutor::SetLocalValue(const EcmaVM *vm, InterpretedFrameHandler *frameHandler,
146 Local<StringRef> name, Local<JSValueRef> value)
147 {
148 std::string varName = name->ToString();
149 int32_t index = DebuggerApi::GetVregIndex(frameHandler, varName);
150 if (index == -1) {
151 return false;
152 }
153
154 DebuggerApi::SetVRegValue(frameHandler, index, value);
155 vm->GetJsDebuggerManager()->NotifyLocalScopeUpdated(varName, value);
156 return true;
157 }
158
GetLexicalValue(const EcmaVM * vm,const InterpretedFrameHandler * frameHandler,Local<StringRef> name)159 Local<JSValueRef> DebuggerExecutor::GetLexicalValue(const EcmaVM *vm, const InterpretedFrameHandler *frameHandler,
160 Local<StringRef> name)
161 {
162 Local<JSValueRef> result;
163
164 auto [level, slot] = DebuggerApi::GetLevelSlot(frameHandler, name->ToString());
165 if (level == -1) {
166 return result;
167 }
168
169 result = DebuggerApi::GetProperties(vm, frameHandler, level, slot);
170 return result;
171 }
172
SetLexicalValue(const EcmaVM * vm,const InterpretedFrameHandler * frameHandler,Local<StringRef> name,Local<JSValueRef> value)173 bool DebuggerExecutor::SetLexicalValue(const EcmaVM *vm, const InterpretedFrameHandler *frameHandler,
174 Local<StringRef> name, Local<JSValueRef> value)
175 {
176 std::string varName = name->ToString();
177 auto [level, slot] = DebuggerApi::GetLevelSlot(frameHandler, varName);
178 if (level == -1) {
179 return false;
180 }
181
182 DebuggerApi::SetProperties(vm, frameHandler, level, slot, value);
183 vm->GetJsDebuggerManager()->NotifyLocalScopeUpdated(varName, value);
184 return true;
185 }
186
GetGlobalValue(const EcmaVM * vm,Local<StringRef> name)187 Local<JSValueRef> DebuggerExecutor::GetGlobalValue(const EcmaVM *vm, Local<StringRef> name)
188 {
189 return DebuggerApi::GetGlobalValue(vm, name);
190 }
191
SetGlobalValue(const EcmaVM * vm,Local<StringRef> name,Local<JSValueRef> value)192 bool DebuggerExecutor::SetGlobalValue(const EcmaVM *vm, Local<StringRef> name, Local<JSValueRef> value)
193 {
194 return DebuggerApi::SetGlobalValue(vm, name, value);
195 }
196 } // namespace panda::ecmascript::tooling
197