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