• 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 "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