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 "helpers.h"
17
18 #include <es2panda.h>
19 #include <ir/base/classDefinition.h>
20 #include <ir/base/classProperty.h>
21 #include <ir/base/methodDefinition.h>
22 #include <ir/base/property.h>
23 #include <ir/base/scriptFunction.h>
24 #include <ir/base/spreadElement.h>
25 #include <ir/expressions/arrayExpression.h>
26 #include <ir/expressions/assignmentExpression.h>
27 #include <ir/expressions/functionExpression.h>
28 #include <ir/expressions/identifier.h>
29 #include <ir/expressions/literals/numberLiteral.h>
30 #include <ir/expressions/literals/stringLiteral.h>
31 #include <ir/expressions/objectExpression.h>
32 #include <ir/expressions/unaryExpression.h>
33 #include <ir/statements/blockStatement.h>
34 #include <ir/statements/expressionStatement.h>
35 #include <ir/statements/variableDeclaration.h>
36 #include <ir/statements/variableDeclarator.h>
37 #include <ir/ts/tsParameterProperty.h>
38 #include <lexer/token/sourceLocation.h>
39 #include <parser/module/sourceTextModuleRecord.h>
40 #include <util/concurrent.h>
41
42 #ifdef ENABLE_BYTECODE_OPT
43 #include <bytecode_optimizer/bytecodeopt_options.h>
44 #include <bytecode_optimizer/optimize_bytecode.h>
45 #else
46 #include <assembly-type.h>
47 #include <assembly-program.h>
48 #include <assembly-emitter.h>
49 #endif
50
51 #ifdef PANDA_TARGET_WINDOWS
52 #include <windows.h>
53 #undef ERROR
54 #else
55 #include <unistd.h>
56 #endif
57 #include <fstream>
58 #include <iostream>
59
60 namespace panda::es2panda::util {
61
62 // Helpers
63
IsGlobalIdentifier(const util::StringView & str)64 bool Helpers::IsGlobalIdentifier(const util::StringView &str)
65 {
66 return (str.Is("NaN") || str.Is("undefined") || str.Is("Infinity"));
67 }
68
ContainSpreadElement(const ArenaVector<ir::Expression * > & args)69 bool Helpers::ContainSpreadElement(const ArenaVector<ir::Expression *> &args)
70 {
71 return std::any_of(args.begin(), args.end(), [](const auto *it) { return it->IsSpreadElement(); });
72 }
73
LiteralToPropName(ArenaAllocator * allocator,const ir::Expression * lit)74 util::StringView Helpers::LiteralToPropName(ArenaAllocator *allocator, const ir::Expression *lit)
75 {
76 switch (lit->Type()) {
77 case ir::AstNodeType::IDENTIFIER: {
78 return lit->AsIdentifier()->Name();
79 }
80 case ir::AstNodeType::STRING_LITERAL: {
81 return lit->AsStringLiteral()->Str();
82 }
83 case ir::AstNodeType::NUMBER_LITERAL: {
84 auto str = lit->AsNumberLiteral()->Str();
85 auto number = lit->AsNumberLiteral()->Number();
86
87 // "e" and "E" represent scientific notation.
88 if ((str.Find("e") == std::string::npos && str.Find("E") == std::string::npos) &&
89 Helpers::IsInteger<uint32_t>(number) && number != 0) {
90 return str;
91 }
92
93 return Helpers::ToStringView(allocator, number);
94 }
95 case ir::AstNodeType::NULL_LITERAL: {
96 return "null";
97 }
98 default: {
99 UNREACHABLE();
100 }
101 }
102 }
103
IsIndex(double number)104 bool Helpers::IsIndex(double number)
105 {
106 if (number >= 0 && number < static_cast<double>(INVALID_INDEX)) {
107 auto intNum = static_cast<uint32_t>(number);
108
109 if (static_cast<double>(intNum) == number) {
110 return true;
111 }
112 }
113
114 return false;
115 }
116
IsDigit(char c)117 static bool IsDigit(char c)
118 {
119 return (c >= '0' && c <= '9');
120 }
121
GetIndex(const util::StringView & str)122 int64_t Helpers::GetIndex(const util::StringView &str)
123 {
124 const auto &s = str.Utf8();
125
126 if (s.empty() || (*s.begin() == '0' && s.length() > 1)) {
127 return INVALID_INDEX;
128 }
129
130 int64_t value = 0;
131 for (const auto c : s) {
132 if (!IsDigit(c)) {
133 return INVALID_INDEX;
134 }
135
136 constexpr auto MULTIPLIER = 10;
137 value *= MULTIPLIER;
138 value += (c - '0');
139
140 if (value >= INVALID_INDEX) {
141 return INVALID_INDEX;
142 }
143 }
144
145 return value;
146 }
147
FileExtensionIs(std::string_view filePath,std::string_view extension)148 bool Helpers::FileExtensionIs(std::string_view filePath, std::string_view extension)
149 {
150 return filePath.length() > extension.length() && Helpers::EndsWith(filePath, extension);
151 }
152
EndsWith(std::string_view str,std::string_view suffix)153 bool Helpers::EndsWith(std::string_view str, std::string_view suffix)
154 {
155 if (str.length() < suffix.length()) {
156 return false;
157 }
158 size_t expectPos = str.length() - suffix.length();
159 return str.find(suffix, expectPos) == expectPos;
160 }
161
GetScientificNotationForDouble(double number,uint32_t significandBitCount,int32_t & numberBitCount,char * significandArray,char * sciNotationArray,uint32_t size)162 void Helpers::GetScientificNotationForDouble(double number, uint32_t significandBitCount, int32_t &numberBitCount,
163 char *significandArray, char *sciNotationArray, uint32_t size)
164 {
165 if (size < MAX_DOUBLE_DIGIT) {
166 std::cerr << "Failed to set the size of buffer in snprintf_s!" << std::endl;
167 return;
168 }
169 if (snprintf_s(sciNotationArray, size, size - 1, "%.*e", significandBitCount - 1, number) == FAIL_SNPRINTF_S) {
170 std::cerr << "Failed to write number to buffer in snprintf_s!" << std::endl;
171 return;
172 }
173
174 // sciNotationArray includes significand, '.' and 'e'
175 // If significandBitCount == 1, sciNotationArray does not contain '.'
176 int32_t exponent = atoi(sciNotationArray + significandBitCount + 1 + (significandBitCount > 1));
177 numberBitCount = exponent + 1;
178
179 // Get the significand of the current sciNotationArray
180 if (significandBitCount > 1) {
181 for (uint32_t i = 0; i < significandBitCount + 1; i++) {
182 significandArray[i] = sciNotationArray[i];
183 }
184 }
185
186 significandArray[significandBitCount + 1] = '\0';
187 }
188
GetIntegerSignificandBitCount(double number,int32_t & numberBitCount,char * significandArray)189 int32_t Helpers::GetIntegerSignificandBitCount(double number, int32_t &numberBitCount, char *significandArray)
190 {
191 uint32_t bitPos = 0;
192 uint32_t minBitPos = 1;
193 uint32_t maxBitPos = MAX_DOUBLE_PRECISION_DIGIT;
194 uint32_t integerAndPointBitCount = 2;
195 char sciNotationArray[MAX_DOUBLE_DIGIT] = {0};
196
197 while (minBitPos < maxBitPos) {
198 bitPos = (minBitPos + maxBitPos) / 2; // 2: binary search
199 GetScientificNotationForDouble(number, bitPos, numberBitCount, significandArray,
200 sciNotationArray, sizeof(sciNotationArray));
201
202 // Update bitPos
203 if (std::strtod(sciNotationArray, nullptr) == number) {
204 while (bitPos >= integerAndPointBitCount && significandArray[bitPos] == '0') {
205 bitPos--;
206 }
207 maxBitPos = bitPos;
208 } else {
209 minBitPos = bitPos + 1;
210 }
211 }
212
213 // minBitPos == maxBitPos
214 bitPos = maxBitPos;
215 GetScientificNotationForDouble(number, bitPos, numberBitCount, significandArray,
216 sciNotationArray, sizeof(sciNotationArray));
217
218 return bitPos;
219 }
220
DoubleToString(double number)221 std::string Helpers::DoubleToString(double number)
222 {
223 // In Scientific notation, number is expressed in the form of significand multiplied by exponent-th power of 10.
224 // The range of significand is: 1 <= |significand| < 10
225 // Scientific notation of number: sciNotationArray = significand * (10 ** exponent)
226 // number 1.23e25 => sciNotationArray: 1.23e+25, significand: 1.23, exponent: 25,
227
228 // In the ECMAScript, integerSignificand, integerSignificandBitCount and numberBitCount are defined as an integer:
229 // 1. integerSignificand is an integer in the Decimal representation of Scientific notation.
230 // 2. integerSignificandBitCount is the number of bits in the Decimal representation of significand.
231 // 3. numberBitCount is the number of bits in the Decimal representation of number.
232 // Scientific notation of number in the ECMAScript of Number::toString (number):
233 // integerSciNotationArray = integerSignificand * (10 ** (numberBitCount - integerSignificandBitCount))
234 // number 1.23e25 => integerSciNotationArray: 123e+23, integerSignificand: 123, integerExponent: 23,
235 // integerSignificandBitCount: 3, numberBitCount: 26
236 std::string result;
237 int32_t numberBitCount = 0;
238 char significandArray[MAX_DOUBLE_DIGIT] = {0};
239
240 if (number < 0) {
241 result += "-";
242 number = -number;
243 }
244
245 // The number of bits of significand in integer form
246 int32_t integerSignificandBitCount = GetIntegerSignificandBitCount(number, numberBitCount, significandArray);
247
248 std::string significand = significandArray;
249 std::string integerSignificand;
250 if (numberBitCount > 0 && numberBitCount <= MAX_DECIMAL_EXPONENT) {
251 integerSignificand = significand.erase(1, 1);
252 if (numberBitCount >= integerSignificandBitCount) {
253 // If integerSignificandBitCount ≤ numberBitCount ≤ 21, return the string represented by Decimal,
254 // integerSignificand followed by (numberBitCount - integerSignificandBitCount) digit zeros.
255 integerSignificand += std::string(numberBitCount - integerSignificandBitCount, '0');
256 } else {
257 // If 0 < numberBitCount < integerSignificandBitCount, return the string represented by Decimal,
258 // integerSignificand followed by point on the (numberBitCount + 1) digit.
259 integerSignificand.insert(numberBitCount, 1, '.');
260 }
261 } else if (numberBitCount <= 0 && numberBitCount > MIN_DECIMAL_EXPONENT) {
262 // If -6 < numberBitCount ≤ 0, return the string consisting of "0." and digit zeros represented by Decimal,
263 // string followed by integerSignificand.
264 integerSignificand = significand.erase(1, 1);
265 integerSignificand = std::string("0.") + std::string(-numberBitCount, '0') + integerSignificand;
266 } else {
267 // If integerSignificandBitCount == 1, return the string consisting of the single digit of significand.
268 if (integerSignificandBitCount == 1) {
269 significand = significand.erase(1, 1);
270 }
271 // If numberBitCount ≤ -6 or numberBitCount > 21, return the string represented by Scientific notation,
272 // integerSignificand followed by "e", symbol and (numberBitCount - 1) digit zeros.
273 significand += 'e' + (numberBitCount >= 1 ? std::string("+") : "") + std::to_string(numberBitCount - 1);
274
275 result += significand;
276 return result;
277 }
278
279 result += integerSignificand;
280 return result;
281 }
282
ToString(double number)283 std::string Helpers::ToString(double number)
284 {
285 if (std::isnan(number)) {
286 return "NaN";
287 }
288 if (number == 0.0) {
289 return "0";
290 }
291 if (std::isinf(number)) {
292 return "Infinity";
293 }
294
295 std::string str;
296 if (Helpers::IsInteger<int32_t>(number)) {
297 str = std::to_string(static_cast<int32_t>(number));
298 } else {
299 str = DoubleToString(number);
300 }
301
302 return str;
303 }
304
ToStringView(ArenaAllocator * allocator,double number)305 util::StringView Helpers::ToStringView(ArenaAllocator *allocator, double number)
306 {
307 util::UString str(ToString(number), allocator);
308 return str.View();
309 }
310
ToStringView(ArenaAllocator * allocator,uint32_t number)311 util::StringView Helpers::ToStringView(ArenaAllocator *allocator, uint32_t number)
312 {
313 ASSERT(number <= static_cast<uint32_t>(std::numeric_limits<int32_t>::max()));
314 return ToStringView(allocator, static_cast<int32_t>(number));
315 }
316
ToStringView(ArenaAllocator * allocator,int32_t number)317 util::StringView Helpers::ToStringView(ArenaAllocator *allocator, int32_t number)
318 {
319 util::UString str(ToString(number), allocator);
320 return str.View();
321 }
322
GetContainingConstructor(const ir::AstNode * node)323 const ir::ScriptFunction *Helpers::GetContainingConstructor(const ir::AstNode *node)
324 {
325 const ir::ScriptFunction *iter = GetContainingFunction(node);
326
327 while (iter != nullptr) {
328 if (iter->IsConstructor()) {
329 return iter;
330 }
331
332 if (!iter->IsArrow()) {
333 return nullptr;
334 }
335
336 iter = GetContainingFunction(iter);
337 }
338
339 return iter;
340 }
341
GetContainingConstructor(const ir::ClassProperty * node)342 const ir::ScriptFunction *Helpers::GetContainingConstructor(const ir::ClassProperty *node)
343 {
344 for (const auto *parent = node->Parent(); parent != nullptr; parent = parent->Parent()) {
345 if (parent->IsClassDefinition()) {
346 return parent->AsClassDefinition()->Ctor()->Function();
347 }
348 }
349
350 return nullptr;
351 }
352
GetContainingFunction(const ir::AstNode * node)353 const ir::ScriptFunction *Helpers::GetContainingFunction(const ir::AstNode *node)
354 {
355 for (const auto *parent = node->Parent(); parent != nullptr; parent = parent->Parent()) {
356 if (parent->IsScriptFunction()) {
357 return parent->AsScriptFunction();
358 }
359 }
360
361 return nullptr;
362 }
363
GetClassDefiniton(const ir::ScriptFunction * node)364 const ir::ClassDefinition *Helpers::GetClassDefiniton(const ir::ScriptFunction *node)
365 {
366 ASSERT(node->IsConstructor());
367 ASSERT(node->Parent()->IsFunctionExpression());
368 ASSERT(node->Parent()->Parent()->IsMethodDefinition());
369 ASSERT(node->Parent()->Parent()->Parent()->IsClassDefinition());
370
371 return node->Parent()->Parent()->Parent()->AsClassDefinition();
372 }
373
IsSpecialPropertyKey(const ir::Expression * expr)374 bool Helpers::IsSpecialPropertyKey(const ir::Expression *expr)
375 {
376 if (!expr->IsStringLiteral()) {
377 return false;
378 }
379
380 auto *lit = expr->AsStringLiteral();
381 return lit->Str().Is("prototype") || lit->Str().Is("constructor");
382 }
383
IsConstantPropertyKey(const ir::Expression * expr,bool isComputed)384 bool Helpers::IsConstantPropertyKey(const ir::Expression *expr, bool isComputed)
385 {
386 switch (expr->Type()) {
387 case ir::AstNodeType::IDENTIFIER: {
388 return !isComputed;
389 }
390 case ir::AstNodeType::NUMBER_LITERAL:
391 case ir::AstNodeType::STRING_LITERAL:
392 case ir::AstNodeType::BOOLEAN_LITERAL:
393 case ir::AstNodeType::NULL_LITERAL: {
394 return true;
395 }
396 default:
397 break;
398 }
399
400 return false;
401 }
402
IsConstantExpr(const ir::Expression * expr)403 bool Helpers::IsConstantExpr(const ir::Expression *expr)
404 {
405 switch (expr->Type()) {
406 case ir::AstNodeType::NUMBER_LITERAL:
407 case ir::AstNodeType::STRING_LITERAL:
408 case ir::AstNodeType::BOOLEAN_LITERAL:
409 case ir::AstNodeType::NULL_LITERAL: {
410 return true;
411 }
412 default:
413 break;
414 }
415
416 return false;
417 }
418
IsBindingPattern(const ir::AstNode * node)419 bool Helpers::IsBindingPattern(const ir::AstNode *node)
420 {
421 return node->IsArrayPattern() || node->IsObjectPattern();
422 }
423
IsPattern(const ir::AstNode * node)424 bool Helpers::IsPattern(const ir::AstNode *node)
425 {
426 return node->IsArrayPattern() || node->IsObjectPattern() || node->IsAssignmentPattern();
427 }
428
CollectBindingName(const ir::AstNode * node,std::vector<const ir::Identifier * > * bindings)429 static void CollectBindingName(const ir::AstNode *node, std::vector<const ir::Identifier *> *bindings)
430 {
431 switch (node->Type()) {
432 case ir::AstNodeType::IDENTIFIER: {
433 if (!Helpers::IsGlobalIdentifier(node->AsIdentifier()->Name())) {
434 bindings->push_back(node->AsIdentifier());
435 }
436
437 break;
438 }
439 case ir::AstNodeType::OBJECT_PATTERN: {
440 for (const auto *prop : node->AsObjectPattern()->Properties()) {
441 CollectBindingName(prop, bindings);
442 }
443 break;
444 }
445 case ir::AstNodeType::ARRAY_PATTERN: {
446 for (const auto *element : node->AsArrayPattern()->Elements()) {
447 CollectBindingName(element, bindings);
448 }
449 break;
450 }
451 case ir::AstNodeType::ASSIGNMENT_PATTERN: {
452 CollectBindingName(node->AsAssignmentPattern()->Left(), bindings);
453 break;
454 }
455 case ir::AstNodeType::PROPERTY: {
456 CollectBindingName(node->AsProperty()->Value(), bindings);
457 break;
458 }
459 case ir::AstNodeType::REST_ELEMENT: {
460 CollectBindingName(node->AsRestElement()->Argument(), bindings);
461 break;
462 }
463 default:
464 break;
465 }
466 }
467
CollectBindingNames(const ir::AstNode * node)468 std::vector<const ir::Identifier *> Helpers::CollectBindingNames(const ir::AstNode *node)
469 {
470 std::vector<const ir::Identifier *> bindings;
471 CollectBindingName(node, &bindings);
472 return bindings;
473 }
474
FunctionName(ArenaAllocator * allocator,const ir::ScriptFunction * func)475 util::StringView Helpers::FunctionName(ArenaAllocator *allocator, const ir::ScriptFunction *func)
476 {
477 if (func->Id()) {
478 return func->Id()->Name();
479 }
480
481 if (func->Parent()->IsFunctionDeclaration()) {
482 return parser::SourceTextModuleRecord::DEFAULT_EXTERNAL_NAME;
483 }
484
485 const ir::AstNode *parent = func->Parent()->Parent();
486
487 if (func->IsConstructor()) {
488 parent = parent->Parent();
489 if (parent->AsClassDefinition()->Ident()) {
490 return parent->AsClassDefinition()->Ident()->Name();
491 }
492
493 parent = parent->Parent()->Parent();
494 }
495
496 switch (parent->Type()) {
497 case ir::AstNodeType::VARIABLE_DECLARATOR: {
498 const ir::VariableDeclarator *varDecl = parent->AsVariableDeclarator();
499
500 if (varDecl->Id()->IsIdentifier()) {
501 return varDecl->Id()->AsIdentifier()->Name();
502 }
503
504 break;
505 }
506 case ir::AstNodeType::METHOD_DEFINITION: {
507 const ir::MethodDefinition *methodDef = parent->AsMethodDefinition();
508
509 if (methodDef->Key()->IsIdentifier()) {
510 return methodDef->Key()->AsIdentifier()->Name();
511 }
512
513 break;
514 }
515 case ir::AstNodeType::ASSIGNMENT_EXPRESSION: {
516 const ir::AssignmentExpression *assignment = parent->AsAssignmentExpression();
517
518 if (assignment->Left()->IsIdentifier()) {
519 return assignment->Left()->AsIdentifier()->Name();
520 }
521
522 break;
523 }
524 case ir::AstNodeType::ASSIGNMENT_PATTERN: {
525 const ir::AssignmentExpression *assignment = parent->AsAssignmentPattern();
526
527 if (assignment->Left()->IsIdentifier()) {
528 return assignment->Left()->AsIdentifier()->Name();
529 }
530
531 break;
532 }
533 case ir::AstNodeType::PROPERTY: {
534 const ir::Property *prop = parent->AsProperty();
535
536 if (prop->Kind() != ir::PropertyKind::PROTO &&
537 Helpers::IsConstantPropertyKey(prop->Key(), prop->IsComputed())) {
538 return Helpers::LiteralToPropName(allocator, prop->Key());
539 }
540
541 break;
542 }
543 case ir::AstNodeType::EXPORT_DEFAULT_DECLARATION: {
544 return parser::SourceTextModuleRecord::DEFAULT_EXTERNAL_NAME;
545 }
546 default:
547 break;
548 }
549
550 return util::StringView();
551 }
552
ParamName(ArenaAllocator * allocator,const ir::AstNode * param,uint32_t index)553 std::tuple<util::StringView, bool> Helpers::ParamName(ArenaAllocator *allocator, const ir::AstNode *param,
554 uint32_t index)
555 {
556 switch (param->Type()) {
557 case ir::AstNodeType::IDENTIFIER: {
558 return {param->AsIdentifier()->Name(), false};
559 }
560 case ir::AstNodeType::ASSIGNMENT_PATTERN: {
561 const auto *lhs = param->AsAssignmentPattern()->Left();
562 if (lhs->IsIdentifier()) {
563 return {param->AsAssignmentPattern()->Left()->AsIdentifier()->Name(), false};
564 }
565 break;
566 }
567 case ir::AstNodeType::REST_ELEMENT: {
568 if (param->AsRestElement()->Argument()->IsIdentifier()) {
569 return {param->AsRestElement()->Argument()->AsIdentifier()->Name(), false};
570 }
571 break;
572 }
573 case ir::AstNodeType::TS_PARAMETER_PROPERTY: {
574 return ParamName(allocator, param->AsTSParameterProperty()->Parameter(), index);
575 }
576 default:
577 break;
578 }
579
580 return {Helpers::ToStringView(allocator, index), true};
581 }
582
IsChild(const ir::AstNode * parent,const ir::AstNode * child)583 bool Helpers::IsChild(const ir::AstNode *parent, const ir::AstNode *child)
584 {
585 while (child) {
586 if (child == parent) {
587 return true;
588 }
589
590 child = child->Parent();
591 }
592
593 return false;
594 }
595
IsObjectPropertyValue(const ArenaVector<ir::Expression * > & properties,const ir::AstNode * ident)596 bool Helpers::IsObjectPropertyValue(const ArenaVector<ir::Expression *> &properties, const ir::AstNode *ident)
597 {
598 for (const auto *prop : properties) {
599 if (prop->AsProperty()->Value() == ident) {
600 return true;
601 }
602 }
603
604 return false;
605 }
606
GetSignedNumberLiteral(const ir::Expression * expr)607 SignedNumberLiteral Helpers::GetSignedNumberLiteral(const ir::Expression *expr)
608 {
609 if (!expr->IsUnaryExpression()) {
610 return SignedNumberLiteral::UNRECOGNIZED;
611 }
612
613 auto unaryExpression = expr->AsUnaryExpression();
614 if (!unaryExpression->Argument()->IsNumberLiteral()) {
615 return SignedNumberLiteral::UNRECOGNIZED;
616 }
617
618 // TODO(hxw): Here we return different value for positive and nagative number literal in UnaryExpression.
619 // Because when we access a computed property by MemberExpression, the compiler should emit different instruction.
620 // Now es2abc always emits the instruction `loadObjByValue` whether the computed property is literal or not.
621 // It can be optimized. For positive integer literal, the instruction should be `loadObjByIndex`.
622 // While for negative number literal, the instruction should be `loadObjByName`.
623 // So I add this util api and return different value for future use.
624 if (unaryExpression->OperatorType() == lexer::TokenType::PUNCTUATOR_PLUS) {
625 return SignedNumberLiteral::POSITIVE;
626 } else if (unaryExpression->OperatorType() == lexer::TokenType::PUNCTUATOR_MINUS) {
627 return SignedNumberLiteral::NEGATIVE;
628 }
629
630 return SignedNumberLiteral::UNRECOGNIZED;
631 }
632
OptimizeProgram(panda::pandasm::Program * prog,const std::string & inputFile)633 void Helpers::OptimizeProgram(panda::pandasm::Program *prog, const std::string &inputFile)
634 {
635 std::map<std::string, size_t> stat;
636 std::map<std::string, size_t> *statp = &stat;
637 panda::pandasm::AsmEmitter::PandaFileToPandaAsmMaps maps{};
638 panda::pandasm::AsmEmitter::PandaFileToPandaAsmMaps *mapsp = &maps;
639
640 #ifdef PANDA_WITH_BYTECODE_OPTIMIZER
641 const uint32_t COMPONENT_MASK = panda::Logger::Component::ASSEMBLER |
642 panda::Logger::Component::BYTECODE_OPTIMIZER |
643 panda::Logger::Component::COMPILER;
644 panda::Logger::InitializeStdLogging(panda::Logger::Level::ERROR, COMPONENT_MASK);
645
646 std::string pid;
647 #ifdef PANDA_TARGET_WINDOWS
648 pid = std::to_string(GetCurrentProcessId());
649 #else
650 pid = std::to_string(getpid());
651 #endif
652 const std::string outputSuffix = ".unopt.abc";
653 std::string tempOutput = panda::os::file::File::GetExtendedFilePath(inputFile + pid + outputSuffix);
654 if (panda::pandasm::AsmEmitter::Emit(tempOutput, *prog, statp, mapsp, true)) {
655 panda::bytecodeopt::OptimizeBytecode(prog, mapsp, tempOutput, true, true);
656 }
657
658 std::remove(tempOutput.c_str());
659 #endif
660 }
661
ReadFileToBuffer(const std::string & file,std::stringstream & ss)662 bool Helpers::ReadFileToBuffer(const std::string &file, std::stringstream &ss)
663 {
664 std::ifstream inputStream = Helpers::FileStream<std::ifstream>(
665 panda::os::file::File::GetExtendedFilePath(file), std::ios::binary);
666 if (inputStream.fail()) {
667 std::cerr << "Failed to read file to buffer: " << file << std::endl;
668 return false;
669 }
670 ss << inputStream.rdbuf();
671 return true;
672 }
673
ScanDirectives(ir::ScriptFunction * func,const lexer::LineIndex & lineIndex)674 void Helpers::ScanDirectives(ir::ScriptFunction *func, const lexer::LineIndex &lineIndex)
675 {
676 auto *body = func->Body();
677 if (!body || body->IsExpression()) {
678 return;
679 }
680
681 auto &statements = body->AsBlockStatement()->Statements();
682 if (statements.empty()) {
683 return;
684 }
685
686 bool keepScan = true;
687 auto iter = statements.begin();
688 while (keepScan && (iter != statements.end())) {
689 auto *stmt = *iter++;
690 if (!stmt->IsExpressionStatement()) {
691 return;
692 }
693
694 auto *expr = stmt->AsExpressionStatement()->GetExpression();
695 if (!expr->IsStringLiteral()) {
696 return;
697 }
698
699 keepScan = SetFuncFlagsForDirectives(expr->AsStringLiteral(), func, lineIndex);
700 }
701
702 return;
703 }
704
SetFuncFlagsForDirectives(const ir::StringLiteral * strLit,ir::ScriptFunction * func,const lexer::LineIndex & lineIndex)705 bool Helpers::SetFuncFlagsForDirectives(const ir::StringLiteral *strLit, ir::ScriptFunction *func,
706 const lexer::LineIndex &lineIndex)
707 {
708 if (strLit->Str().Is(SHOW_SOURCE)) {
709 func->AddFlag(ir::ScriptFunctionFlags::SHOW_SOURCE);
710 return true;
711 }
712
713 if (strLit->Str().Is(USE_CONCURRENT)) {
714 util::Concurrent::SetConcurrent(func, strLit, lineIndex);
715 return true;
716 }
717
718 return false;
719 }
720
GetHashString(std::string str)721 std::string Helpers::GetHashString(std::string str)
722 {
723 uint64_t result = FNV_OFFSET;
724
725 const uint8_t *input = reinterpret_cast<const uint8_t *>(str.c_str());
726 // FNV-1a 64-bit Algorithm
727 for (size_t i = 0; i < str.size(); i++) {
728 result ^= input[i];
729 result *= FNV_PRIME;
730 }
731
732 return std::to_string(result);
733 }
734
735 #ifdef PANDA_TARGET_WINDOWS
Utf8ToUtf16(const std::string & utf8)736 std::wstring Helpers::Utf8ToUtf16(const std::string &utf8)
737 {
738 std::wstring utf16;
739 if (utf8.empty()) {
740 return utf16;
741 }
742
743 if (utf8.length() > static_cast<size_t>(std::numeric_limits<int>::max())) {
744 std::cerr << "Length of filename: " << utf8 << " is too long" << std::endl;
745 return utf16;
746 }
747
748 const int utf8Length = static_cast<int>(utf8.length());
749 constexpr DWORD kFlags = MB_ERR_INVALID_CHARS;
750 const int utf16Length = MultiByteToWideChar(CP_UTF8, kFlags, utf8.data(), utf8Length, nullptr, 0);
751
752 if (utf16Length == 0) {
753 std::cerr << "The filename: " << utf8 << " is not a valid utf8 encoding string" << std::endl;
754 return utf16;
755 }
756
757 utf16.resize(utf16Length);
758 MultiByteToWideChar(CP_UTF8, kFlags, utf8.data(), utf8Length, &utf16[0], utf16Length);
759 return utf16;
760 }
761 #endif
762
763 } // namespace panda::es2panda::util
764