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