• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 "agent/runtime_impl.h"
17 
18 #include <iomanip>
19 
20 #include "base/pt_returns.h"
21 #include "protocol_channel.h"
22 
23 #include "ecmascript/napi/include/dfx_jsnapi.h"
24 
25 namespace panda::ecmascript::tooling {
Dispatch(const DispatchRequest & request)26 void RuntimeImpl::DispatcherImpl::Dispatch(const DispatchRequest &request)
27 {
28     static std::unordered_map<std::string, AgentHandler> dispatcherTable {
29         { "enable", &RuntimeImpl::DispatcherImpl::Enable },
30         { "getProperties", &RuntimeImpl::DispatcherImpl::GetProperties },
31         { "runIfWaitingForDebugger", &RuntimeImpl::DispatcherImpl::RunIfWaitingForDebugger },
32         { "callFunctionOn", &RuntimeImpl::DispatcherImpl::CallFunctionOn },
33         { "getHeapUsage", &RuntimeImpl::DispatcherImpl::GetHeapUsage }
34     };
35 
36     const std::string &method = request.GetMethod();
37     LOG_DEBUGGER(DEBUG) << "dispatch [" << method << "] to RuntimeImpl";
38 
39     auto entry = dispatcherTable.find(method);
40     if (entry != dispatcherTable.end()) {
41         (this->*(entry->second))(request);
42     } else {
43         LOG_DEBUGGER(ERROR) << "unknown method: " << method;
44         SendResponse(request, DispatchResponse::Fail("unknown method: " + method));
45     }
46 }
47 
Enable(const DispatchRequest & request)48 void RuntimeImpl::DispatcherImpl::Enable(const DispatchRequest &request)
49 {
50     DispatchResponse response = runtime_->Enable();
51     SendResponse(request, response);
52 }
53 
Disable(const DispatchRequest & request)54 void RuntimeImpl::DispatcherImpl::Disable(const DispatchRequest &request)
55 {
56     DispatchResponse response = runtime_->Disable();
57     SendResponse(request, response);
58 }
59 
RunIfWaitingForDebugger(const DispatchRequest & request)60 void RuntimeImpl::DispatcherImpl::RunIfWaitingForDebugger(const DispatchRequest &request)
61 {
62     DispatchResponse response = runtime_->RunIfWaitingForDebugger();
63     SendResponse(request, response);
64 }
65 
GetProperties(const DispatchRequest & request)66 void RuntimeImpl::DispatcherImpl::GetProperties(const DispatchRequest &request)
67 {
68     std::unique_ptr<GetPropertiesParams> params = GetPropertiesParams::Create(request.GetParams());
69     if (params == nullptr) {
70         SendResponse(request, DispatchResponse::Fail("wrong params"));
71         return;
72     }
73 
74     std::vector<std::unique_ptr<PropertyDescriptor>> outPropertyDesc;
75     std::optional<std::vector<std::unique_ptr<InternalPropertyDescriptor>>> outInternalDescs;
76     std::optional<std::vector<std::unique_ptr<PrivatePropertyDescriptor>>> outPrivateProperties;
77     std::optional<std::unique_ptr<ExceptionDetails>> outExceptionDetails;
78     DispatchResponse response = runtime_->GetProperties(*params, &outPropertyDesc, &outInternalDescs,
79         &outPrivateProperties, &outExceptionDetails);
80     if (outExceptionDetails) {
81         ASSERT(outExceptionDetails.value() != nullptr);
82         LOG_DEBUGGER(WARN) << "GetProperties thrown an exception";
83     }
84     GetPropertiesReturns result(std::move(outPropertyDesc),
85         std::move(outInternalDescs),
86         std::move(outPrivateProperties),
87         std::move(outExceptionDetails));
88     SendResponse(request, response, result);
89 }
90 
CallFunctionOn(const DispatchRequest & request)91 void RuntimeImpl::DispatcherImpl::CallFunctionOn(const DispatchRequest &request)
92 {
93     std::unique_ptr<CallFunctionOnParams> params = CallFunctionOnParams::Create(request.GetParams());
94     if (params == nullptr) {
95         SendResponse(request, DispatchResponse::Fail("wrong params"));
96         return;
97     }
98 
99     std::unique_ptr<RemoteObject> outRemoteObject;
100     std::optional<std::unique_ptr<ExceptionDetails>> outExceptionDetails;
101     DispatchResponse response = runtime_->CallFunctionOn(*params, &outRemoteObject, &outExceptionDetails);
102     if (outExceptionDetails) {
103         ASSERT(outExceptionDetails.value() != nullptr);
104         LOG_DEBUGGER(WARN) << "CallFunctionOn thrown an exception";
105     }
106     if (outRemoteObject == nullptr) {
107         SendResponse(request, response);
108         return;
109     }
110 
111     CallFunctionOnReturns result(std::move(outRemoteObject), std::move(outExceptionDetails));
112     SendResponse(request, response, result);
113 }
114 
GetHeapUsage(const DispatchRequest & request)115 void RuntimeImpl::DispatcherImpl::GetHeapUsage(const DispatchRequest &request)
116 {
117     double usedSize = 0;
118     double totalSize = 0;
119     DispatchResponse response = runtime_->GetHeapUsage(&usedSize, &totalSize);
120     GetHeapUsageReturns result(usedSize, totalSize);
121     SendResponse(request, response, result);
122 }
123 
AllowNotify() const124 bool RuntimeImpl::Frontend::AllowNotify() const
125 {
126     return channel_ != nullptr;
127 }
128 
RunIfWaitingForDebugger()129 void RuntimeImpl::Frontend::RunIfWaitingForDebugger()
130 {
131     if (!AllowNotify()) {
132         return;
133     }
134 
135     channel_->RunIfWaitingForDebugger();
136 }
137 
Enable()138 DispatchResponse RuntimeImpl::Enable()
139 {
140     return DispatchResponse::Ok();
141 }
142 
Disable()143 DispatchResponse RuntimeImpl::Disable()
144 {
145     return DispatchResponse::Ok();
146 }
147 
RunIfWaitingForDebugger()148 DispatchResponse RuntimeImpl::RunIfWaitingForDebugger()
149 {
150     frontend_.RunIfWaitingForDebugger();
151     return DispatchResponse::Ok();
152 }
153 
CallFunctionOn(const CallFunctionOnParams & params,std::unique_ptr<RemoteObject> * outRemoteObject,std::optional<std::unique_ptr<ExceptionDetails>> * outExceptionDetails)154 DispatchResponse RuntimeImpl::CallFunctionOn([[maybe_unused]] const CallFunctionOnParams &params,
155     std::unique_ptr<RemoteObject> *outRemoteObject,
156     [[maybe_unused]] std::optional<std::unique_ptr<ExceptionDetails>> *outExceptionDetails)
157 {
158     // Return EvalError temporarily.
159     auto error = Exception::EvalError(vm_, StringRef::NewFromUtf8(vm_, "Unsupport eval now"));
160     *outRemoteObject = RemoteObject::FromTagged(vm_, error);
161     return DispatchResponse::Ok();
162 }
163 
GetHeapUsage(double * usedSize,double * totalSize)164 DispatchResponse RuntimeImpl::GetHeapUsage(double *usedSize, double *totalSize)
165 {
166 #ifdef ECMASCRIPT_SUPPORT_HEAPPROFILER
167     *totalSize = static_cast<double>(DFXJSNApi::GetHeapTotalSize(vm_));
168     *usedSize = static_cast<double>(DFXJSNApi::GetHeapUsedSize(vm_));
169 #else
170     *totalSize = 0;
171     *usedSize = 0;
172 #endif
173     return DispatchResponse::Ok();
174 }
175 
GetProperties(const GetPropertiesParams & params,std::vector<std::unique_ptr<PropertyDescriptor>> * outPropertyDesc,std::optional<std::vector<std::unique_ptr<InternalPropertyDescriptor>>> * outInternalDescs,std::optional<std::vector<std::unique_ptr<PrivatePropertyDescriptor>>> * outPrivateProps,std::optional<std::unique_ptr<ExceptionDetails>> * outExceptionDetails)176 DispatchResponse RuntimeImpl::GetProperties(const GetPropertiesParams &params,
177     std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc,
178     [[maybe_unused]] std::optional<std::vector<std::unique_ptr<InternalPropertyDescriptor>>> *outInternalDescs,
179     [[maybe_unused]] std::optional<std::vector<std::unique_ptr<PrivatePropertyDescriptor>>> *outPrivateProps,
180     [[maybe_unused]] std::optional<std::unique_ptr<ExceptionDetails>> *outExceptionDetails)
181 {
182     RemoteObjectId objectId = params.GetObjectId();
183     bool isOwn = params.GetOwnProperties();
184     bool isAccessorOnly = params.GetAccessPropertiesOnly();
185     auto iter = properties_.find(objectId);
186     if (iter == properties_.end()) {
187         LOG_DEBUGGER(ERROR) << "RuntimeImpl::GetProperties Unknown object id: " << objectId;
188         return DispatchResponse::Fail("Unknown object id");
189     }
190     Local<JSValueRef> value = Local<JSValueRef>(vm_, iter->second);
191     if (value.IsEmpty() || !value->IsObject()) {
192         LOG_DEBUGGER(ERROR) << "RuntimeImpl::GetProperties should a js object";
193         return DispatchResponse::Fail("Not a object");
194     }
195     bool skipProto = false;
196     if (!internalObjects_.IsEmpty() && internalObjects_->Get(vm_, value)->IsNumber()) {
197         if (static_cast<ArkInternalValueType>(internalObjects_->Get(vm_, value)->ToNumber(vm_)->Value()) ==
198             ArkInternalValueType::Entry) {
199             skipProto = true;
200         }
201     }
202     if (value->IsArrayBuffer()) {
203         Local<ArrayBufferRef> arrayBufferRef(value);
204         AddTypedArrayRefs(arrayBufferRef, outPropertyDesc);
205     } else if (value->IsSharedArrayBuffer()) {
206         Local<ArrayBufferRef> arrayBufferRef(value);
207         AddSharedArrayBufferRefs(arrayBufferRef, outPropertyDesc);
208     } else if (value->IsMapIterator()) {
209         GetMapIteratorValue(value, outPropertyDesc);
210     } else if (value->IsSetIterator()) {
211         GetSetIteratorValue(value, outPropertyDesc);
212     } else if (value->IsJSPrimitiveRef() && value->IsJSPrimitiveNumber()) {
213         GetPrimitiveNumberValue(value, outPropertyDesc);
214     } else if (value->IsJSPrimitiveRef() && value->IsJSPrimitiveString()) {
215         GetPrimitiveStringValue(value, outPropertyDesc);
216     } else if (value->IsJSPrimitiveRef() && value->IsJSPrimitiveBoolean()) {
217         GetPrimitiveBooleanValue(value, outPropertyDesc);
218     } else if (value->IsGeneratorFunction()) {
219         GetGeneratorFunctionValue(value, outPropertyDesc);
220     } else if (value->IsGeneratorObject()) {
221         GetGeneratorObjectValue(value, outPropertyDesc);
222     } else if (value->IsJSNumberFormat()) {
223         GetNumberFormatValue(value, outPropertyDesc);
224     } else if (value->IsJSCollator()) {
225         GetCollatorValue(value, outPropertyDesc);
226     } else if (value->IsJSDateTimeFormat()) {
227         GetDateTimeFormatValue(value, outPropertyDesc);
228     } else if (value->IsMap()) {
229         GetMapValue(value, outPropertyDesc);
230     } else if (value->IsRegExp()) {
231         GetRegExpValue(value, outPropertyDesc);
232     } else if (value->IsSet()) {
233         GetSetValue(value, outPropertyDesc);
234     }
235     Local<ArrayRef> keys = Local<ObjectRef>(value)->GetOwnPropertyNames(vm_);
236     int32_t length = keys->Length(vm_);
237     Local<JSValueRef> name = JSValueRef::Undefined(vm_);
238     for (int32_t i = 0; i < length; ++i) {
239         name = keys->Get(vm_, i);
240         PropertyAttribute jsProperty = PropertyAttribute::Default();
241         if (!Local<ObjectRef>(value)->GetOwnProperty(vm_, name, jsProperty)) {
242             continue;
243         }
244         std::unique_ptr<PropertyDescriptor> debuggerProperty =
245             PropertyDescriptor::FromProperty(vm_, name, jsProperty);
246         if (isAccessorOnly && !jsProperty.HasGetter() && !jsProperty.HasSetter()) {
247             continue;
248         }
249         if (debuggerProperty->HasGet()) {
250             debuggerProperty->GetGet()->SetObjectId(curObjectId_);
251             properties_[curObjectId_++] = Global<JSValueRef>(vm_, jsProperty.GetGetter(vm_));
252         }
253         if (debuggerProperty->HasSet()) {
254             debuggerProperty->GetSet()->SetObjectId(curObjectId_);
255             properties_[curObjectId_++] = Global<JSValueRef>(vm_, jsProperty.GetSetter(vm_));
256         }
257         if (debuggerProperty->HasValue()) {
258             Local<JSValueRef> vValue = jsProperty.GetValue(vm_);
259             if (vValue->IsObject() && !vValue->IsProxy()) {
260                 debuggerProperty->GetValue()->SetObjectId(curObjectId_);
261                 properties_[curObjectId_++] = Global<JSValueRef>(vm_, vValue);
262             }
263         }
264         if (debuggerProperty->HasSymbol()) {
265             debuggerProperty->GetSymbol()->SetObjectId(curObjectId_);
266             properties_[curObjectId_++] = Global<JSValueRef>(vm_, name);
267         }
268         outPropertyDesc->emplace_back(std::move(debuggerProperty));
269     }
270     if (!skipProto) {
271         GetProtoOrProtoType(value, isOwn, isAccessorOnly, outPropertyDesc);
272     }
273     GetAdditionalProperties(value, outPropertyDesc);
274 
275     return DispatchResponse::Ok();
276 }
277 
AddTypedArrayRefs(Local<ArrayBufferRef> arrayBufferRef,std::vector<std::unique_ptr<PropertyDescriptor>> * outPropertyDesc)278 void RuntimeImpl::AddTypedArrayRefs(Local<ArrayBufferRef> arrayBufferRef,
279     std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc)
280 {
281     int32_t arrayBufferByteLength = arrayBufferRef->ByteLength(vm_);
282     int32_t typedArrayLength = arrayBufferByteLength;
283     AddTypedArrayRef<Int8ArrayRef>(arrayBufferRef, typedArrayLength, "[[Int8Array]]", outPropertyDesc);
284     AddTypedArrayRef<Uint8ArrayRef>(arrayBufferRef, typedArrayLength, "[[Uint8Array]]", outPropertyDesc);
285     AddTypedArrayRef<Uint8ClampedArrayRef>(arrayBufferRef, typedArrayLength, "[[Uint8ClampedArray]]", outPropertyDesc);
286 
287     if ((arrayBufferByteLength % NumberSize::BYTES_OF_16BITS) == 0) {
288         typedArrayLength = arrayBufferByteLength / NumberSize::BYTES_OF_16BITS;
289         AddTypedArrayRef<Int16ArrayRef>(arrayBufferRef, typedArrayLength, "[[Int16Array]]", outPropertyDesc);
290         AddTypedArrayRef<Uint16ArrayRef>(arrayBufferRef, typedArrayLength, "[[Uint16Array]]", outPropertyDesc);
291     }
292 
293     if ((arrayBufferByteLength % NumberSize::BYTES_OF_32BITS) == 0) {
294         typedArrayLength = arrayBufferByteLength / NumberSize::BYTES_OF_32BITS;
295         AddTypedArrayRef<Int32ArrayRef>(arrayBufferRef, typedArrayLength, "[[Int32Array]]", outPropertyDesc);
296         AddTypedArrayRef<Uint32ArrayRef>(arrayBufferRef, typedArrayLength, "[[Uint32Array]]", outPropertyDesc);
297         AddTypedArrayRef<Float32ArrayRef>(arrayBufferRef, typedArrayLength, "[[Float32Array]]", outPropertyDesc);
298     }
299 
300     if ((arrayBufferByteLength % NumberSize::BYTES_OF_64BITS) == 0) {
301         typedArrayLength = arrayBufferByteLength / NumberSize::BYTES_OF_64BITS;
302         AddTypedArrayRef<Float64ArrayRef>(arrayBufferRef, typedArrayLength, "[[Float64Array]]", outPropertyDesc);
303         AddTypedArrayRef<BigInt64ArrayRef>(arrayBufferRef, typedArrayLength, "[[BigInt64Array]]", outPropertyDesc);
304         AddTypedArrayRef<BigUint64ArrayRef>(arrayBufferRef, typedArrayLength, "[[BigUint64Array]]", outPropertyDesc);
305     }
306 }
307 
AddSharedArrayBufferRefs(Local<ArrayBufferRef> arrayBufferRef,std::vector<std::unique_ptr<PropertyDescriptor>> * outPropertyDesc)308 void RuntimeImpl::AddSharedArrayBufferRefs(Local<ArrayBufferRef> arrayBufferRef,
309     std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc)
310 {
311     int32_t arrayBufferByteLength = arrayBufferRef->ByteLength(vm_);
312     int32_t typedArrayLength = arrayBufferByteLength;
313     AddTypedArrayRef<Int8ArrayRef>(arrayBufferRef, typedArrayLength, "[[Int8Array]]", outPropertyDesc);
314     AddTypedArrayRef<Uint8ArrayRef>(arrayBufferRef, typedArrayLength, "[[Uint8Array]]", outPropertyDesc);
315 
316     if ((arrayBufferByteLength % NumberSize::BYTES_OF_16BITS) == 0) {
317         typedArrayLength = arrayBufferByteLength / NumberSize::BYTES_OF_16BITS;
318         AddTypedArrayRef<Int16ArrayRef>(arrayBufferRef, typedArrayLength, "[[Int16Array]]", outPropertyDesc);
319     }
320 
321     if ((arrayBufferByteLength % NumberSize::BYTES_OF_32BITS) == 0) {
322         typedArrayLength = arrayBufferByteLength / NumberSize::BYTES_OF_32BITS;
323         AddTypedArrayRef<Int32ArrayRef>(arrayBufferRef, typedArrayLength, "[[Int32Array]]", outPropertyDesc);
324     }
325     Local<JSValueRef> jsValueRef;
326     jsValueRef = NumberRef::New(vm_, arrayBufferByteLength);
327     SetKeyValue(jsValueRef, outPropertyDesc, "[[ArrayBufferByteLength]]");
328     SetKeyValue(jsValueRef, outPropertyDesc, "byteLength");
329 }
330 
331 template <typename TypedArrayRef>
AddTypedArrayRef(Local<ArrayBufferRef> arrayBufferRef,int32_t length,const char * name,std::vector<std::unique_ptr<PropertyDescriptor>> * outPropertyDesc)332 void RuntimeImpl::AddTypedArrayRef(Local<ArrayBufferRef> arrayBufferRef, int32_t length, const char* name,
333     std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc)
334 {
335     Local<JSValueRef> jsValueRefTypedArray(TypedArrayRef::New(vm_, arrayBufferRef, 0, length));
336     std::unique_ptr<RemoteObject> remoteObjectTypedArray = RemoteObject::FromTagged(vm_, jsValueRefTypedArray);
337     remoteObjectTypedArray->SetObjectId(curObjectId_);
338     properties_[curObjectId_++] = Global<JSValueRef>(vm_, jsValueRefTypedArray);
339     std::unique_ptr<PropertyDescriptor> debuggerProperty = std::make_unique<PropertyDescriptor>();
340     debuggerProperty->SetName(name)
341         .SetWritable(true)
342         .SetConfigurable(true)
343         .SetEnumerable(false)
344         .SetIsOwn(true)
345         .SetValue(std::move(remoteObjectTypedArray));
346     outPropertyDesc->emplace_back(std::move(debuggerProperty));
347 }
348 
CacheObjectIfNeeded(Local<JSValueRef> valRef,RemoteObject * remoteObj)349 void RuntimeImpl::CacheObjectIfNeeded(Local<JSValueRef> valRef, RemoteObject *remoteObj)
350 {
351     if (valRef->IsObject() && !valRef->IsProxy()) {
352         remoteObj->SetObjectId(curObjectId_);
353         properties_[curObjectId_++] = Global<JSValueRef>(vm_, valRef);
354     }
355 }
356 
GetProtoOrProtoType(Local<JSValueRef> value,bool isOwn,bool isAccessorOnly,std::vector<std::unique_ptr<PropertyDescriptor>> * outPropertyDesc)357 void RuntimeImpl::GetProtoOrProtoType(Local<JSValueRef> value, bool isOwn, bool isAccessorOnly,
358     std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc)
359 {
360     if (!isAccessorOnly && isOwn && !value->IsProxy()) {
361         return;
362     }
363     // Get Function ProtoOrHClass
364     if (value->IsConstructor()) {
365         Local<JSValueRef> prototype = Local<FunctionRef>(value)->GetFunctionPrototype(vm_);
366         std::unique_ptr<RemoteObject> protoObj = RemoteObject::FromTagged(vm_, prototype);
367         CacheObjectIfNeeded(prototype, protoObj.get());
368         std::unique_ptr<PropertyDescriptor> debuggerProperty = std::make_unique<PropertyDescriptor>();
369         debuggerProperty->SetName("prototype")
370             .SetWritable(false)
371             .SetConfigurable(false)
372             .SetEnumerable(false)
373             .SetIsOwn(true)
374             .SetValue(std::move(protoObj));
375         outPropertyDesc->emplace_back(std::move(debuggerProperty));
376     }
377     // Get __proto__
378     Local<JSValueRef> proto = Local<ObjectRef>(value)->GetPrototype(vm_);
379     std::unique_ptr<RemoteObject> protoObj = RemoteObject::FromTagged(vm_, proto);
380     CacheObjectIfNeeded(proto, protoObj.get());
381     std::unique_ptr<PropertyDescriptor> debuggerProperty = std::make_unique<PropertyDescriptor>();
382     debuggerProperty->SetName("__proto__")
383         .SetWritable(true)
384         .SetConfigurable(true)
385         .SetEnumerable(false)
386         .SetIsOwn(true)
387         .SetValue(std::move(protoObj));
388     outPropertyDesc->emplace_back(std::move(debuggerProperty));
389 }
390 
GetAdditionalProperties(Local<JSValueRef> value,std::vector<std::unique_ptr<PropertyDescriptor>> * outPropertyDesc)391 void RuntimeImpl::GetAdditionalProperties(Local<JSValueRef> value,
392     std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc)
393 {
394     // The length of the TypedArray have to be limited(less than or equal to lengthTypedArrayLimit) until we construct
395     // the PropertyPreview class. Let lengthTypedArrayLimit be 10000 temporarily.
396     static const uint32_t lengthTypedArrayLimit = 10000;
397 
398     // The width of the string-expression for JSTypedArray::MAX_TYPED_ARRAY_INDEX which is euqal to
399     // JSObject::MAX_ELEMENT_INDEX which is equal to std::numeric_limits<uint32_t>::max(). (42,9496,7295)
400     static const int32_t widthStrExprMaxElementIndex = 10;
401 
402     if (value->IsTypedArray()) {
403         Local<TypedArrayRef> localTypedArrayRef(value);
404         uint32_t lengthTypedArray = localTypedArrayRef->ArrayLength(vm_);
405         if (lengthTypedArray > lengthTypedArrayLimit) {
406             LOG_DEBUGGER(ERROR) << "The length of the TypedArray is non-compliant or unsupported.";
407             return;
408         }
409         for (uint32_t i = 0; i < lengthTypedArray; i++) {
410             Local<JSValueRef> localValRefElement = localTypedArrayRef->Get(vm_, i);
411             std::unique_ptr<RemoteObject> remoteObjElement = RemoteObject::FromTagged(vm_, localValRefElement);
412             remoteObjElement->SetObjectId(curObjectId_);
413             properties_[curObjectId_++] = Global<JSValueRef>(vm_, localValRefElement);
414             std::unique_ptr<PropertyDescriptor> debuggerProperty = std::make_unique<PropertyDescriptor>();
415 
416             std::ostringstream osNameElement;
417             osNameElement << std::right << std::setw(widthStrExprMaxElementIndex) << i;
418             std::string cStrNameElement = osNameElement.str();
419             debuggerProperty->SetName(cStrNameElement)
420                 .SetWritable(true)
421                 .SetConfigurable(true)
422                 .SetEnumerable(false)
423                 .SetIsOwn(true)
424                 .SetValue(std::move(remoteObjElement));
425             outPropertyDesc->emplace_back(std::move(debuggerProperty));
426         }
427     }
428 }
429 
SetKeyValue(Local<JSValueRef> & jsValueRef,std::vector<std::unique_ptr<PropertyDescriptor>> * outPropertyDesc,const std::string & strProName)430 void RuntimeImpl::SetKeyValue(Local<JSValueRef> &jsValueRef,
431     std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc, const std::string &strProName)
432 {
433     std::unique_ptr<RemoteObject> remoteObj = RemoteObject::FromTagged(vm_, jsValueRef);
434     remoteObj->SetObjectId(curObjectId_);
435     properties_[curObjectId_++] = Global<JSValueRef>(vm_, jsValueRef);
436     std::unique_ptr<PropertyDescriptor> debuggerProperty = std::make_unique<PropertyDescriptor>();
437     debuggerProperty->SetName(strProName)
438         .SetWritable(false)
439         .SetConfigurable(false)
440         .SetEnumerable(false)
441         .SetIsOwn(false)
442         .SetValue(std::move(remoteObj));
443     outPropertyDesc->emplace_back(std::move(debuggerProperty));
444 }
445 
GetPrimitiveNumberValue(Local<JSValueRef> value,std::vector<std::unique_ptr<PropertyDescriptor>> * outPropertyDesc)446 void RuntimeImpl::GetPrimitiveNumberValue(Local<JSValueRef> value,
447     std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc)
448 {
449     Local<JSValueRef> jsValueRef;
450     jsValueRef = value->ToNumber(vm_);
451     SetKeyValue(jsValueRef, outPropertyDesc, "[[PrimitiveValue]]");
452 }
453 
GetPrimitiveStringValue(Local<JSValueRef> value,std::vector<std::unique_ptr<PropertyDescriptor>> * outPropertyDesc)454 void RuntimeImpl::GetPrimitiveStringValue(Local<JSValueRef> value,
455     std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc)
456 {
457     Local<JSValueRef> jsValueRef;
458     jsValueRef = value->ToString(vm_);
459     SetKeyValue(jsValueRef, outPropertyDesc, "[[PrimitiveValue]]");
460 }
461 
GetPrimitiveBooleanValue(Local<JSValueRef> value,std::vector<std::unique_ptr<PropertyDescriptor>> * outPropertyDesc)462 void RuntimeImpl::GetPrimitiveBooleanValue(Local<JSValueRef> value,
463     std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc)
464 {
465     Local<JSValueRef> jsValueRef;
466     Local<PrimitiveRef> primitiveRef(value);
467     jsValueRef = primitiveRef->GetValue(vm_);
468     SetKeyValue(jsValueRef, outPropertyDesc, "[[PrimitiveValue]]");
469 }
470 
GetMapIteratorValue(Local<JSValueRef> value,std::vector<std::unique_ptr<PropertyDescriptor>> * outPropertyDesc)471 void RuntimeImpl::GetMapIteratorValue(Local<JSValueRef> value,
472     std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc)
473 {
474     Local<JSValueRef> jsValueRef;
475     Local<MapIteratorRef> iterRef = value->ToObject(vm_);
476     if (!iterRef.IsEmpty()) {
477         jsValueRef = NumberRef::New(vm_, iterRef->GetIndex());
478         SetKeyValue(jsValueRef, outPropertyDesc, "[[IteratorIndex]]");
479         jsValueRef = iterRef->GetKind(vm_);
480         SetKeyValue(jsValueRef, outPropertyDesc, "[[IteratorKind]]");
481     }
482 }
483 
GetSetIteratorValue(Local<JSValueRef> value,std::vector<std::unique_ptr<PropertyDescriptor>> * outPropertyDesc)484 void RuntimeImpl::GetSetIteratorValue(Local<JSValueRef> value,
485     std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc)
486 {
487     Local<JSValueRef> jsValueRef;
488     Local<SetIteratorRef> iterRef = value->ToObject(vm_);
489     if (!iterRef.IsEmpty()) {
490         jsValueRef = NumberRef::New(vm_, iterRef->GetIndex());
491         SetKeyValue(jsValueRef, outPropertyDesc, "[[IteratorIndex]]");
492         jsValueRef = iterRef->GetKind(vm_);
493         SetKeyValue(jsValueRef, outPropertyDesc, "[[IteratorKind]]");
494     }
495 }
496 
GetGeneratorFunctionValue(Local<JSValueRef> value,std::vector<std::unique_ptr<PropertyDescriptor>> * outPropertyDesc)497 void RuntimeImpl::GetGeneratorFunctionValue(Local<JSValueRef> value,
498     std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc)
499 {
500     Local<JSValueRef> jsValueRef;
501     Local<GeneratorFunctionRef> genFuncRef = value->ToObject(vm_);
502     if (!genFuncRef.IsEmpty()) {
503         jsValueRef = BooleanRef::New(vm_, genFuncRef->IsGenerator());
504         SetKeyValue(jsValueRef, outPropertyDesc, "[[IsGenerator]]");
505     }
506 }
507 
GetGeneratorObjectValue(Local<JSValueRef> value,std::vector<std::unique_ptr<PropertyDescriptor>> * outPropertyDesc)508 void RuntimeImpl::GetGeneratorObjectValue(Local<JSValueRef> value,
509     std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc)
510 {
511     Local<JSValueRef> jsValueRef;
512     Local<GeneratorObjectRef> genObjRef = value->ToObject(vm_);
513     if (!genObjRef.IsEmpty()) {
514         jsValueRef = genObjRef->GetGeneratorState(vm_);
515         SetKeyValue(jsValueRef, outPropertyDesc, "[[GeneratorState]]");
516         jsValueRef = genObjRef->GetGeneratorFunction(vm_);
517         SetKeyValue(jsValueRef, outPropertyDesc, "[[GeneratorFunction]]");
518         jsValueRef = JSNApi::GetGlobalObject(vm_);
519         SetKeyValue(jsValueRef, outPropertyDesc, "[[GeneratorReceiver]]");
520     }
521 }
522 
GetNumberFormatValue(Local<JSValueRef> value,std::vector<std::unique_ptr<PropertyDescriptor>> * outPropertyDesc)523 void RuntimeImpl::GetNumberFormatValue(Local<JSValueRef> value,
524     std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc)
525 {
526     Local<NumberFormatRef> numberFormatRef = value->ToObject(vm_);
527     Local<JSValueRef> jsValueRef = numberFormatRef->GetFormatFunction(vm_);
528     SetKeyValue(jsValueRef, outPropertyDesc, "format");
529 }
530 
GetCollatorValue(Local<JSValueRef> value,std::vector<std::unique_ptr<PropertyDescriptor>> * outPropertyDesc)531 void RuntimeImpl::GetCollatorValue(Local<JSValueRef> value,
532     std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc)
533 {
534     Local<CollatorRef> collatorRef = value->ToObject(vm_);
535     Local<JSValueRef> jsValueRef = collatorRef->GetCompareFunction(vm_);
536     SetKeyValue(jsValueRef, outPropertyDesc, "compare");
537 }
538 
GetDateTimeFormatValue(Local<JSValueRef> value,std::vector<std::unique_ptr<PropertyDescriptor>> * outPropertyDesc)539 void RuntimeImpl::GetDateTimeFormatValue(Local<JSValueRef> value,
540     std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc)
541 {
542     Local<DataTimeFormatRef> dtFormatRef = value->ToObject(vm_);
543     Local<JSValueRef> jsValueRef = dtFormatRef->GetFormatFunction(vm_);
544     SetKeyValue(jsValueRef, outPropertyDesc, "format");
545 }
546 
AddInternalProperties(Local<ObjectRef> objRef,ArkInternalValueType type)547 void RuntimeImpl::AddInternalProperties(Local<ObjectRef> objRef, ArkInternalValueType type)
548 {
549     if (internalObjects_.IsEmpty()) {
550         internalObjects_ = Global<MapRef>(vm_, MapRef::New(vm_));
551     }
552     internalObjects_->Set(vm_, objRef, NumberRef::New(vm_, static_cast<int32_t>(type)));
553 }
554 
GetMapValue(Local<JSValueRef> value,std::vector<std::unique_ptr<PropertyDescriptor>> * outPropertyDesc)555 void RuntimeImpl::GetMapValue(Local<JSValueRef> value,
556     std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc)
557 {
558     Local<MapRef> mapRef = value->ToObject(vm_);
559     int32_t size = mapRef->GetSize();
560     int32_t len = mapRef->GetTotalElements();
561     int32_t index = 0;
562     Local<JSValueRef> jsValueRef = NumberRef::New(vm_, size);
563     SetKeyValue(jsValueRef, outPropertyDesc, "size");
564     jsValueRef = ArrayRef::New(vm_, size);
565     for (int32_t i = 0; i < len; i++) {
566         Local<JSValueRef> jsKey = mapRef->GetKey(vm_, i);
567         if (jsKey->IsHole()) {
568             continue;
569         }
570         Local<JSValueRef> jsValue = mapRef->GetValue(vm_, i);
571         Local<ObjectRef> objRef = ObjectRef::New(vm_);
572         objRef->Set(vm_, StringRef::NewFromUtf8(vm_, "key"), jsKey);
573         objRef->Set(vm_, StringRef::NewFromUtf8(vm_, "value"), jsValue);
574         AddInternalProperties(objRef, ArkInternalValueType::Entry);
575         ArrayRef::SetValueAt(vm_, jsValueRef, index++, objRef);
576     }
577     AddInternalProperties(jsValueRef, ArkInternalValueType::Entry);
578     SetKeyValue(jsValueRef, outPropertyDesc, "[[Entries]]");
579 }
580 
GetSetValue(Local<JSValueRef> value,std::vector<std::unique_ptr<PropertyDescriptor>> * outPropertyDesc)581 void RuntimeImpl::GetSetValue(Local<JSValueRef> value,
582     std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc)
583 {
584     Local<SetRef> setRef = value->ToObject(vm_);
585     int32_t size = setRef->GetSize();
586     int32_t len = setRef->GetTotalElements();
587     int32_t index = 0;
588     Local<JSValueRef> jsValueRef = NumberRef::New(vm_, size);
589     SetKeyValue(jsValueRef, outPropertyDesc, "size");
590     jsValueRef = ArrayRef::New(vm_, size);
591     for (int32_t i = 0; i < len; i++) {
592         Local<JSValueRef> elementRef = setRef->GetValue(vm_, i);
593         if (elementRef->IsHole()) {
594             continue;
595         } else if (elementRef->IsObject()) {
596             Local<ObjectRef> objRef = ObjectRef::New(vm_);
597             objRef->Set(vm_, StringRef::NewFromUtf8(vm_, "value"), elementRef);
598             AddInternalProperties(objRef, ArkInternalValueType::Entry);
599             ArrayRef::SetValueAt(vm_, jsValueRef, index++, objRef);
600         } else {
601             ArrayRef::SetValueAt(vm_, jsValueRef, index++, elementRef);
602         }
603     }
604     AddInternalProperties(jsValueRef, ArkInternalValueType::Entry);
605     SetKeyValue(jsValueRef, outPropertyDesc, "[[Entries]]");
606 }
607 
GetRegExpValue(Local<JSValueRef> value,std::vector<std::unique_ptr<PropertyDescriptor>> * outPropertyDesc)608 void RuntimeImpl::GetRegExpValue(Local<JSValueRef> value,
609     std::vector<std::unique_ptr<PropertyDescriptor>> *outPropertyDesc)
610 {
611     Local<RegExpRef> regExpRef = value->ToObject(vm_);
612     Local<JSValueRef> jsValueRef = regExpRef->IsGlobal(vm_);
613     SetKeyValue(jsValueRef, outPropertyDesc, "global");
614     jsValueRef = regExpRef->IsIgnoreCase(vm_);
615     SetKeyValue(jsValueRef, outPropertyDesc, "ignoreCase");
616     jsValueRef = regExpRef->IsMultiline(vm_);
617     SetKeyValue(jsValueRef, outPropertyDesc, "multiline");
618     jsValueRef = regExpRef->IsDotAll(vm_);
619     SetKeyValue(jsValueRef, outPropertyDesc, "dotAll");
620     SetKeyValue(jsValueRef, outPropertyDesc, "hasIndices");
621     jsValueRef = regExpRef->IsUtf16(vm_);
622     SetKeyValue(jsValueRef, outPropertyDesc, "unicode");
623     jsValueRef = regExpRef->IsStick(vm_);
624     SetKeyValue(jsValueRef, outPropertyDesc, "sticky");
625     std::string strFlags = regExpRef->GetOriginalFlags();
626     jsValueRef = StringRef::NewFromUtf8(vm_, strFlags.c_str());
627     SetKeyValue(jsValueRef, outPropertyDesc, "flags");
628     std::string strSource = regExpRef->GetOriginalSource(vm_)->ToString();
629     jsValueRef = StringRef::NewFromUtf8(vm_, strSource.c_str());
630     SetKeyValue(jsValueRef, outPropertyDesc, "source");
631 }
632 }  // namespace panda::ecmascript::tooling