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