/* * Copyright (c) 2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "agent/runtime_impl.h" #include <iomanip> #include "base/pt_returns.h" #include "protocol_channel.h" #include "ecmascript/napi/include/dfx_jsnapi.h" namespace panda::ecmascript::tooling { void RuntimeImpl::DispatcherImpl::Dispatch(const DispatchRequest &request) { static std::unordered_map<std::string, AgentHandler> dispatcherTable { { "enable", &RuntimeImpl::DispatcherImpl::Enable }, { "getProperties", &RuntimeImpl::DispatcherImpl::GetProperties }, { "runIfWaitingForDebugger", &RuntimeImpl::DispatcherImpl::RunIfWaitingForDebugger }, { "callFunctionOn", &RuntimeImpl::DispatcherImpl::CallFunctionOn }, { "getHeapUsage", &RuntimeImpl::DispatcherImpl::GetHeapUsage } }; const std::string &method = request.GetMethod(); LOG_DEBUGGER(DEBUG) << "dispatch [" << method << "] to RuntimeImpl"; auto entry = dispatcherTable.find(method); if (entry != dispatcherTable.end()) { (this->*(entry->second))(request); } else { LOG_DEBUGGER(ERROR) << "unknown method: " << method; SendResponse(request, DispatchResponse::Fail("unknown method: " + method)); } } void RuntimeImpl::DispatcherImpl::Enable(const DispatchRequest &request) { DispatchResponse response = runtime_->Enable(); SendResponse(request, response); } void RuntimeImpl::DispatcherImpl::Disable(const DispatchRequest &request) { DispatchResponse response = runtime_->Disable(); SendResponse(request, response); } void RuntimeImpl::DispatcherImpl::RunIfWaitingForDebugger(const DispatchRequest &request) { DispatchResponse response = runtime_->RunIfWaitingForDebugger(); SendResponse(request, response); } void RuntimeImpl::DispatcherImpl::GetProperties(const DispatchRequest &request) { std::unique_ptr<GetPropertiesParams> params = GetPropertiesParams::Create(request.GetParams()); if (params == nullptr) { SendResponse(request, DispatchResponse::Fail("wrong params")); return; } std::vector<std::unique_ptr<PropertyDescriptor>> outPropertyDesc; std::optional<std::vector<std::unique_ptr<InternalPropertyDescriptor>>> outInternalDescs; std::optional<std::vector<std::unique_ptr<PrivatePropertyDescriptor>>> outPrivateProperties; std::optional<std::unique_ptr<ExceptionDetails>> outExceptionDetails; DispatchResponse response = runtime_->GetProperties(*params, &outPropertyDesc, &outInternalDescs, &outPrivateProperties, &outExceptionDetails); if (outExceptionDetails) { ASSERT(outExceptionDetails.value() != nullptr); LOG_DEBUGGER(WARN) << "GetProperties thrown an exception"; } GetPropertiesReturns result(std::move(outPropertyDesc), std::move(outInternalDescs), std::move(outPrivateProperties), std::move(outExceptionDetails)); SendResponse(request, response, result); } void RuntimeImpl::DispatcherImpl::CallFunctionOn(const DispatchRequest &request) { std::unique_ptr<CallFunctionOnParams> params = CallFunctionOnParams::Create(request.GetParams()); if (params == nullptr) { SendResponse(request, DispatchResponse::Fail("wrong params")); return; } std::unique_ptr<RemoteObject> outRemoteObject; std::optional<std::unique_ptr<ExceptionDetails>> outExceptionDetails; DispatchResponse response = runtime_->CallFunctionOn(*params, &outRemoteObject, &outExceptionDetails); if (outExceptionDetails) { ASSERT(outExceptionDetails.value() != nullptr); LOG_DEBUGGER(WARN) << "CallFunctionOn thrown an exception"; } if (outRemoteObject == nullptr) { SendResponse(request, response); return; } CallFunctionOnReturns result(std::move(outRemoteObject), std::move(outExceptionDetails)); SendResponse(request, response, result); } void RuntimeImpl::DispatcherImpl::GetHeapUsage(const DispatchRequest &request) { double usedSize = 0; double totalSize = 0; DispatchResponse response = runtime_->GetHeapUsage(&usedSize, &totalSize); GetHeapUsageReturns result(usedSize, totalSize); SendResponse(request, response, result); } bool RuntimeImpl::Frontend::AllowNotify() const { return channel_ != nullptr; } void RuntimeImpl::Frontend::RunIfWaitingForDebugger() { if (!AllowNotify()) { return; } channel_->RunIfWaitingForDebugger(); } DispatchResponse RuntimeImpl::Enable() { internalObjects_ = Global<MapRef>(vm_, MapRef::New(vm_)); return DispatchResponse::Ok(); } DispatchResponse RuntimeImpl::Disable() { internalObjects_.FreeGlobalHandleAddr(); return DispatchResponse::Ok(); } DispatchResponse RuntimeImpl::RunIfWaitingForDebugger() { frontend_.RunIfWaitingForDebugger(); return DispatchResponse::Ok(); } DispatchResponse RuntimeImpl::CallFunctionOn([[maybe_unused]] const CallFunctionOnParams ¶ms, std::unique_ptr<RemoteObject> *outRemoteObject, [[maybe_unused]] std::optional<std::unique_ptr<ExceptionDetails>> *outExceptionDetails) { // Return EvalError temporarily. auto error = Exception::EvalError(vm_, StringRef::NewFromUtf8(vm_, "Unsupport eval now")); *outRemoteObject = RemoteObject::FromTagged(vm_, error); return DispatchResponse::Ok(); } DispatchResponse RuntimeImpl::GetHeapUsage(double *usedSize, double *totalSize) { #ifdef ECMASCRIPT_SUPPORT_HEAPPROFILER *totalSize = static_cast<double>(DFXJSNApi::GetHeapTotalSize(vm_)); *usedSize = static_cast<double>(DFXJSNApi::GetHeapUsedSize(vm_)); #else *totalSize = 0; *usedSize = 0; #endif return DispatchResponse::Ok(); } DispatchResponse RuntimeImpl::GetProperties(const GetPropertiesParams ¶ms, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc, [[maybe_unused]] std::optional<std::vector<std::unique_ptr<InternalPropertyDescriptor>>> *outInternalDescs, [[maybe_unused]] std::optional<std::vector<std::unique_ptr<PrivatePropertyDescriptor>>> *outPrivateProps, [[maybe_unused]] std::optional<std::unique_ptr<ExceptionDetails>> *outExceptionDetails) { RemoteObjectId objectId = params.GetObjectId(); bool isOwn = params.GetOwnProperties(); bool isAccessorOnly = params.GetAccessPropertiesOnly(); auto iter = properties_.find(objectId); if (iter == properties_.end()) { LOG_DEBUGGER(ERROR) << "RuntimeImpl::GetProperties Unknown object id: " << objectId; return DispatchResponse::Fail("Unknown object id"); } Local<JSValueRef> value = Local<JSValueRef>(vm_, iter->second); if (value.IsEmpty() || !value->IsObject()) { LOG_DEBUGGER(ERROR) << "RuntimeImpl::GetProperties should a js object"; return DispatchResponse::Fail("Not a object"); } bool skipProto = false; if (!internalObjects_.IsEmpty() && internalObjects_->Get(vm_, value)->IsNumber()) { if (static_cast<ArkInternalValueType>(internalObjects_->Get(vm_, value)->ToNumber(vm_)->Value()) == ArkInternalValueType::Entry || static_cast<ArkInternalValueType>(internalObjects_->Get(vm_, value)-> ToNumber(vm_)->Value()) == ArkInternalValueType::Scope) { skipProto = true; } } if (value->IsArrayBuffer()) { Local<ArrayBufferRef> arrayBufferRef(value); AddTypedArrayRefs(arrayBufferRef, outPropertyDesc); } else if (value->IsSharedArrayBuffer()) { Local<ArrayBufferRef> arrayBufferRef(value); AddSharedArrayBufferRefs(arrayBufferRef, outPropertyDesc); } else if (value->IsProxy()) { GetProxyValue(value, outPropertyDesc); return DispatchResponse::Ok(); } else if (value->IsMapIterator()) { GetMapIteratorValue(value, outPropertyDesc); } else if (value->IsSetIterator()) { GetSetIteratorValue(value, outPropertyDesc); } else if (value->IsJSPrimitiveRef() && value->IsJSPrimitiveNumber()) { GetPrimitiveNumberValue(value, outPropertyDesc); } else if (value->IsJSPrimitiveRef() && value->IsJSPrimitiveString()) { GetPrimitiveStringValue(value, outPropertyDesc); } else if (value->IsJSPrimitiveRef() && value->IsJSPrimitiveBoolean()) { GetPrimitiveBooleanValue(value, outPropertyDesc); } else if (value->IsGeneratorFunction()) { GetGeneratorFunctionValue(value, outPropertyDesc); } else if (value->IsGeneratorObject()) { GetGeneratorObjectValue(value, outPropertyDesc); } else if (value->IsJSNumberFormat()) { GetNumberFormatValue(value, outPropertyDesc); } else if (value->IsJSCollator()) { GetCollatorValue(value, outPropertyDesc); } else if (value->IsJSDateTimeFormat()) { GetDateTimeFormatValue(value, outPropertyDesc); } else if (value->IsMap()) { GetMapValue(value, outPropertyDesc); } else if (value->IsWeakMap()) { GetWeakMapValue(value, outPropertyDesc); } else if (value->IsRegExp()) { GetRegExpValue(value, outPropertyDesc); } else if (value->IsSet()) { GetSetValue(value, outPropertyDesc); } else if (value->IsWeakSet()) { GetWeakSetValue(value, outPropertyDesc); } else if (value->IsDataView()) { GetDataViewValue(value, outPropertyDesc); } else if (value->IsHashMap()) { GetHashMapValue(value, outPropertyDesc); } else if (value->IsHashSet()) { GetHashSetValue(value, outPropertyDesc); } else if (value->IsLightWeightMap()) { GetLightWeightMapValue(value, outPropertyDesc); } else if (value->IsLightWeightSet()) { GetLightWeightSetValue(value, outPropertyDesc); } else if (value->IsLinkedList()) { GetLinkedListValue(value, outPropertyDesc); } else if (value->IsList()) { GetListValue(value, outPropertyDesc); } else if (value->IsPlainArray()) { GetPlainArrayValue(value, outPropertyDesc); } else if (value->IsTreeMap()) { GetTreeMapValue(value, outPropertyDesc); } else if (value->IsTreeSet()) { GetTreeSetValue(value, outPropertyDesc); } else if (value->IsArrayList()) { GetArrayListValue(value, outPropertyDesc); GetProtoOrProtoType(value, isOwn, isAccessorOnly, outPropertyDesc); return DispatchResponse::Ok(); } else if (value->IsDeque()) { GetDequeValue(value, outPropertyDesc); GetProtoOrProtoType(value, isOwn, isAccessorOnly, outPropertyDesc); return DispatchResponse::Ok(); } else if (value->IsQueue()) { GetQueueValue(value, outPropertyDesc); GetProtoOrProtoType(value, isOwn, isAccessorOnly, outPropertyDesc); return DispatchResponse::Ok(); } else if (value->IsStack()) { GetStackValue(value, outPropertyDesc); GetProtoOrProtoType(value, isOwn, isAccessorOnly, outPropertyDesc); return DispatchResponse::Ok(); } else if (value->IsVector()) { GetVectorValue(value, outPropertyDesc); GetProtoOrProtoType(value, isOwn, isAccessorOnly, outPropertyDesc); return DispatchResponse::Ok(); } Local<ArrayRef> keys = Local<ObjectRef>(value)->GetOwnPropertyNames(vm_); int32_t length = static_cast<int32_t>(keys->Length(vm_)); Local<JSValueRef> name = JSValueRef::Undefined(vm_); for (int32_t i = 0; i < length; ++i) { name = keys->Get(vm_, i); PropertyAttribute jsProperty = PropertyAttribute::Default(); if (!Local<ObjectRef>(value)->GetOwnProperty(vm_, name, jsProperty)) { continue; } std::unique_ptr<PropertyDescriptor> debuggerProperty = PropertyDescriptor::FromProperty(vm_, name, jsProperty); if (isAccessorOnly && !jsProperty.HasGetter() && !jsProperty.HasSetter()) { continue; } if (debuggerProperty->HasGet()) { debuggerProperty->GetGet()->SetObjectId(curObjectId_); properties_[curObjectId_++] = Global<JSValueRef>(vm_, jsProperty.GetGetter(vm_)); } if (debuggerProperty->HasSet()) { debuggerProperty->GetSet()->SetObjectId(curObjectId_); properties_[curObjectId_++] = Global<JSValueRef>(vm_, jsProperty.GetSetter(vm_)); } if (debuggerProperty->HasValue()) { Local<JSValueRef> vValue = jsProperty.GetValue(vm_); if (vValue->IsObject()) { debuggerProperty->GetValue()->SetObjectId(curObjectId_); properties_[curObjectId_++] = Global<JSValueRef>(vm_, vValue); } } if (debuggerProperty->HasSymbol()) { debuggerProperty->GetSymbol()->SetObjectId(curObjectId_); properties_[curObjectId_++] = Global<JSValueRef>(vm_, name); } outPropertyDesc->emplace_back(std::move(debuggerProperty)); } if (!skipProto) { GetProtoOrProtoType(value, isOwn, isAccessorOnly, outPropertyDesc); } GetAdditionalProperties(value, outPropertyDesc); return DispatchResponse::Ok(); } void RuntimeImpl::AddTypedArrayRefs(Local<ArrayBufferRef> arrayBufferRef, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { int32_t arrayBufferByteLength = arrayBufferRef->ByteLength(vm_); int32_t typedArrayLength = arrayBufferByteLength; AddTypedArrayRef<Int8ArrayRef>(arrayBufferRef, typedArrayLength, "[[Int8Array]]", outPropertyDesc); AddTypedArrayRef<Uint8ArrayRef>(arrayBufferRef, typedArrayLength, "[[Uint8Array]]", outPropertyDesc); AddTypedArrayRef<Uint8ClampedArrayRef>(arrayBufferRef, typedArrayLength, "[[Uint8ClampedArray]]", outPropertyDesc); if ((arrayBufferByteLength % NumberSize::BYTES_OF_16BITS) == 0) { typedArrayLength = arrayBufferByteLength / NumberSize::BYTES_OF_16BITS; AddTypedArrayRef<Int16ArrayRef>(arrayBufferRef, typedArrayLength, "[[Int16Array]]", outPropertyDesc); AddTypedArrayRef<Uint16ArrayRef>(arrayBufferRef, typedArrayLength, "[[Uint16Array]]", outPropertyDesc); } if ((arrayBufferByteLength % NumberSize::BYTES_OF_32BITS) == 0) { typedArrayLength = arrayBufferByteLength / NumberSize::BYTES_OF_32BITS; AddTypedArrayRef<Int32ArrayRef>(arrayBufferRef, typedArrayLength, "[[Int32Array]]", outPropertyDesc); AddTypedArrayRef<Uint32ArrayRef>(arrayBufferRef, typedArrayLength, "[[Uint32Array]]", outPropertyDesc); AddTypedArrayRef<Float32ArrayRef>(arrayBufferRef, typedArrayLength, "[[Float32Array]]", outPropertyDesc); } if ((arrayBufferByteLength % NumberSize::BYTES_OF_64BITS) == 0) { typedArrayLength = arrayBufferByteLength / NumberSize::BYTES_OF_64BITS; AddTypedArrayRef<Float64ArrayRef>(arrayBufferRef, typedArrayLength, "[[Float64Array]]", outPropertyDesc); AddTypedArrayRef<BigInt64ArrayRef>(arrayBufferRef, typedArrayLength, "[[BigInt64Array]]", outPropertyDesc); AddTypedArrayRef<BigUint64ArrayRef>(arrayBufferRef, typedArrayLength, "[[BigUint64Array]]", outPropertyDesc); } } void RuntimeImpl::AddSharedArrayBufferRefs(Local<ArrayBufferRef> arrayBufferRef, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { int32_t arrayBufferByteLength = arrayBufferRef->ByteLength(vm_); int32_t typedArrayLength = arrayBufferByteLength; AddTypedArrayRef<Int8ArrayRef>(arrayBufferRef, typedArrayLength, "[[Int8Array]]", outPropertyDesc); AddTypedArrayRef<Uint8ArrayRef>(arrayBufferRef, typedArrayLength, "[[Uint8Array]]", outPropertyDesc); if ((arrayBufferByteLength % NumberSize::BYTES_OF_16BITS) == 0) { typedArrayLength = arrayBufferByteLength / NumberSize::BYTES_OF_16BITS; AddTypedArrayRef<Int16ArrayRef>(arrayBufferRef, typedArrayLength, "[[Int16Array]]", outPropertyDesc); } if ((arrayBufferByteLength % NumberSize::BYTES_OF_32BITS) == 0) { typedArrayLength = arrayBufferByteLength / NumberSize::BYTES_OF_32BITS; AddTypedArrayRef<Int32ArrayRef>(arrayBufferRef, typedArrayLength, "[[Int32Array]]", outPropertyDesc); } Local<JSValueRef> jsValueRef; jsValueRef = NumberRef::New(vm_, arrayBufferByteLength); SetKeyValue(jsValueRef, outPropertyDesc, "[[ArrayBufferByteLength]]"); SetKeyValue(jsValueRef, outPropertyDesc, "byteLength"); } template <typename TypedArrayRef> void RuntimeImpl::AddTypedArrayRef(Local<ArrayBufferRef> arrayBufferRef, int32_t length, const char* name, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<JSValueRef> jsValueRefTypedArray(TypedArrayRef::New(vm_, arrayBufferRef, 0, length)); std::unique_ptr<RemoteObject> remoteObjectTypedArray = RemoteObject::FromTagged(vm_, jsValueRefTypedArray); remoteObjectTypedArray->SetObjectId(curObjectId_); properties_[curObjectId_++] = Global<JSValueRef>(vm_, jsValueRefTypedArray); std::unique_ptr<PropertyDescriptor> debuggerProperty = std::make_unique<PropertyDescriptor>(); debuggerProperty->SetName(name) .SetWritable(true) .SetConfigurable(true) .SetEnumerable(false) .SetIsOwn(true) .SetValue(std::move(remoteObjectTypedArray)); outPropertyDesc->emplace_back(std::move(debuggerProperty)); } void RuntimeImpl::CacheObjectIfNeeded(Local<JSValueRef> valRef, RemoteObject *remoteObj) { if (valRef->IsObject()) { remoteObj->SetObjectId(curObjectId_); properties_[curObjectId_++] = Global<JSValueRef>(vm_, valRef); } } void RuntimeImpl::GetProtoOrProtoType(Local<JSValueRef> value, bool isOwn, bool isAccessorOnly, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { if (!isAccessorOnly && isOwn) { return; } // Get Function ProtoOrHClass if (value->IsConstructor()) { Local<JSValueRef> prototype = Local<FunctionRef>(value)->GetFunctionPrototype(vm_); std::unique_ptr<RemoteObject> protoObj = RemoteObject::FromTagged(vm_, prototype); CacheObjectIfNeeded(prototype, protoObj.get()); std::unique_ptr<PropertyDescriptor> debuggerProperty = std::make_unique<PropertyDescriptor>(); debuggerProperty->SetName("prototype") .SetWritable(false) .SetConfigurable(false) .SetEnumerable(false) .SetIsOwn(true) .SetValue(std::move(protoObj)); outPropertyDesc->emplace_back(std::move(debuggerProperty)); } // Get __proto__ Local<JSValueRef> proto = Local<ObjectRef>(value)->GetPrototype(vm_); std::unique_ptr<RemoteObject> protoObj = RemoteObject::FromTagged(vm_, proto); CacheObjectIfNeeded(proto, protoObj.get()); std::unique_ptr<PropertyDescriptor> debuggerProperty = std::make_unique<PropertyDescriptor>(); debuggerProperty->SetName("__proto__") .SetWritable(true) .SetConfigurable(true) .SetEnumerable(false) .SetIsOwn(true) .SetValue(std::move(protoObj)); outPropertyDesc->emplace_back(std::move(debuggerProperty)); } void RuntimeImpl::GetAdditionalProperties(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { // The length of the TypedArray have to be limited(less than or equal to lengthTypedArrayLimit) until we construct // the PropertyPreview class. Let lengthTypedArrayLimit be 10000 temporarily. static const uint32_t lengthTypedArrayLimit = 10000; // The width of the string-expression for JSTypedArray::MAX_TYPED_ARRAY_INDEX which is euqal to // JSObject::MAX_ELEMENT_INDEX which is equal to std::numeric_limits<uint32_t>::max(). (42,9496,7295) static const int32_t widthStrExprMaxElementIndex = 10; if (value->IsTypedArray()) { Local<TypedArrayRef> localTypedArrayRef(value); uint32_t lengthTypedArray = localTypedArrayRef->ArrayLength(vm_); if (lengthTypedArray > lengthTypedArrayLimit) { LOG_DEBUGGER(ERROR) << "The length of the TypedArray is non-compliant or unsupported."; return; } for (uint32_t i = 0; i < lengthTypedArray; ++i) { Local<JSValueRef> localValRefElement = localTypedArrayRef->Get(vm_, i); std::unique_ptr<RemoteObject> remoteObjElement = RemoteObject::FromTagged(vm_, localValRefElement); remoteObjElement->SetObjectId(curObjectId_); properties_[curObjectId_++] = Global<JSValueRef>(vm_, localValRefElement); std::unique_ptr<PropertyDescriptor> debuggerProperty = std::make_unique<PropertyDescriptor>(); std::ostringstream osNameElement; osNameElement << std::right << std::setw(widthStrExprMaxElementIndex) << i; std::string cStrNameElement = osNameElement.str(); debuggerProperty->SetName(cStrNameElement) .SetWritable(true) .SetConfigurable(true) .SetEnumerable(false) .SetIsOwn(true) .SetValue(std::move(remoteObjElement)); outPropertyDesc->emplace_back(std::move(debuggerProperty)); } } } void RuntimeImpl::SetKeyValue(Local<JSValueRef> &jsValueRef, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc, const std::string &strProName) { std::unique_ptr<RemoteObject> remoteObj = RemoteObject::FromTagged(vm_, jsValueRef); remoteObj->SetObjectId(curObjectId_); properties_[curObjectId_++] = Global<JSValueRef>(vm_, jsValueRef); std::unique_ptr<PropertyDescriptor> debuggerProperty = std::make_unique<PropertyDescriptor>(); debuggerProperty->SetName(strProName) .SetWritable(false) .SetConfigurable(false) .SetEnumerable(false) .SetIsOwn(false) .SetValue(std::move(remoteObj)); outPropertyDesc->emplace_back(std::move(debuggerProperty)); } void RuntimeImpl::GetPrimitiveNumberValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<JSValueRef> jsValueRef; jsValueRef = value->ToNumber(vm_); SetKeyValue(jsValueRef, outPropertyDesc, "[[PrimitiveValue]]"); } void RuntimeImpl::GetPrimitiveStringValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<JSValueRef> jsValueRef; jsValueRef = value->ToString(vm_); SetKeyValue(jsValueRef, outPropertyDesc, "[[PrimitiveValue]]"); } void RuntimeImpl::GetPrimitiveBooleanValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<JSValueRef> jsValueRef; Local<PrimitiveRef> primitiveRef(value); jsValueRef = primitiveRef->GetValue(vm_); SetKeyValue(jsValueRef, outPropertyDesc, "[[PrimitiveValue]]"); } void RuntimeImpl::GetMapIteratorValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<JSValueRef> jsValueRef; Local<MapIteratorRef> iterRef = value->ToObject(vm_); if (!iterRef.IsEmpty()) { jsValueRef = NumberRef::New(vm_, iterRef->GetIndex()); SetKeyValue(jsValueRef, outPropertyDesc, "[[IteratorIndex]]"); jsValueRef = iterRef->GetKind(vm_); SetKeyValue(jsValueRef, outPropertyDesc, "[[IteratorKind]]"); } } void RuntimeImpl::GetSetIteratorValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<JSValueRef> jsValueRef; Local<SetIteratorRef> iterRef = value->ToObject(vm_); if (!iterRef.IsEmpty()) { jsValueRef = NumberRef::New(vm_, iterRef->GetIndex()); SetKeyValue(jsValueRef, outPropertyDesc, "[[IteratorIndex]]"); jsValueRef = iterRef->GetKind(vm_); SetKeyValue(jsValueRef, outPropertyDesc, "[[IteratorKind]]"); } } void RuntimeImpl::GetGeneratorFunctionValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<JSValueRef> jsValueRef; Local<GeneratorFunctionRef> genFuncRef = value->ToObject(vm_); if (!genFuncRef.IsEmpty()) { jsValueRef = BooleanRef::New(vm_, genFuncRef->IsGenerator()); SetKeyValue(jsValueRef, outPropertyDesc, "[[IsGenerator]]"); } } void RuntimeImpl::GetGeneratorObjectValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<JSValueRef> jsValueRef; Local<GeneratorObjectRef> genObjRef = value->ToObject(vm_); if (!genObjRef.IsEmpty()) { jsValueRef = genObjRef->GetGeneratorState(vm_); SetKeyValue(jsValueRef, outPropertyDesc, "[[GeneratorState]]"); jsValueRef = genObjRef->GetGeneratorFunction(vm_); SetKeyValue(jsValueRef, outPropertyDesc, "[[GeneratorFunction]]"); jsValueRef = JSNApi::GetGlobalObject(vm_); SetKeyValue(jsValueRef, outPropertyDesc, "[[GeneratorReceiver]]"); } } void RuntimeImpl::GetNumberFormatValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<NumberFormatRef> numberFormatRef = value->ToObject(vm_); Local<JSValueRef> jsValueRef = numberFormatRef->GetFormatFunction(vm_); SetKeyValue(jsValueRef, outPropertyDesc, "format"); } void RuntimeImpl::GetCollatorValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<CollatorRef> collatorRef = value->ToObject(vm_); Local<JSValueRef> jsValueRef = collatorRef->GetCompareFunction(vm_); SetKeyValue(jsValueRef, outPropertyDesc, "compare"); } void RuntimeImpl::GetDateTimeFormatValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<DataTimeFormatRef> dtFormatRef = value->ToObject(vm_); Local<JSValueRef> jsValueRef = dtFormatRef->GetFormatFunction(vm_); SetKeyValue(jsValueRef, outPropertyDesc, "format"); } void RuntimeImpl::GetMapValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<MapRef> mapRef = value->ToObject(vm_); int32_t size = mapRef->GetSize(); int32_t len = mapRef->GetTotalElements(); int32_t index = 0; Local<JSValueRef> jsValueRef = NumberRef::New(vm_, size); SetKeyValue(jsValueRef, outPropertyDesc, "size"); jsValueRef = ArrayRef::New(vm_, size); for (int32_t i = 0; i < len; ++i) { Local<JSValueRef> jsKey = mapRef->GetKey(vm_, i); if (jsKey->IsHole()) { continue; } Local<JSValueRef> jsValue = mapRef->GetValue(vm_, i); Local<ObjectRef> objRef = ObjectRef::New(vm_); objRef->Set(vm_, StringRef::NewFromUtf8(vm_, "key"), jsKey); objRef->Set(vm_, StringRef::NewFromUtf8(vm_, "value"), jsValue); DebuggerApi::AddInternalProperties(vm_, objRef, ArkInternalValueType::Entry, internalObjects_); ArrayRef::SetValueAt(vm_, jsValueRef, index++, objRef); } DebuggerApi::AddInternalProperties(vm_, jsValueRef, ArkInternalValueType::Entry, internalObjects_); SetKeyValue(jsValueRef, outPropertyDesc, "[[Entries]]"); } void RuntimeImpl::GetWeakMapValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<WeakMapRef> weakMapRef = value->ToObject(vm_); int32_t size = weakMapRef->GetSize(); int32_t len = weakMapRef->GetTotalElements(); int32_t index = 0; Local<JSValueRef> jsValueRef = NumberRef::New(vm_, size); SetKeyValue(jsValueRef, outPropertyDesc, "size"); jsValueRef = ArrayRef::New(vm_, size); for (int32_t i = 0; i < len; i++) { Local<JSValueRef> jsKey = weakMapRef->GetKey(vm_, i); if (jsKey->IsHole() || !jsKey->IsObject()) { continue; } Local<JSValueRef> jsValue = weakMapRef->GetValue(vm_, i); Local<ObjectRef> objRef = ObjectRef::New(vm_); objRef->Set(vm_, StringRef::NewFromUtf8(vm_, "key"), jsKey); objRef->Set(vm_, StringRef::NewFromUtf8(vm_, "value"), jsValue); DebuggerApi::AddInternalProperties(vm_, objRef, ArkInternalValueType::Entry, internalObjects_); ArrayRef::SetValueAt(vm_, jsValueRef, index++, objRef); } DebuggerApi::AddInternalProperties(vm_, jsValueRef, ArkInternalValueType::Entry, internalObjects_); SetKeyValue(jsValueRef, outPropertyDesc, "[[Entries]]"); } void RuntimeImpl::GetSetValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<SetRef> setRef = value->ToObject(vm_); int32_t size = setRef->GetSize(); int32_t len = setRef->GetTotalElements(); int32_t index = 0; Local<JSValueRef> jsValueRef = NumberRef::New(vm_, size); SetKeyValue(jsValueRef, outPropertyDesc, "size"); jsValueRef = ArrayRef::New(vm_, size); for (int32_t i = 0; i < len; ++i) { Local<JSValueRef> elementRef = setRef->GetValue(vm_, i); if (elementRef->IsHole()) { continue; } else if (elementRef->IsObject()) { Local<ObjectRef> objRef = ObjectRef::New(vm_); objRef->Set(vm_, StringRef::NewFromUtf8(vm_, "value"), elementRef); DebuggerApi::AddInternalProperties(vm_, objRef, ArkInternalValueType::Entry, internalObjects_); ArrayRef::SetValueAt(vm_, jsValueRef, index++, objRef); } else { ArrayRef::SetValueAt(vm_, jsValueRef, index++, elementRef); } } DebuggerApi::AddInternalProperties(vm_, jsValueRef, ArkInternalValueType::Entry, internalObjects_); SetKeyValue(jsValueRef, outPropertyDesc, "[[Entries]]"); } void RuntimeImpl::GetWeakSetValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<WeakSetRef> weakSetRef = value->ToObject(vm_); int32_t size = weakSetRef->GetSize(); int32_t len = weakSetRef->GetTotalElements(); int32_t index = 0; Local<JSValueRef> jsValueRef = NumberRef::New(vm_, size); SetKeyValue(jsValueRef, outPropertyDesc, "size"); jsValueRef = ArrayRef::New(vm_, size); for (int32_t i = 0; i < len; ++i) { Local<JSValueRef> elementRef = weakSetRef->GetValue(vm_, i); if (elementRef->IsHole()) { continue; } else if (elementRef->IsObject()) { Local<ObjectRef> objRef = ObjectRef::New(vm_); objRef->Set(vm_, StringRef::NewFromUtf8(vm_, "value"), elementRef); DebuggerApi::AddInternalProperties(vm_, objRef, ArkInternalValueType::Entry, internalObjects_); ArrayRef::SetValueAt(vm_, jsValueRef, index++, objRef); } else { ArrayRef::SetValueAt(vm_, jsValueRef, index++, elementRef); } } DebuggerApi::AddInternalProperties(vm_, jsValueRef, ArkInternalValueType::Entry, internalObjects_); SetKeyValue(jsValueRef, outPropertyDesc, "[[Entries]]"); } void RuntimeImpl::GetDataViewValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<DataViewRef> dataViewRef = value->ToObject(vm_); Local<ArrayBufferRef> buffer = dataViewRef->GetArrayBuffer(vm_); int32_t byteLength = static_cast<int32_t>(dataViewRef->ByteLength()); int32_t byteOffset = static_cast<int32_t>(dataViewRef->ByteOffset()); Local<JSValueRef> jsValueRef = ArrayBufferRef::New(vm_, buffer->ByteLength(vm_)); SetKeyValue(jsValueRef, outPropertyDesc, "buffer"); jsValueRef = NumberRef::New(vm_, byteLength); SetKeyValue(jsValueRef, outPropertyDesc, "byteLength"); jsValueRef = NumberRef::New(vm_, byteOffset); SetKeyValue(jsValueRef, outPropertyDesc, "byteOffset"); } void RuntimeImpl::GetRegExpValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<RegExpRef> regExpRef = value->ToObject(vm_); Local<JSValueRef> jsValueRef = regExpRef->IsGlobal(vm_); SetKeyValue(jsValueRef, outPropertyDesc, "global"); jsValueRef = regExpRef->IsIgnoreCase(vm_); SetKeyValue(jsValueRef, outPropertyDesc, "ignoreCase"); jsValueRef = regExpRef->IsMultiline(vm_); SetKeyValue(jsValueRef, outPropertyDesc, "multiline"); jsValueRef = regExpRef->IsDotAll(vm_); SetKeyValue(jsValueRef, outPropertyDesc, "dotAll"); SetKeyValue(jsValueRef, outPropertyDesc, "hasIndices"); jsValueRef = regExpRef->IsUtf16(vm_); SetKeyValue(jsValueRef, outPropertyDesc, "unicode"); jsValueRef = regExpRef->IsStick(vm_); SetKeyValue(jsValueRef, outPropertyDesc, "sticky"); std::string strFlags = regExpRef->GetOriginalFlags(); jsValueRef = StringRef::NewFromUtf8(vm_, strFlags.c_str()); SetKeyValue(jsValueRef, outPropertyDesc, "flags"); std::string strSource = regExpRef->GetOriginalSource(vm_)->ToString(); jsValueRef = StringRef::NewFromUtf8(vm_, strSource.c_str()); SetKeyValue(jsValueRef, outPropertyDesc, "source"); } void RuntimeImpl::GetArrayListValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<JSValueRef> jsValueRef = DebuggerApi::GetArrayListValue(vm_, value, internalObjects_); Local<JSValueRef> size = NumberRef::New(vm_, DebuggerApi::GetContainerLength(vm_, jsValueRef)); SetKeyValue(size, outPropertyDesc, "size"); SetKeyValue(jsValueRef, outPropertyDesc, "[[ArrayList]]"); } void RuntimeImpl::GetDequeValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<JSValueRef> jsValueRef = DebuggerApi::GetDequeValue(vm_, value, internalObjects_); Local<JSValueRef> size = NumberRef::New(vm_, DebuggerApi::GetContainerLength(vm_, jsValueRef)); SetKeyValue(size, outPropertyDesc, "size"); SetKeyValue(jsValueRef, outPropertyDesc, "[[Deque]]"); } void RuntimeImpl::GetHashMapValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<JSValueRef> jsValueRef = DebuggerApi::GetHashMapValue(vm_, value, internalObjects_); Local<JSValueRef> size = NumberRef::New(vm_, DebuggerApi::GetContainerLength(vm_, jsValueRef)); SetKeyValue(size, outPropertyDesc, "size"); SetKeyValue(jsValueRef, outPropertyDesc, "[[HashMap]]"); } void RuntimeImpl::GetHashSetValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<JSValueRef> jsValueRef = DebuggerApi::GetHashSetValue(vm_, value, internalObjects_); Local<JSValueRef> size = NumberRef::New(vm_, DebuggerApi::GetContainerLength(vm_, jsValueRef)); SetKeyValue(size, outPropertyDesc, "size"); SetKeyValue(jsValueRef, outPropertyDesc, "[[HashSet]]"); } void RuntimeImpl::GetLightWeightMapValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<JSValueRef> jsValueRef = DebuggerApi::GetLightWeightMapValue(vm_, value, internalObjects_); Local<JSValueRef> size = NumberRef::New(vm_, DebuggerApi::GetContainerLength(vm_, jsValueRef)); SetKeyValue(size, outPropertyDesc, "size"); SetKeyValue(jsValueRef, outPropertyDesc, "[[LightWeightMap]]"); } void RuntimeImpl::GetLightWeightSetValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<JSValueRef> jsValueRef = DebuggerApi::GetLightWeightSetValue(vm_, value, internalObjects_); Local<JSValueRef> size = NumberRef::New(vm_, DebuggerApi::GetContainerLength(vm_, jsValueRef)); SetKeyValue(size, outPropertyDesc, "size"); SetKeyValue(jsValueRef, outPropertyDesc, "[[LightWeightSet]]"); } void RuntimeImpl::GetLinkedListValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<JSValueRef> jsValueRef = DebuggerApi::GetLinkedListValue(vm_, value, internalObjects_); Local<JSValueRef> size = NumberRef::New(vm_, DebuggerApi::GetContainerLength(vm_, jsValueRef)); SetKeyValue(size, outPropertyDesc, "size"); SetKeyValue(jsValueRef, outPropertyDesc, "[[LinkedList]]"); } void RuntimeImpl::GetListValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<JSValueRef> jsValueRef = DebuggerApi::GetListValue(vm_, value, internalObjects_); Local<JSValueRef> size = NumberRef::New(vm_, DebuggerApi::GetContainerLength(vm_, jsValueRef)); SetKeyValue(size, outPropertyDesc, "size"); SetKeyValue(jsValueRef, outPropertyDesc, "[[List]]"); } void RuntimeImpl::GetPlainArrayValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<JSValueRef> jsValueRef = DebuggerApi::GetPlainArrayValue(vm_, value, internalObjects_); Local<JSValueRef> size = NumberRef::New(vm_, DebuggerApi::GetContainerLength(vm_, jsValueRef)); SetKeyValue(size, outPropertyDesc, "size"); SetKeyValue(jsValueRef, outPropertyDesc, "[[PlainArray]]"); } void RuntimeImpl::GetQueueValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<JSValueRef> jsValueRef = DebuggerApi::GetQueueValue(vm_, value, internalObjects_); Local<JSValueRef> size = NumberRef::New(vm_, DebuggerApi::GetContainerLength(vm_, jsValueRef)); SetKeyValue(size, outPropertyDesc, "size"); SetKeyValue(jsValueRef, outPropertyDesc, "[[Queue]]"); } void RuntimeImpl::GetStackValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<JSValueRef> jsValueRef = DebuggerApi::GetStackValue(vm_, value, internalObjects_); Local<JSValueRef> size = NumberRef::New(vm_, DebuggerApi::GetContainerLength(vm_, jsValueRef)); SetKeyValue(size, outPropertyDesc, "size"); SetKeyValue(jsValueRef, outPropertyDesc, "[[Stack]]"); } void RuntimeImpl::GetTreeMapValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<JSValueRef> jsValueRef = DebuggerApi::GetTreeMapValue(vm_, value, internalObjects_); Local<JSValueRef> size = NumberRef::New(vm_, DebuggerApi::GetContainerLength(vm_, jsValueRef)); SetKeyValue(size, outPropertyDesc, "size"); SetKeyValue(jsValueRef, outPropertyDesc, "[[TreeMap]]"); } void RuntimeImpl::GetTreeSetValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<JSValueRef> jsValueRef = DebuggerApi::GetTreeSetValue(vm_, value, internalObjects_); Local<JSValueRef> size = NumberRef::New(vm_, DebuggerApi::GetContainerLength(vm_, jsValueRef)); SetKeyValue(size, outPropertyDesc, "size"); SetKeyValue(jsValueRef, outPropertyDesc, "[[TreeSet]]"); } void RuntimeImpl::GetVectorValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<JSValueRef> jsValueRef = DebuggerApi::GetVectorValue(vm_, value, internalObjects_); Local<JSValueRef> size = NumberRef::New(vm_, DebuggerApi::GetContainerLength(vm_, jsValueRef)); SetKeyValue(size, outPropertyDesc, "size"); SetKeyValue(jsValueRef, outPropertyDesc, "[[Vector]]"); } void RuntimeImpl::GetProxyValue(Local<JSValueRef> value, std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc) { Local<ProxyRef> proxyRef = value->ToObject(vm_); if (proxyRef.IsEmpty()) { return; } Local<JSValueRef> target = proxyRef->GetTarget(vm_); SetKeyValue(target, outPropertyDesc, "[[Target]]"); Local<JSValueRef> handler = proxyRef->GetHandler(vm_); SetKeyValue(handler, outPropertyDesc, "[[Handler]]"); Local<JSValueRef> isRevoked = BooleanRef::New(vm_, proxyRef->IsRevoked()); SetKeyValue(isRevoked, outPropertyDesc, "[[IsRevoked]]"); } } // namespace panda::ecmascript::tooling