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 "ecmascript/builtins/builtins_ark_tools.h"
17
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <fcntl.h>
21 #include "ecmascript/js_function.h"
22 #include "ecmascript/base/string_helper.h"
23 #include "ecmascript/js_tagged_value-inl.h"
24 #include "ecmascript/mem/tagged_object-inl.h"
25 #include "ecmascript/napi/include/dfx_jsnapi.h"
26 #include "ecmascript/mem/clock_scope.h"
27
28 namespace panda::ecmascript::builtins {
29 using StringHelper = base::StringHelper;
30
31 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
32 constexpr char FILEDIR[] = "/data/storage/el2/base/files/";
33 #endif
ObjectDump(EcmaRuntimeCallInfo * info)34 JSTaggedValue BuiltinsArkTools::ObjectDump(EcmaRuntimeCallInfo *info)
35 {
36 ASSERT(info);
37 JSThread *thread = info->GetThread();
38 [[maybe_unused]] EcmaHandleScope handleScope(thread);
39
40 JSHandle<EcmaString> str = JSTaggedValue::ToString(thread, GetCallArg(info, 0));
41 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
42 // The default log level of ace_engine and js_runtime is error
43 LOG_ECMA(ERROR) << ": " << EcmaStringAccessor(str).ToStdString();
44
45 uint32_t numArgs = info->GetArgsNumber();
46 for (uint32_t i = 1; i < numArgs; i++) {
47 JSHandle<JSTaggedValue> obj = GetCallArg(info, i);
48 std::ostringstream oss;
49 obj->Dump(oss);
50
51 // The default log level of ace_engine and js_runtime is error
52 LOG_ECMA(ERROR) << ": " << oss.str();
53 }
54
55 return JSTaggedValue::Undefined();
56 }
57
CompareHClass(EcmaRuntimeCallInfo * info)58 JSTaggedValue BuiltinsArkTools::CompareHClass(EcmaRuntimeCallInfo *info)
59 {
60 ASSERT(info);
61 JSThread *thread = info->GetThread();
62 [[maybe_unused]] EcmaHandleScope handleScope(thread);
63
64 JSHandle<JSTaggedValue> obj1 = GetCallArg(info, 0);
65 JSHandle<JSTaggedValue> obj2 = GetCallArg(info, 1);
66 JSHClass *obj1Hclass = obj1->GetTaggedObject()->GetClass();
67 JSHClass *obj2Hclass = obj2->GetTaggedObject()->GetClass();
68 std::ostringstream oss;
69 obj1Hclass->Dump(oss);
70 obj2Hclass->Dump(oss);
71 bool res = (obj1Hclass == obj2Hclass);
72 if (!res) {
73 LOG_ECMA(ERROR) << "These two object don't share the same hclass:" << oss.str();
74 }
75 return JSTaggedValue(res);
76 }
77
DumpHClass(EcmaRuntimeCallInfo * info)78 JSTaggedValue BuiltinsArkTools::DumpHClass(EcmaRuntimeCallInfo *info)
79 {
80 ASSERT(info);
81 JSThread *thread = info->GetThread();
82 [[maybe_unused]] EcmaHandleScope handleScope(thread);
83
84 JSHandle<JSTaggedValue> obj = GetCallArg(info, 0);
85 JSHClass *objHclass = obj->GetTaggedObject()->GetClass();
86 std::ostringstream oss;
87 objHclass->Dump(oss);
88
89 LOG_ECMA(ERROR) << "hclass:" << oss.str();
90 return JSTaggedValue::Undefined();
91 }
92
IsTSHClass(EcmaRuntimeCallInfo * info)93 JSTaggedValue BuiltinsArkTools::IsTSHClass(EcmaRuntimeCallInfo *info)
94 {
95 ASSERT(info);
96 JSThread *thread = info->GetThread();
97 [[maybe_unused]] EcmaHandleScope handleScope(thread);
98
99 ASSERT(info->GetArgsNumber() == 1);
100 JSHandle<JSTaggedValue> object = GetCallArg(info, 0);
101 JSHClass *hclass = object->GetTaggedObject()->GetClass();
102 bool isTSHClass = hclass->IsTS();
103 return GetTaggedBoolean(isTSHClass);
104 }
105
GetHClass(EcmaRuntimeCallInfo * info)106 JSTaggedValue BuiltinsArkTools::GetHClass(EcmaRuntimeCallInfo *info)
107 {
108 ASSERT(info);
109 JSThread *thread = info->GetThread();
110 [[maybe_unused]] EcmaHandleScope handleScope(thread);
111
112 ASSERT(info->GetArgsNumber() == 1);
113 JSHandle<JSTaggedValue> object = GetCallArg(info, 0);
114 JSHClass *hclass = object->GetTaggedObject()->GetClass();
115 return JSTaggedValue(hclass);
116 }
117
HasTSSubtyping(EcmaRuntimeCallInfo * info)118 JSTaggedValue BuiltinsArkTools::HasTSSubtyping(EcmaRuntimeCallInfo *info)
119 {
120 ASSERT(info);
121 JSThread *thread = info->GetThread();
122 [[maybe_unused]] EcmaHandleScope handleScope(thread);
123
124 ASSERT(info->GetArgsNumber() == 1);
125 JSHandle<JSTaggedValue> object = GetCallArg(info, 0);
126 JSHClass *hclass = object->GetTaggedObject()->GetClass();
127 return GetTaggedBoolean(hclass->HasTSSubtyping());
128 }
129
IsNotHoleProperty(EcmaRuntimeCallInfo * info)130 JSTaggedValue BuiltinsArkTools::IsNotHoleProperty(EcmaRuntimeCallInfo *info)
131 {
132 [[maybe_unused]] DisallowGarbageCollection noGc;
133 ASSERT(info);
134 JSThread *thread = info->GetThread();
135 [[maybe_unused]] EcmaHandleScope handleScope(thread);
136
137 ASSERT(info->GetArgsNumber() == 2); // 2 : object and key
138 JSHandle<JSTaggedValue> object = GetCallArg(info, 0);
139 JSTaggedValue key = GetCallArg(info, 1).GetTaggedValue();
140 JSHClass *hclass = object->GetTaggedObject()->GetClass();
141 int entry = JSHClass::FindPropertyEntry(thread, hclass, key);
142 if (entry == -1) {
143 return GetTaggedBoolean(false);
144 }
145 PropertyAttributes attr = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject())->GetAttr(entry);
146 return GetTaggedBoolean(attr.IsNotHole());
147 }
148
ExcutePendingJob(EcmaRuntimeCallInfo * info)149 JSTaggedValue BuiltinsArkTools::ExcutePendingJob(EcmaRuntimeCallInfo *info)
150 {
151 ASSERT(info);
152 JSThread *thread = info->GetThread();
153 [[maybe_unused]] EcmaHandleScope handleScope(thread);
154
155 thread->GetCurrentEcmaContext()->ExecutePromisePendingJob();
156 return JSTaggedValue::True();
157 }
158
GetLexicalEnv(EcmaRuntimeCallInfo * info)159 JSTaggedValue BuiltinsArkTools::GetLexicalEnv(EcmaRuntimeCallInfo *info)
160 {
161 ASSERT(info);
162 JSThread *thread = info->GetThread();
163 [[maybe_unused]] EcmaHandleScope handleScope(thread);
164
165 ASSERT(info->GetArgsNumber() == 1);
166 JSHandle<JSTaggedValue> object = GetCallArg(info, 0);
167 if (object->IsHeapObject() && object->IsJSFunction()) {
168 JSHandle<JSFunction> function = JSHandle<JSFunction>::Cast(object);
169 return function->GetLexicalEnv();
170 }
171 return JSTaggedValue::Null();
172 }
173
ForceFullGC(EcmaRuntimeCallInfo * info)174 JSTaggedValue BuiltinsArkTools::ForceFullGC(EcmaRuntimeCallInfo *info)
175 {
176 ASSERT(info);
177 const_cast<Heap *>(info->GetThread()->GetEcmaVM()->GetHeap())->CollectGarbage(
178 TriggerGCType::FULL_GC, GCReason::EXTERNAL_TRIGGER);
179 return JSTaggedValue::True();
180 }
181
RemoveAOTFlag(EcmaRuntimeCallInfo * info)182 JSTaggedValue BuiltinsArkTools::RemoveAOTFlag(EcmaRuntimeCallInfo *info)
183 {
184 ASSERT(info);
185 JSThread *thread = info->GetThread();
186 [[maybe_unused]] EcmaHandleScope handleScope(thread);
187
188 ASSERT(info->GetArgsNumber() == 1);
189 JSHandle<JSTaggedValue> object = GetCallArg(info, 0);
190 if (object->IsHeapObject() && object->IsJSFunction()) {
191 JSHandle<JSFunction> func = JSHandle<JSFunction>::Cast(object);
192 JSHandle<Method> method = JSHandle<Method>(thread, func->GetMethod());
193 method->SetAotCodeBit(false);
194 }
195
196 return JSTaggedValue::Undefined();
197 }
198
199 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
StartCpuProfiler(EcmaRuntimeCallInfo * info)200 JSTaggedValue BuiltinsArkTools::StartCpuProfiler(EcmaRuntimeCallInfo *info)
201 {
202 ASSERT(info);
203 JSThread *thread = info->GetThread();
204 [[maybe_unused]] EcmaHandleScope handleScope(thread);
205
206 auto vm = thread->GetEcmaVM();
207
208 // get file name
209 JSHandle<JSTaggedValue> fileNameValue = GetCallArg(info, 0);
210 std::string fileName = "";
211 if (fileNameValue->IsString()) {
212 JSHandle<EcmaString> str = JSTaggedValue::ToString(thread, fileNameValue);
213 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
214 fileName = EcmaStringAccessor(str).ToStdString() + ".cpuprofile";
215 } else {
216 fileName = GetProfileName();
217 }
218
219 if (!CreateFile(fileName)) {
220 LOG_ECMA(ERROR) << "CreateFile failed " << fileName;
221 }
222
223 // get sampling interval
224 JSHandle<JSTaggedValue> samplingIntervalValue = GetCallArg(info, 1);
225 uint32_t interval = 500; // 500:Default Sampling interval 500 microseconds
226 if (samplingIntervalValue->IsNumber()) {
227 interval = JSTaggedValue::ToUint32(thread, samplingIntervalValue);
228 }
229
230 DFXJSNApi::StartCpuProfilerForFile(vm, fileName, interval);
231 return JSTaggedValue::Undefined();
232 }
233
StopCpuProfiler(EcmaRuntimeCallInfo * info)234 JSTaggedValue BuiltinsArkTools::StopCpuProfiler(EcmaRuntimeCallInfo *info)
235 {
236 JSThread *thread = info->GetThread();
237 [[maybe_unused]] EcmaHandleScope handleScope(thread);
238 auto vm = thread->GetEcmaVM();
239 DFXJSNApi::StopCpuProfilerForFile(vm);
240
241 return JSTaggedValue::Undefined();
242 }
243
GetProfileName()244 std::string BuiltinsArkTools::GetProfileName()
245 {
246 char time1[16] = {0}; // 16:Time format length
247 char time2[16] = {0}; // 16:Time format length
248 time_t timep = std::time(nullptr);
249 struct tm nowTime1;
250 localtime_r(&timep, &nowTime1);
251 size_t result = 0;
252 result = strftime(time1, sizeof(time1), "%Y%m%d", &nowTime1);
253 if (result == 0) {
254 LOG_ECMA(ERROR) << "get time failed";
255 return "";
256 }
257 result = strftime(time2, sizeof(time2), "%H%M%S", &nowTime1);
258 if (result == 0) {
259 LOG_ECMA(ERROR) << "get time failed";
260 return "";
261 }
262 std::string profileName = "cpuprofile-";
263 profileName += time1;
264 profileName += "TO";
265 profileName += time2;
266 profileName += ".cpuprofile";
267 return profileName;
268 }
269
CreateFile(std::string & fileName)270 bool BuiltinsArkTools::CreateFile(std::string &fileName)
271 {
272 std::string path = FILEDIR + fileName;
273 if (access(path.c_str(), F_OK) == 0) {
274 if (access(path.c_str(), W_OK) == 0) {
275 fileName = path;
276 return true;
277 }
278 LOG_ECMA(ERROR) << "file create failed, W_OK false";
279 return false;
280 }
281 const mode_t defaultMode = S_IRUSR | S_IWUSR | S_IRGRP; // -rw-r--
282 int fd = creat(path.c_str(), defaultMode);
283 if (fd == -1) {
284 fd = creat(fileName.c_str(), defaultMode);
285 if (fd == -1) {
286 LOG_ECMA(ERROR) << "file create failed, errno = "<< errno;
287 return false;
288 }
289 close(fd);
290 return true;
291 } else {
292 fileName = path;
293 close(fd);
294 return true;
295 }
296 }
297 #endif
298
299 // It is used to check whether an object is a proto, and this function can be
300 // used to check whether the state machine of IC is faulty.
IsPrototype(EcmaRuntimeCallInfo * info)301 JSTaggedValue BuiltinsArkTools::IsPrototype(EcmaRuntimeCallInfo *info)
302 {
303 ASSERT(info);
304 JSThread *thread = info->GetThread();
305 [[maybe_unused]] EcmaHandleScope handleScope(thread);
306
307 JSHandle<JSTaggedValue> obj = GetCallArg(info, 0);
308 JSHClass *objHclass = obj->GetTaggedObject()->GetClass();
309 return JSTaggedValue(objHclass->IsPrototype());
310 }
311
TimeInUs(EcmaRuntimeCallInfo * info)312 JSTaggedValue BuiltinsArkTools::TimeInUs([[maybe_unused]] EcmaRuntimeCallInfo *info)
313 {
314 ClockScope scope;
315 return JSTaggedValue(scope.GetCurTime());
316 }
317 } // namespace panda::ecmascript::builtins
318