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 "frameworks/bridge/declarative_frontend/engine/v8/v8_utils.h"
17
18 #include "base/log/log.h"
19
20 #include "frameworks/bridge/declarative_frontend/engine/v8/v8_declarative_engine.h"
21
22 namespace OHOS::Ace::Framework {
23 namespace V8Utils {
GetObjectKeys(v8::Local<v8::Object> obj)24 std::vector<std::string> GetObjectKeys(v8::Local<v8::Object> obj)
25 {
26 auto isolate = v8::Isolate::GetCurrent();
27 auto context = isolate->GetCurrentContext();
28 v8::Local<v8::Array> arr = obj->GetPropertyNames(context, v8::KeyCollectionMode::kIncludePrototypes,
29 v8::PropertyFilter::ALL_PROPERTIES, v8::IndexFilter::kSkipIndices)
30 .ToLocalChecked();
31
32 std::vector<std::string> res;
33 for (uint32_t i = 0; i < arr->Length(); ++i) {
34 v8::Local<v8::Value> key = arr->Get(context, i).ToLocalChecked();
35 v8::String::Utf8Value s(isolate, key);
36 if (*s) {
37 res.push_back(*s);
38 }
39 }
40
41 return res;
42 }
43
JsStdDumpErrorAce(v8::Isolate * isolate,const v8::TryCatch * tryCatch)44 void JsStdDumpErrorAce(v8::Isolate* isolate, const v8::TryCatch* tryCatch)
45 {
46 v8::HandleScope handleScope(isolate);
47 auto context = isolate->GetCurrentContext();
48 auto stagingPage = static_cast<RefPtr<JsAcePage>*>(isolate->GetData(V8DeclarativeEngineInstance::STAGING_PAGE));
49
50 // dump exception message
51 v8::String::Utf8Value exception(isolate, tryCatch->Exception());
52 LOGE("[DUMP] %{private}s", *exception);
53
54 v8::Local<v8::Message> message = tryCatch->Message();
55 v8::Maybe<int> lineNumberLocal = message->GetLineNumber(context);
56 v8::MaybeLocal<v8::String> line = message->GetSourceLine(context);
57 int columnNumberStart = message->GetStartColumn();
58 int columnNumberEnd = message->GetEndColumn();
59
60 int lineNumber = -1;
61 std::string source;
62 std::string column;
63 if (!lineNumberLocal.IsNothing()) {
64 lineNumber = lineNumberLocal.ToChecked();
65 }
66
67 if (!line.IsEmpty()) {
68 v8::String::Utf8Value lineStrUtf8(isolate, line.ToLocalChecked());
69 source = *lineStrUtf8;
70 source += "\t\t";
71 }
72
73 v8::String::Utf8Value script(isolate, message->GetScriptResourceName());
74 if (!(*script)) {
75 LOGE("%{private}s", source.c_str());
76 return;
77 }
78
79 source += "(" + std::string(*script);
80 if (lineNumber != -1 && columnNumberStart != -1 && columnNumberEnd != -1) {
81 column.append(columnNumberStart, ' ');
82 column.append("^");
83 if ((columnNumberEnd - columnNumberStart) > 1) {
84 column.append(columnNumberEnd - columnNumberStart - 1, '~');
85 }
86 column.append("^");
87
88 source += ":" + std::to_string(lineNumber) + ":" + std::to_string(columnNumberStart) + "-" +
89 std::to_string(columnNumberEnd);
90 } else {
91 source += ")";
92 }
93
94 LOGE("%s", source.c_str());
95 if (!line.IsEmpty()) {
96 LOGE("%s", column.c_str());
97 }
98
99 RefPtr<RevSourceMap> pageMap;
100 RefPtr<RevSourceMap> appMap;
101 if (stagingPage && (*stagingPage)) {
102 pageMap = (*stagingPage)->GetPageMap();
103 appMap = (*stagingPage)->GetAppMap();
104 }
105
106 if (!tryCatch->StackTrace(context).IsEmpty()) {
107 v8::String::Utf8Value stackTrace(isolate, tryCatch->StackTrace(context).ToLocalChecked());
108 if (pageMap || appMap) {
109 std::string tempStack = JsStdDumpSourceFile(*stackTrace, pageMap, appMap);
110 LOGE("%{public}s", tempStack.c_str());
111 } else {
112 LOGE("%{public}s", *stackTrace);
113 }
114 }
115 }
116
ValueTypeAsString(v8::Local<v8::Value> val)117 std::string ValueTypeAsString(v8::Local<v8::Value> val)
118 {
119 auto isolate = v8::Isolate::GetCurrent();
120 v8::String::Utf8Value valType(isolate, val->TypeOf(isolate));
121 if (*valType) {
122 return *valType;
123 } else {
124 return "";
125 }
126 }
127
JsStdDumpSourceFile(const std::string & stackTrace,const RefPtr<RevSourceMap> & pageMap,const RefPtr<RevSourceMap> & appMap)128 std::string JsStdDumpSourceFile(const std::string& stackTrace, const RefPtr<RevSourceMap>& pageMap,
129 const RefPtr<RevSourceMap>& appMap)
130 {
131
132 const std::string suffix = ".js";
133 std::string ans = "";
134 std::string tempStack = stackTrace;
135 int32_t appFlag = tempStack.find("app.js");
136 bool isAppPage = appFlag > 0 && appMap;
137
138 // find per line of stack
139 std::vector<std::string> res;
140 ExtractEachInfo(tempStack, res);
141
142 // collect error info first
143 ans = ans + res[0] + "\n";
144 for (uint32_t i = 1; i < res.size(); i++) {
145 std::string temp = res[i];
146 std::string line = "";
147 std::string column = "";
148 GetPosInfo(temp, line, column);
149 if (line == "" || column == "") {
150 LOGI("the stack without line info");
151 break;
152 }
153
154 const std::string sourceInfo = GetSourceInfo(line, column, pageMap, appMap, isAppPage);
155 if (sourceInfo == "") {
156 break;
157 }
158 temp = "at " + sourceInfo;
159 ans = ans + temp + "\n";
160 }
161 if (ans == "") {
162 return tempStack;
163 }
164 return ans;
165 }
166
ExtractEachInfo(const std::string & tempStack,std::vector<std::string> & res)167 void ExtractEachInfo(const std::string& tempStack, std::vector<std::string>& res)
168 {
169 std::string tempStr = "";
170 for (uint32_t i = 0; i < tempStack.length(); i++) {
171 if (tempStack[i] == '\n') {
172 res.push_back(tempStr);
173 tempStr = "";
174 } else {
175 tempStr += tempStack[i];
176 }
177 }
178 res.push_back(tempStr);
179 }
180
GetPosInfo(const std::string & temp,std::string & line,std::string & column)181 void GetPosInfo(const std::string& temp, std::string& line, std::string& column)
182 {
183 // 0 for colum, 1 for row
184 int32_t flag = 0;
185 // find line, column
186 for (int32_t i = temp.length() - 1; i > 0; i--) {
187 if (temp[i] == ':') {
188 flag += 1;
189 continue;
190 }
191 // some stack line may end with ")"
192 if (flag == 0) {
193 if (temp[i] >= '0' && temp[i] <= '9') {
194 column = temp[i] + column;
195 }
196 } else if (flag == 1) {
197 line = temp[i] + line;
198 } else {
199 break;
200 }
201 }
202 }
203
GetSourceInfo(const std::string & line,const std::string & column,const RefPtr<RevSourceMap> & pageMap,const RefPtr<RevSourceMap> & appMap,bool isAppPage)204 std::string GetSourceInfo(const std::string& line, const std::string& column, const RefPtr<RevSourceMap>& pageMap,
205 const RefPtr<RevSourceMap>& appMap, bool isAppPage)
206 {
207 std::string sourceInfo;
208 MappingInfo mapInfo;
209 if (isAppPage) {
210 mapInfo = appMap->Find(StringToInt(line), StringToInt(column));
211 } else {
212 mapInfo = pageMap->Find(StringToInt(line), StringToInt(column));
213 }
214 if (mapInfo.row == 0 || mapInfo.col == 0) {
215 return "";
216 }
217 sourceInfo = "(" + mapInfo.sources + ":" + std::to_string(mapInfo.row) + ":" + std::to_string(mapInfo.col) + ")";
218 return sourceInfo;
219 }
220
221 } // namespace V8Utils
222 } // namespace OHOS::Ace::Framework
223