/* * Copyright (c) 2021-2023 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 #include "tooling/base/pt_returns.h" #include "protocol_channel.h" #include "ecmascript/napi/include/dfx_jsnapi.h" namespace panda::ecmascript::tooling { // Whenever adding a new protocol which is not a standard CDP protocol, // must add its methodName to the runtimeProtocolsList void RuntimeImpl::InitializeExtendedProtocolsList() { std::vector runtimeProtocolList {}; runtimeExtendedProtocols_ = std::move(runtimeProtocolList); } void RuntimeImpl::DispatcherImpl::Dispatch(const DispatchRequest &request) { Method method = GetMethodEnum(request.GetMethod()); LOG_DEBUGGER(DEBUG) << "dispatch [" << request.GetMethod() << "] to RuntimeImpl"; switch (method) { case Method::ENABLE: Enable(request); break; case Method::DISABLE: Disable(request); break; case Method::GET_PROPERTIES: GetProperties(request); break; case Method::RUN_IF_WAITING_FOR_DEBUGGER: RunIfWaitingForDebugger(request); break; case Method::GET_HEAP_USAGE: GetHeapUsage(request); break; default: SendResponse(request, DispatchResponse::Fail("unknown method: " + request.GetMethod())); break; } } RuntimeImpl::DispatcherImpl::Method RuntimeImpl::DispatcherImpl::GetMethodEnum(const std::string& method) { if (method == "enable") { return Method::ENABLE; } else if (method == "disable") { return Method::DISABLE; } else if (method == "getProperties") { return Method::GET_PROPERTIES; } else if (method == "runIfWaitingForDebugger") { return Method::RUN_IF_WAITING_FOR_DEBUGGER; } else if (method == "getHeapUsage") { return Method::GET_HEAP_USAGE; } else { return Method::UNKNOWN; } } void RuntimeImpl::DispatcherImpl::Enable(const DispatchRequest &request) { DispatchResponse response = runtime_->Enable(); runtime_->InitializeExtendedProtocolsList(); EnableReturns result(runtime_->runtimeExtendedProtocols_); SendResponse(request, response, result); } 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 params = GetPropertiesParams::Create(request.GetParams()); if (params == nullptr) { SendResponse(request, DispatchResponse::Fail("wrong params")); return; } std::vector> outPropertyDesc; std::optional>> outInternalDescs; std::optional>> outPrivateProperties; std::optional> 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::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(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::GetHeapUsage(double *usedSize, double *totalSize) { #ifdef ECMASCRIPT_SUPPORT_HEAPPROFILER *totalSize = static_cast(DFXJSNApi::GetHeapTotalSize(vm_)); *usedSize = static_cast(DFXJSNApi::GetHeapUsedSize(vm_)); #else *totalSize = 0; *usedSize = 0; #endif return DispatchResponse::Ok(); } DispatchResponse RuntimeImpl::GetProperties(const GetPropertiesParams ¶ms, std::vector> *outPropertyDesc, [[maybe_unused]] std::optional>> *outInternalDescs, [[maybe_unused]] std::optional>> *outPrivateProps, [[maybe_unused]] std::optional> *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 value = Local(vm_, iter->second); if (value.IsEmpty() || !value->IsObject(vm_)) { 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(internalObjects_->Get(vm_, value)->ToNumber(vm_)->Value()) == ArkInternalValueType::Entry || static_cast(internalObjects_->Get(vm_, value)-> ToNumber(vm_)->Value()) == ArkInternalValueType::Scope) { skipProto = true; } } if (value->IsArrayBuffer(vm_)) { Local arrayBufferRef(value); AddTypedArrayRefs(arrayBufferRef, outPropertyDesc); } else if (value->IsSharedArrayBuffer(vm_)) { Local arrayBufferRef(value); AddSharedArrayBufferRefs(arrayBufferRef, outPropertyDesc); } else if (value->IsProxy(vm_)) { GetProxyValue(value, outPropertyDesc); return DispatchResponse::Ok(); } else if (value->IsMapIterator(vm_)) { GetMapIteratorValue(value, outPropertyDesc); } else if (value->IsSetIterator(vm_)) { GetSetIteratorValue(value, outPropertyDesc); } else if (value->IsJSPrimitiveRef(vm_) && value->IsJSPrimitiveNumber(vm_)) { GetPrimitiveNumberValue(value, outPropertyDesc); } else if (value->IsJSPrimitiveRef(vm_) && value->IsJSPrimitiveString(vm_)) { GetPrimitiveStringValue(value, outPropertyDesc); } else if (value->IsJSPrimitiveRef(vm_) && value->IsJSPrimitiveBoolean(vm_)) { GetPrimitiveBooleanValue(value, outPropertyDesc); } else if (value->IsGeneratorFunction(vm_)) { GetGeneratorFunctionValue(value, outPropertyDesc); } else if (value->IsGeneratorObject(vm_)) { GetGeneratorObjectValue(value, outPropertyDesc); } else if (value->IsJSNumberFormat(vm_)) { GetNumberFormatValue(value, outPropertyDesc); } else if (value->IsJSCollator(vm_)) { GetCollatorValue(value, outPropertyDesc); } else if (value->IsJSDateTimeFormat(vm_)) { GetDateTimeFormatValue(value, outPropertyDesc); } else if (value->IsSharedMap(vm_)) { GetSharedMapValue(value, outPropertyDesc); } else if (value->IsMap(vm_)) { GetMapValue(value, outPropertyDesc); } else if (value->IsWeakMap(vm_)) { GetWeakMapValue(value, outPropertyDesc); } else if (value->IsRegExp(vm_)) { GetRegExpValue(value, outPropertyDesc); } else if (value->IsSharedSet(vm_)) { GetSendableSetValue(value, outPropertyDesc); } else if (value->IsSet(vm_)) { GetSetValue(value, outPropertyDesc); } else if (value->IsWeakSet(vm_)) { GetWeakSetValue(value, outPropertyDesc); } else if (value->IsDataView(vm_)) { GetDataViewValue(value, outPropertyDesc); } else if (value->IsHashMap(vm_)) { GetHashMapValue(value, outPropertyDesc); } else if (value->IsHashSet(vm_)) { GetHashSetValue(value, outPropertyDesc); } else if (value->IsLightWeightMap(vm_)) { GetLightWeightMapValue(value, outPropertyDesc); } else if (value->IsLightWeightSet(vm_)) { GetLightWeightSetValue(value, outPropertyDesc); } else if (value->IsLinkedList(vm_)) { GetLinkedListValue(value, outPropertyDesc); } else if (value->IsList(vm_)) { GetListValue(value, outPropertyDesc); } else if (value->IsPlainArray(vm_)) { GetPlainArrayValue(value, outPropertyDesc); } else if (value->IsTreeMap(vm_)) { GetTreeMapValue(value, outPropertyDesc); } else if (value->IsTreeSet(vm_)) { GetTreeSetValue(value, outPropertyDesc); } else if (value->IsArrayList(vm_)) { GetArrayListValue(value, outPropertyDesc); GetProtoOrProtoType(value, isOwn, isAccessorOnly, outPropertyDesc); return DispatchResponse::Ok(); } else if (value->IsDeque(vm_)) { GetDequeValue(value, outPropertyDesc); GetProtoOrProtoType(value, isOwn, isAccessorOnly, outPropertyDesc); return DispatchResponse::Ok(); } else if (value->IsQueue(vm_)) { GetQueueValue(value, outPropertyDesc); GetProtoOrProtoType(value, isOwn, isAccessorOnly, outPropertyDesc); return DispatchResponse::Ok(); } else if (value->IsStack(vm_)) { GetStackValue(value, outPropertyDesc); GetProtoOrProtoType(value, isOwn, isAccessorOnly, outPropertyDesc); return DispatchResponse::Ok(); } else if (value->IsVector(vm_)) { GetVectorValue(value, outPropertyDesc); GetProtoOrProtoType(value, isOwn, isAccessorOnly, outPropertyDesc); return DispatchResponse::Ok(); } else if (value->IsPromise(vm_)) { GetPromiseValue(value, outPropertyDesc); GetProtoOrProtoType(value, isOwn, isAccessorOnly, outPropertyDesc); return DispatchResponse::Ok(); } Local keys = Local(value)->GetOwnPropertyNames(vm_); int32_t length = static_cast(keys->Length(vm_)); Local name = JSValueRef::Undefined(vm_); for (int32_t i = 0; i < length; ++i) { name = keys->Get(vm_, i); PropertyAttribute jsProperty = PropertyAttribute::Default(); if (!Local(value)->GetOwnProperty(vm_, name, jsProperty)) { continue; } std::unique_ptr debuggerProperty = PropertyDescriptor::FromProperty(vm_, name, jsProperty); if (isAccessorOnly && !jsProperty.HasGetter() && !jsProperty.HasSetter()) { continue; } if (debuggerProperty->HasGet()) { debuggerProperty->GetGet()->SetObjectId(curObjectId_); properties_[curObjectId_++] = Global(vm_, jsProperty.GetGetter(vm_)); } if (debuggerProperty->HasSet()) { debuggerProperty->GetSet()->SetObjectId(curObjectId_); properties_[curObjectId_++] = Global(vm_, jsProperty.GetSetter(vm_)); } if (debuggerProperty->HasValue()) { Local vValue = jsProperty.GetValue(vm_); if (vValue->IsObject(vm_)) { debuggerProperty->GetValue()->SetObjectId(curObjectId_); properties_[curObjectId_++] = Global(vm_, vValue); } } if (debuggerProperty->HasSymbol()) { debuggerProperty->GetSymbol()->SetObjectId(curObjectId_); properties_[curObjectId_++] = Global(vm_, name); } outPropertyDesc->emplace_back(std::move(debuggerProperty)); } if (!skipProto) { GetProtoOrProtoType(value, isOwn, isAccessorOnly, outPropertyDesc); } return DispatchResponse::Ok(); } void RuntimeImpl::AddTypedArrayRefs(Local arrayBufferRef, std::vector> *outPropertyDesc) { int32_t arrayBufferByteLength = arrayBufferRef->ByteLength(vm_); int32_t typedArrayLength = arrayBufferByteLength; AddTypedArrayRef(arrayBufferRef, typedArrayLength, "[[Int8Array]]", outPropertyDesc); AddTypedArrayRef(arrayBufferRef, typedArrayLength, "[[Uint8Array]]", outPropertyDesc); AddTypedArrayRef(arrayBufferRef, typedArrayLength, "[[Uint8ClampedArray]]", outPropertyDesc); if ((arrayBufferByteLength % NumberSize::BYTES_OF_16BITS) == 0) { typedArrayLength = arrayBufferByteLength / NumberSize::BYTES_OF_16BITS; AddTypedArrayRef(arrayBufferRef, typedArrayLength, "[[Int16Array]]", outPropertyDesc); AddTypedArrayRef(arrayBufferRef, typedArrayLength, "[[Uint16Array]]", outPropertyDesc); } if ((arrayBufferByteLength % NumberSize::BYTES_OF_32BITS) == 0) { typedArrayLength = arrayBufferByteLength / NumberSize::BYTES_OF_32BITS; AddTypedArrayRef(arrayBufferRef, typedArrayLength, "[[Int32Array]]", outPropertyDesc); AddTypedArrayRef(arrayBufferRef, typedArrayLength, "[[Uint32Array]]", outPropertyDesc); AddTypedArrayRef(arrayBufferRef, typedArrayLength, "[[Float32Array]]", outPropertyDesc); } if ((arrayBufferByteLength % NumberSize::BYTES_OF_64BITS) == 0) { typedArrayLength = arrayBufferByteLength / NumberSize::BYTES_OF_64BITS; AddTypedArrayRef(arrayBufferRef, typedArrayLength, "[[Float64Array]]", outPropertyDesc); AddTypedArrayRef(arrayBufferRef, typedArrayLength, "[[BigInt64Array]]", outPropertyDesc); AddTypedArrayRef(arrayBufferRef, typedArrayLength, "[[BigUint64Array]]", outPropertyDesc); } } void RuntimeImpl::AddSharedArrayBufferRefs(Local arrayBufferRef, std::vector> *outPropertyDesc) { int32_t arrayBufferByteLength = arrayBufferRef->ByteLength(vm_); int32_t typedArrayLength = arrayBufferByteLength; AddTypedArrayRef(arrayBufferRef, typedArrayLength, "[[Int8Array]]", outPropertyDesc); AddTypedArrayRef(arrayBufferRef, typedArrayLength, "[[Uint8Array]]", outPropertyDesc); if ((arrayBufferByteLength % NumberSize::BYTES_OF_16BITS) == 0) { typedArrayLength = arrayBufferByteLength / NumberSize::BYTES_OF_16BITS; AddTypedArrayRef(arrayBufferRef, typedArrayLength, "[[Int16Array]]", outPropertyDesc); } if ((arrayBufferByteLength % NumberSize::BYTES_OF_32BITS) == 0) { typedArrayLength = arrayBufferByteLength / NumberSize::BYTES_OF_32BITS; AddTypedArrayRef(arrayBufferRef, typedArrayLength, "[[Int32Array]]", outPropertyDesc); } Local jsValueRef; jsValueRef = NumberRef::New(vm_, arrayBufferByteLength); SetKeyValue(jsValueRef, outPropertyDesc, "[[ArrayBufferByteLength]]"); SetKeyValue(jsValueRef, outPropertyDesc, "byteLength"); } template void RuntimeImpl::AddTypedArrayRef(Local arrayBufferRef, int32_t length, const char* name, std::vector> *outPropertyDesc) { Local jsValueRefTypedArray(TypedArrayRef::New(vm_, arrayBufferRef, 0, length)); std::unique_ptr remoteObjectTypedArray = RemoteObject::FromTagged(vm_, jsValueRefTypedArray); remoteObjectTypedArray->SetObjectId(curObjectId_); properties_[curObjectId_++] = Global(vm_, jsValueRefTypedArray); std::unique_ptr debuggerProperty = std::make_unique(); 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 valRef, RemoteObject *remoteObj) { if (valRef->IsObject(vm_)) { remoteObj->SetObjectId(curObjectId_); properties_[curObjectId_++] = Global(vm_, valRef); } } void RuntimeImpl::GetProtoOrProtoType(Local value, bool isOwn, bool isAccessorOnly, std::vector> *outPropertyDesc) { if (!isAccessorOnly && isOwn) { return; } // Get Function ProtoOrHClass if (value->IsConstructor(vm_)) { Local prototype = Local(value)->GetFunctionPrototype(vm_); std::unique_ptr protoObj = RemoteObject::FromTagged(vm_, prototype); CacheObjectIfNeeded(prototype, protoObj.get()); std::unique_ptr debuggerProperty = std::make_unique(); debuggerProperty->SetName("prototype") .SetWritable(false) .SetConfigurable(false) .SetEnumerable(false) .SetIsOwn(true) .SetValue(std::move(protoObj)); outPropertyDesc->emplace_back(std::move(debuggerProperty)); } // Get __proto__ Local proto = Local(value)->GetPrototype(vm_); std::unique_ptr protoObj = RemoteObject::FromTagged(vm_, proto); CacheObjectIfNeeded(proto, protoObj.get()); std::unique_ptr debuggerProperty = std::make_unique(); 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 value, std::vector> *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::max(). (42,9496,7295) static const int32_t widthStrExprMaxElementIndex = 10; if (value->IsTypedArray(vm_)) { Local 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 localValRefElement = localTypedArrayRef->Get(vm_, i); std::unique_ptr remoteObjElement = RemoteObject::FromTagged(vm_, localValRefElement); remoteObjElement->SetObjectId(curObjectId_); properties_[curObjectId_++] = Global(vm_, localValRefElement); std::unique_ptr debuggerProperty = std::make_unique(); 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, std::vector> *outPropertyDesc, const std::string &strProName) { std::unique_ptr remoteObj = RemoteObject::FromTagged(vm_, jsValueRef); remoteObj->SetObjectId(curObjectId_); properties_[curObjectId_++] = Global(vm_, jsValueRef); std::unique_ptr debuggerProperty = std::make_unique(); 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 value, std::vector> *outPropertyDesc) { Local jsValueRef; jsValueRef = value->ToNumber(vm_); SetKeyValue(jsValueRef, outPropertyDesc, "[[PrimitiveValue]]"); } void RuntimeImpl::GetPrimitiveStringValue(Local value, std::vector> *outPropertyDesc) { Local jsValueRef; jsValueRef = value->ToString(vm_); SetKeyValue(jsValueRef, outPropertyDesc, "[[PrimitiveValue]]"); } void RuntimeImpl::GetPrimitiveBooleanValue(Local value, std::vector> *outPropertyDesc) { Local jsValueRef; Local primitiveRef(value); jsValueRef = primitiveRef->GetValue(vm_); SetKeyValue(jsValueRef, outPropertyDesc, "[[PrimitiveValue]]"); } void RuntimeImpl::GetMapIteratorValue(Local value, std::vector> *outPropertyDesc) { Local jsValueRef; Local 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 value, std::vector> *outPropertyDesc) { Local jsValueRef; Local 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 value, std::vector> *outPropertyDesc) { Local jsValueRef; Local genFuncRef = value->ToObject(vm_); if (!genFuncRef.IsEmpty()) { jsValueRef = BooleanRef::New(vm_, genFuncRef->IsGenerator(vm_)); SetKeyValue(jsValueRef, outPropertyDesc, "[[IsGenerator]]"); } } void RuntimeImpl::GetGeneratorObjectValue(Local value, std::vector> *outPropertyDesc) { Local jsValueRef; Local 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 value, std::vector> *outPropertyDesc) { Local numberFormatRef = value->ToObject(vm_); Local jsValueRef = numberFormatRef->GetFormatFunction(vm_); SetKeyValue(jsValueRef, outPropertyDesc, "format"); } void RuntimeImpl::GetCollatorValue(Local value, std::vector> *outPropertyDesc) { Local collatorRef = value->ToObject(vm_); Local jsValueRef = collatorRef->GetCompareFunction(vm_); SetKeyValue(jsValueRef, outPropertyDesc, "compare"); } void RuntimeImpl::GetDateTimeFormatValue(Local value, std::vector> *outPropertyDesc) { Local dtFormatRef = value->ToObject(vm_); Local jsValueRef = dtFormatRef->GetFormatFunction(vm_); SetKeyValue(jsValueRef, outPropertyDesc, "format"); } void RuntimeImpl::GetSharedMapValue(Local value, std::vector> *outPropertyDesc) { Local sendableMapRef(value); uint32_t size = sendableMapRef->GetSize(vm_); uint32_t len = sendableMapRef->GetTotalElements(vm_); uint32_t index = 0; Local jsValueRef = NumberRef::New(vm_, size); SetKeyValue(jsValueRef, outPropertyDesc, "size"); jsValueRef = ArrayRef::New(vm_, size); for (uint32_t i = 0; i < len; ++i) { Local jsKey = sendableMapRef->GetKey(vm_, i); if (jsKey->IsHole()) { continue; } Local jsValue = sendableMapRef->GetValue(vm_, i); Local 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::GetMapValue(Local value, std::vector> *outPropertyDesc) { Local mapRef = value->ToObject(vm_); int32_t size = mapRef->GetSize(vm_); int32_t len = mapRef->GetTotalElements(vm_); int32_t index = 0; Local jsValueRef = NumberRef::New(vm_, size); SetKeyValue(jsValueRef, outPropertyDesc, "size"); jsValueRef = ArrayRef::New(vm_, size); for (int32_t i = 0; i < len; ++i) { Local jsKey = mapRef->GetKey(vm_, i); if (jsKey->IsHole()) { continue; } Local jsValue = mapRef->GetValue(vm_, i); Local 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 value, std::vector> *outPropertyDesc) { Local weakMapRef = value->ToObject(vm_); int32_t size = weakMapRef->GetSize(vm_); int32_t len = weakMapRef->GetTotalElements(vm_); int32_t index = 0; Local jsValueRef = ArrayRef::New(vm_, size); for (int32_t i = 0; i < len; i++) { Local jsKey = weakMapRef->GetKey(vm_, i); if (jsKey->IsHole() || !jsKey->IsObject(vm_)) { continue; } Local jsValue = weakMapRef->GetValue(vm_, i); Local 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::GetSendableSetValue(Local value, std::vector> *outPropertyDesc) { Local setRef = value->ToObject(vm_); uint32_t size = setRef->GetSize(vm_); uint32_t len = setRef->GetTotalElements(vm_); int32_t index = 0; Local jsValueRef = NumberRef::New(vm_, size); SetKeyValue(jsValueRef, outPropertyDesc, "size"); jsValueRef = ArrayRef::New(vm_, size); for (uint32_t i = 0; i < len; ++i) { Local elementRef = setRef->GetValue(vm_, i); if (elementRef->IsHole()) { continue; } else if (elementRef->IsObject(vm_)) { Local 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::GetSetValue(Local value, std::vector> *outPropertyDesc) { Local setRef = value->ToObject(vm_); int32_t size = setRef->GetSize(vm_); int32_t len = setRef->GetTotalElements(vm_); int32_t index = 0; Local jsValueRef = NumberRef::New(vm_, size); SetKeyValue(jsValueRef, outPropertyDesc, "size"); jsValueRef = ArrayRef::New(vm_, size); for (int32_t i = 0; i < len; ++i) { Local elementRef = setRef->GetValue(vm_, i); if (elementRef->IsHole()) { continue; } else if (elementRef->IsObject(vm_)) { Local 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 value, std::vector> *outPropertyDesc) { Local weakSetRef = value->ToObject(vm_); int32_t size = weakSetRef->GetSize(vm_); int32_t len = weakSetRef->GetTotalElements(vm_); int32_t index = 0; Local jsValueRef = ArrayRef::New(vm_, size); for (int32_t i = 0; i < len; ++i) { Local elementRef = weakSetRef->GetValue(vm_, i); if (elementRef->IsHole()) { continue; } Local 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); } DebuggerApi::AddInternalProperties(vm_, jsValueRef, ArkInternalValueType::Entry, internalObjects_); SetKeyValue(jsValueRef, outPropertyDesc, "[[Entries]]"); } void RuntimeImpl::GetDataViewValue(Local value, std::vector> *outPropertyDesc) { Local dataViewRef = value->ToObject(vm_); int32_t byteLength = static_cast(dataViewRef->ByteLength()); int32_t byteOffset = static_cast(dataViewRef->ByteOffset()); Local jsValueRef = dataViewRef->GetArrayBuffer(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 value, std::vector> *outPropertyDesc) { Local regExpRef = value->ToObject(vm_); Local 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(vm_); jsValueRef = StringRef::NewFromUtf8(vm_, strFlags.c_str()); SetKeyValue(jsValueRef, outPropertyDesc, "flags"); std::string strSource = regExpRef->GetOriginalSource(vm_)->ToString(vm_); jsValueRef = StringRef::NewFromUtf8(vm_, strSource.c_str()); SetKeyValue(jsValueRef, outPropertyDesc, "source"); } void RuntimeImpl::GetArrayListValue(Local value, std::vector> *outPropertyDesc) { Local jsValueRef = DebuggerApi::GetArrayListValue(vm_, value, internalObjects_); Local size = NumberRef::New(vm_, DebuggerApi::GetContainerLength(vm_, jsValueRef)); SetKeyValue(size, outPropertyDesc, "size"); SetKeyValue(jsValueRef, outPropertyDesc, "[[ArrayList]]"); } void RuntimeImpl::GetDequeValue(Local value, std::vector> *outPropertyDesc) { Local jsValueRef = DebuggerApi::GetDequeValue(vm_, value, internalObjects_); Local size = NumberRef::New(vm_, DebuggerApi::GetContainerLength(vm_, jsValueRef)); SetKeyValue(size, outPropertyDesc, "size"); SetKeyValue(jsValueRef, outPropertyDesc, "[[Deque]]"); } void RuntimeImpl::GetHashMapValue(Local value, std::vector> *outPropertyDesc) { Local jsValueRef = DebuggerApi::GetHashMapValue(vm_, value, internalObjects_); Local size = NumberRef::New(vm_, DebuggerApi::GetContainerLength(vm_, jsValueRef)); SetKeyValue(size, outPropertyDesc, "size"); SetKeyValue(jsValueRef, outPropertyDesc, "[[HashMap]]"); } void RuntimeImpl::GetHashSetValue(Local value, std::vector> *outPropertyDesc) { Local jsValueRef = DebuggerApi::GetHashSetValue(vm_, value, internalObjects_); Local size = NumberRef::New(vm_, DebuggerApi::GetContainerLength(vm_, jsValueRef)); SetKeyValue(size, outPropertyDesc, "size"); SetKeyValue(jsValueRef, outPropertyDesc, "[[HashSet]]"); } void RuntimeImpl::GetLightWeightMapValue(Local value, std::vector> *outPropertyDesc) { Local jsValueRef = DebuggerApi::GetLightWeightMapValue(vm_, value, internalObjects_); Local size = NumberRef::New(vm_, DebuggerApi::GetContainerLength(vm_, jsValueRef)); SetKeyValue(size, outPropertyDesc, "size"); SetKeyValue(jsValueRef, outPropertyDesc, "[[LightWeightMap]]"); } void RuntimeImpl::GetLightWeightSetValue(Local value, std::vector> *outPropertyDesc) { Local jsValueRef = DebuggerApi::GetLightWeightSetValue(vm_, value, internalObjects_); Local size = NumberRef::New(vm_, DebuggerApi::GetContainerLength(vm_, jsValueRef)); SetKeyValue(size, outPropertyDesc, "size"); SetKeyValue(jsValueRef, outPropertyDesc, "[[LightWeightSet]]"); } void RuntimeImpl::GetLinkedListValue(Local value, std::vector> *outPropertyDesc) { Local jsValueRef = DebuggerApi::GetLinkedListValue(vm_, value, internalObjects_); Local size = NumberRef::New(vm_, DebuggerApi::GetContainerLength(vm_, jsValueRef)); SetKeyValue(size, outPropertyDesc, "size"); SetKeyValue(jsValueRef, outPropertyDesc, "[[LinkedList]]"); } void RuntimeImpl::GetListValue(Local value, std::vector> *outPropertyDesc) { Local jsValueRef = DebuggerApi::GetListValue(vm_, value, internalObjects_); Local size = NumberRef::New(vm_, DebuggerApi::GetContainerLength(vm_, jsValueRef)); SetKeyValue(size, outPropertyDesc, "size"); SetKeyValue(jsValueRef, outPropertyDesc, "[[List]]"); } void RuntimeImpl::GetPlainArrayValue(Local value, std::vector> *outPropertyDesc) { Local jsValueRef = DebuggerApi::GetPlainArrayValue(vm_, value, internalObjects_); Local size = NumberRef::New(vm_, DebuggerApi::GetContainerLength(vm_, jsValueRef)); SetKeyValue(size, outPropertyDesc, "size"); SetKeyValue(jsValueRef, outPropertyDesc, "[[PlainArray]]"); } void RuntimeImpl::GetQueueValue(Local value, std::vector> *outPropertyDesc) { Local jsValueRef = DebuggerApi::GetQueueValue(vm_, value, internalObjects_); Local size = NumberRef::New(vm_, DebuggerApi::GetContainerLength(vm_, jsValueRef)); SetKeyValue(size, outPropertyDesc, "size"); SetKeyValue(jsValueRef, outPropertyDesc, "[[Queue]]"); } void RuntimeImpl::GetStackValue(Local value, std::vector> *outPropertyDesc) { Local jsValueRef = DebuggerApi::GetStackValue(vm_, value, internalObjects_); Local size = NumberRef::New(vm_, DebuggerApi::GetContainerLength(vm_, jsValueRef)); SetKeyValue(size, outPropertyDesc, "size"); SetKeyValue(jsValueRef, outPropertyDesc, "[[Stack]]"); } void RuntimeImpl::GetTreeMapValue(Local value, std::vector> *outPropertyDesc) { Local jsValueRef = DebuggerApi::GetTreeMapValue(vm_, value, internalObjects_); Local size = NumberRef::New(vm_, DebuggerApi::GetContainerLength(vm_, jsValueRef)); SetKeyValue(size, outPropertyDesc, "size"); SetKeyValue(jsValueRef, outPropertyDesc, "[[TreeMap]]"); } void RuntimeImpl::GetTreeSetValue(Local value, std::vector> *outPropertyDesc) { Local jsValueRef = DebuggerApi::GetTreeSetValue(vm_, value, internalObjects_); Local size = NumberRef::New(vm_, DebuggerApi::GetContainerLength(vm_, jsValueRef)); SetKeyValue(size, outPropertyDesc, "size"); SetKeyValue(jsValueRef, outPropertyDesc, "[[TreeSet]]"); } void RuntimeImpl::GetVectorValue(Local value, std::vector> *outPropertyDesc) { Local jsValueRef = DebuggerApi::GetVectorValue(vm_, value, internalObjects_); Local size = NumberRef::New(vm_, DebuggerApi::GetContainerLength(vm_, jsValueRef)); SetKeyValue(size, outPropertyDesc, "size"); SetKeyValue(jsValueRef, outPropertyDesc, "[[Vector]]"); } void RuntimeImpl::GetProxyValue(Local value, std::vector> *outPropertyDesc) { Local proxyRef = value->ToObject(vm_); if (proxyRef.IsEmpty()) { return; } Local target = proxyRef->GetTarget(vm_); SetKeyValue(target, outPropertyDesc, "[[Target]]"); Local handler = proxyRef->GetHandler(vm_); SetKeyValue(handler, outPropertyDesc, "[[Handler]]"); Local isRevoked = BooleanRef::New(vm_, proxyRef->IsRevoked()); SetKeyValue(isRevoked, outPropertyDesc, "[[IsRevoked]]"); } void RuntimeImpl::GetPromiseValue(Local value, std::vector> *outPropertyDesc) { Local promiseRef = value->ToObject(vm_); if (promiseRef.IsEmpty()) { return; } Local promiseState = promiseRef->GetPromiseState(vm_); SetKeyValue(promiseState, outPropertyDesc, "[[PromiseState]]"); Local promiseResult = promiseRef->GetPromiseResult(vm_); SetKeyValue(promiseResult, outPropertyDesc, "[[PromiseResult]]"); } } // namespace panda::ecmascript::tooling