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
27 namespace panda::ecmascript::builtins {
28 using StringHelper = base::StringHelper;
29
30 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
31 constexpr char FILEDIR[] = "/data/storage/el2/base/files/";
32 #endif
ObjectDump(EcmaRuntimeCallInfo * info)33 JSTaggedValue BuiltinsArkTools::ObjectDump(EcmaRuntimeCallInfo *info)
34 {
35 ASSERT(info);
36 JSThread *thread = info->GetThread();
37 [[maybe_unused]] EcmaHandleScope handleScope(thread);
38
39 JSHandle<EcmaString> str = JSTaggedValue::ToString(thread, GetCallArg(info, 0));
40 // The default log level of ace_engine and js_runtime is error
41 LOG_ECMA(ERROR) << ": " << EcmaStringAccessor(str).ToStdString();
42
43 uint32_t numArgs = info->GetArgsNumber();
44 for (uint32_t i = 1; i < numArgs; i++) {
45 JSHandle<JSTaggedValue> obj = GetCallArg(info, i);
46 std::ostringstream oss;
47 obj->Dump(oss);
48
49 // The default log level of ace_engine and js_runtime is error
50 LOG_ECMA(ERROR) << ": " << oss.str();
51 }
52
53 return JSTaggedValue::Undefined();
54 }
55
CompareHClass(EcmaRuntimeCallInfo * info)56 JSTaggedValue BuiltinsArkTools::CompareHClass(EcmaRuntimeCallInfo *info)
57 {
58 ASSERT(info);
59 JSThread *thread = info->GetThread();
60 [[maybe_unused]] EcmaHandleScope handleScope(thread);
61
62 JSHandle<JSTaggedValue> obj1 = GetCallArg(info, 0);
63 JSHandle<JSTaggedValue> obj2 = GetCallArg(info, 1);
64 JSHClass* obj1Hclass = obj1->GetTaggedObject()->GetClass();
65 JSHClass* obj2Hclass = obj2->GetTaggedObject()->GetClass();
66 std::ostringstream oss;
67 obj1Hclass->Dump(oss);
68 obj2Hclass->Dump(oss);
69 bool res = (obj1Hclass == obj2Hclass);
70 if (!res) {
71 LOG_ECMA(ERROR) << "These two object don't share the same hclass:" << oss.str();
72 }
73 return JSTaggedValue(res);
74 }
75
DumpHClass(EcmaRuntimeCallInfo * info)76 JSTaggedValue BuiltinsArkTools::DumpHClass(EcmaRuntimeCallInfo *info)
77 {
78 ASSERT(info);
79 JSThread *thread = info->GetThread();
80 [[maybe_unused]] EcmaHandleScope handleScope(thread);
81
82 JSHandle<JSTaggedValue> obj = GetCallArg(info, 0);
83 JSHClass* objHclass = obj->GetTaggedObject()->GetClass();
84 std::ostringstream oss;
85 objHclass->Dump(oss);
86
87 LOG_ECMA(ERROR) << "hclass:" << oss.str();
88 return JSTaggedValue::Undefined();
89 }
90
IsTSHClass(EcmaRuntimeCallInfo * info)91 JSTaggedValue BuiltinsArkTools::IsTSHClass(EcmaRuntimeCallInfo *info)
92 {
93 ASSERT(info);
94 JSThread *thread = info->GetThread();
95 [[maybe_unused]] EcmaHandleScope handleScope(thread);
96
97 ASSERT(info->GetArgsNumber() == 1);
98 JSHandle<JSTaggedValue> object = GetCallArg(info, 0);
99 JSHClass* hclass = object->GetTaggedObject()->GetClass();
100 bool isTSHClass = hclass->IsTS();
101 return GetTaggedBoolean(isTSHClass);
102 }
103
GetHClass(EcmaRuntimeCallInfo * info)104 JSTaggedValue BuiltinsArkTools::GetHClass(EcmaRuntimeCallInfo *info)
105 {
106 ASSERT(info);
107 JSThread *thread = info->GetThread();
108 [[maybe_unused]] EcmaHandleScope handleScope(thread);
109
110 ASSERT(info->GetArgsNumber() == 1);
111 JSHandle<JSTaggedValue> object = GetCallArg(info, 0);
112 JSHClass* hclass = object->GetTaggedObject()->GetClass();
113 return JSTaggedValue(hclass);
114 }
115
ForceFullGC(EcmaRuntimeCallInfo * info)116 JSTaggedValue BuiltinsArkTools::ForceFullGC(EcmaRuntimeCallInfo *info)
117 {
118 ASSERT(info);
119 const_cast<Heap *>(info->GetThread()->GetEcmaVM()->GetHeap())->CollectGarbage(TriggerGCType::FULL_GC);
120 return JSTaggedValue::True();
121 }
122
RemoveAOTFlag(EcmaRuntimeCallInfo * info)123 JSTaggedValue BuiltinsArkTools::RemoveAOTFlag(EcmaRuntimeCallInfo *info)
124 {
125 ASSERT(info);
126 JSThread *thread = info->GetThread();
127 [[maybe_unused]] EcmaHandleScope handleScope(thread);
128
129 ASSERT(info->GetArgsNumber() == 1);
130 JSHandle<JSTaggedValue> object = GetCallArg(info, 0);
131 JSHandle<JSFunction> func = JSHandle<JSFunction>::Cast(object);
132 JSHandle<Method> method = JSHandle<Method>(thread, func->GetMethod());
133 method->SetAotCodeBit(false);
134
135 return JSTaggedValue::Undefined();
136 }
137
138 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
StartCpuProfiler(EcmaRuntimeCallInfo * info)139 JSTaggedValue BuiltinsArkTools::StartCpuProfiler(EcmaRuntimeCallInfo *info)
140 {
141 ASSERT(info);
142 JSThread *thread = info->GetThread();
143 [[maybe_unused]] EcmaHandleScope handleScope(thread);
144
145 auto vm = thread->GetEcmaVM();
146
147 // get file name
148 JSHandle<JSTaggedValue> fileNameValue = GetCallArg(info, 0);
149 std::string fileName = "";
150 if (fileNameValue->IsString()) {
151 JSHandle<EcmaString> str = JSTaggedValue::ToString(thread, fileNameValue);
152 fileName = EcmaStringAccessor(str).ToStdString() + ".cpuprofile";
153 } else {
154 fileName = GetProfileName();
155 }
156
157 if (!CreateFile(fileName)) {
158 LOG_ECMA(ERROR) << "CreateFile failed " << fileName;
159 }
160
161 // get sampling interval
162 JSHandle<JSTaggedValue> samplingIntervalValue = GetCallArg(info, 1);
163 uint32_t interval = 500; // 500:Default Sampling interval 500 microseconds
164 if (samplingIntervalValue->IsNumber()) {
165 interval = JSTaggedValue::ToUint32(thread, samplingIntervalValue);
166 }
167
168 DFXJSNApi::StartCpuProfilerForFile(vm, fileName, interval);
169 return JSTaggedValue::Undefined();
170 }
171
StopCpuProfiler(EcmaRuntimeCallInfo * info)172 JSTaggedValue BuiltinsArkTools::StopCpuProfiler(EcmaRuntimeCallInfo *info)
173 {
174 JSThread *thread = info->GetThread();
175 [[maybe_unused]] EcmaHandleScope handleScope(thread);
176 auto vm = thread->GetEcmaVM();
177 DFXJSNApi::StopCpuProfilerForFile(vm);
178
179 return JSTaggedValue::Undefined();
180 }
181
GetProfileName()182 std::string BuiltinsArkTools::GetProfileName()
183 {
184 char time1[16] = {0}; // 16:Time format length
185 char time2[16] = {0}; // 16:Time format length
186 time_t timep = std::time(nullptr);
187 struct tm nowTime1;
188 localtime_r(&timep, &nowTime1);
189 size_t result = 0;
190 result = strftime(time1, sizeof(time1), "%Y%m%d", &nowTime1);
191 if (result == 0) {
192 LOG_ECMA(ERROR) << "get time failed";
193 return "";
194 }
195 result = strftime(time2, sizeof(time2), "%H%M%S", &nowTime1);
196 if (result == 0) {
197 LOG_ECMA(ERROR) << "get time failed";
198 return "";
199 }
200 std::string profileName = "cpuprofile-";
201 profileName += time1;
202 profileName += "TO";
203 profileName += time2;
204 profileName += ".cpuprofile";
205 return profileName;
206 }
207
CreateFile(std::string & fileName)208 bool BuiltinsArkTools::CreateFile(std::string &fileName)
209 {
210 std::string path = FILEDIR + fileName;
211 if (access(path.c_str(), F_OK) == 0) {
212 if (access(path.c_str(), W_OK) == 0) {
213 fileName = path;
214 return true;
215 }
216 LOG_ECMA(ERROR) << "file create failed, W_OK false";
217 return false;
218 }
219 const mode_t defaultMode = S_IRUSR | S_IWUSR | S_IRGRP; // -rw-r--
220 int fd = creat(path.c_str(), defaultMode);
221 if (fd == -1) {
222 fd = creat(fileName.c_str(), defaultMode);
223 if (fd == -1) {
224 LOG_ECMA(ERROR) << "file create failed, errno = "<< errno;
225 return false;
226 }
227 close(fd);
228 return true;
229 } else {
230 fileName = path;
231 close(fd);
232 return true;
233 }
234 }
235 #endif
236
237 // It is used to check whether an object is a proto, and this function can be
238 // used to check whether the state machine of IC is faulty.
IsPrototype(EcmaRuntimeCallInfo * info)239 JSTaggedValue BuiltinsArkTools::IsPrototype(EcmaRuntimeCallInfo *info)
240 {
241 ASSERT(info);
242 JSThread *thread = info->GetThread();
243 [[maybe_unused]] EcmaHandleScope handleScope(thread);
244
245 JSHandle<JSTaggedValue> obj = GetCallArg(info, 0);
246 JSHClass *objHclass = obj->GetTaggedObject()->GetClass();
247 return JSTaggedValue(objHclass->IsPrototype());
248 }
249 } // namespace panda::ecmascript::builtins
250