27#define TRACE_ASM_PARSER(...) \
28 if (v8_flags.trace_asm_parser) { \
29 PrintF(__VA_ARGS__); \
32#define TRACE_ASM_PARSER(...)
35#define FAIL_AND_RETURN(ret, msg) \
37 failure_message_ = msg; \
38 failure_location_ = static_cast<int>(scanner_.Position()); \
39 TRACE_ASM_PARSER("[asm.js failure: %s, token: '%s', see: %s:%d]\n", msg, \
40 scanner_.Name(scanner_.Token()).c_str(), __FILE__, \
44#define FAIL(msg) FAIL_AND_RETURN(, msg)
45#define FAILn(msg) FAIL_AND_RETURN(nullptr, msg)
47#define EXPECT_TOKEN_OR_RETURN(ret, token) \
49 if (scanner_.Token() != token) { \
50 FAIL_AND_RETURN(ret, "Unexpected token"); \
55#define EXPECT_TOKEN(token) EXPECT_TOKEN_OR_RETURN(, token)
56#define EXPECT_TOKENn(token) EXPECT_TOKEN_OR_RETURN(nullptr, token)
58#define RECURSE_OR_RETURN(ret, call) \
61 if (GetCurrentStackPosition() < stack_limit_) { \
62 FAIL_AND_RETURN(ret, "Stack overflow while parsing asm.js module."); \
65 if (failed_) return ret; \
68#define RECURSE(call) RECURSE_OR_RETURN(, call)
69#define RECURSEn(call) RECURSE_OR_RETURN(nullptr, call)
71#define TOK(name) AsmJsScanner::kToken_##name
80 global_imports_(zone) {
86 auto* d = AsmType::Double();
87 auto* dq = AsmType::DoubleQ();
95 auto* f = AsmType::Float();
96 auto* fh = AsmType::Floatish();
97 auto* fq = AsmType::FloatQ();
99 fq2fh->AsFunctionType()->AddArgument(fq);
101 auto* s = AsmType::Signed();
102 auto* u = AsmType::Unsigned();
104 s2u->AsFunctionType()->AddArgument(s);
106 auto*
i = AsmType::Int();
123 stdlib_minmax_->AsOverloadedFunctionType()->AddOverload(minmax_s);
124 stdlib_minmax_->AsOverloadedFunctionType()->AddOverload(minmax_f);
125 stdlib_minmax_->AsOverloadedFunctionType()->AddOverload(minmax_d);
133 stdlib_abs_->AsOverloadedFunctionType()->AddOverload(s2u);
135 stdlib_abs_->AsOverloadedFunctionType()->AddOverload(fq2fh);
151 zone(), !return_type->
IsA(AsmType::Void()) ? 1 : 0, params.size());
152 for (
auto param : params) {
153 if (param->IsA(AsmType::Double())) {
155 }
else if (param->IsA(AsmType::Float())) {
157 }
else if (param->IsA(AsmType::Int())) {
163 if (!return_type->
IsA(AsmType::Void())) {
164 if (return_type->
IsA(AsmType::Double())) {
166 }
else if (return_type->
IsA(AsmType::Float())) {
168 }
else if (return_type->
IsA(AsmType::Signed())) {
174 return sig_builder.
Get();
185 local_depth_ =
parser_->function_temp_locals_depth_;
186 parser_->function_temp_locals_depth_++;
190 parser_->function_temp_locals_depth_--;
192 uint32_t
get()
const {
return parser_->TempVariable(local_depth_); }
205 size_t old_capacity = var_info.
size();
209 if (index + 1 > old_capacity) {
210 size_t new_size = std::max(2 * old_capacity, index + 1);
212 std::copy(var_info.
begin(), var_info.
end(), new_info.
begin());
215 return &var_info[
index];
242 info->mutable_variable = mutable_variable;
250 info->mutable_variable =
false;
352 FAIL(
"Undefined function");
355 FAIL(
"Undefined function table");
370 global_import.import_name, global_import.value_type,
372 start->EmitWithU32V(kExprGlobalGet, import_index);
373 start->EmitWithU32V(kExprGlobalSet,
VarIndex(global_import.var_info));
375 start->Emit(kExprEnd);
388 FAIL(
"Expected stdlib parameter");
394 FAIL(
"Expected foreign parameter");
398 FAIL(
"Duplicate parameter name");
403 FAIL(
"Expected heap parameter");
407 FAIL(
"Duplicate parameter name");
418 bool mutable_variable =
true;
423 mutable_variable =
false;
439 FAIL(
"Expected identifier");
444 FAIL(
"Cannot shadow parameters");
448 FAIL(
"Redefinition of variable");
457 if (uvalue > 0x7FFFFFFF) {
458 FAIL(
"Numeric literal out of range");
461 mutable_variable ? AsmType::Int() : AsmType::Signed(),
463 }
else if (
Check(
'-')) {
468 if (uvalue > 0x7FFFFFFF) {
469 FAIL(
"Numeric literal out of range");
477 mutable_variable ? AsmType::Int() : AsmType::Signed(),
481 FAIL(
"Expected numeric literal");
493 FAIL(
"Bad variable declaration");
499 bool mutable_variable) {
503 FAIL(
"Can only use immutable variables in global definition");
505 if (mutable_variable) {
506 FAIL(
"Can only define immutable variables with other immutables");
508 if (!src_info->
type->
IsA(AsmType::Int()) &&
509 !src_info->
type->
IsA(AsmType::Float()) &&
510 !src_info->
type->
IsA(AsmType::Double())) {
511 FAIL(
"Expected int, float, double, or fround for global definition");
514 info->type = src_info->
type;
515 info->index = src_info->
index;
516 info->mutable_variable =
false;
540 FAIL(
"Expected numeric literal");
547 bool mutable_variable) {
561 FAIL(
"Expected |0 type annotation for foreign integer import");
567 info->mutable_variable =
false;
578#define V(name, _junk1, _junk2, _junk3) \
580 DeclareStdlibFunc(info, VarKind::kSpecial, AsmType::name()); \
581 stdlib_uses_.Add(StandardMember::k##name); \
586 FAIL(
"Expected ArrayBuffer view");
599#define V(name, const_value) \
601 DeclareGlobal(info, false, AsmType::Double(), kWasmF64, \
602 WasmInitExpr(const_value)); \
603 stdlib_uses_.Add(StandardMember::kMath##name); \
607#define V(name, Name, op, sig) \
609 DeclareStdlibFunc(info, VarKind::kMath##Name, stdlib_##sig##_); \
610 stdlib_uses_.Add(StandardMember::kMath##Name); \
615 FAIL(
"Invalid member of stdlib.Math");
623 WasmInitExpr(std::numeric_limits<double>::quiet_NaN()));
626 FAIL(
"Invalid member of stdlib");
639 FAIL(
"Illegal export name");
644 FAIL(
"Expected function name");
648 FAIL(
"Expected function");
661 FAIL(
"Single function export must be a function name");
665 FAIL(
"Single function export must be a function");
668 info->function_builder);
676 FAIL(
"Expected table name");
681 FAIL(
"Function table redefined");
685 FAIL(
"Function table name collides");
692 FAIL(
"Expected function name");
696 FAIL(
"Expected function");
701 if (
count >=
static_cast<uint64_t
>(table_info->
mask) + 1) {
702 FAIL(
"Exceeded function table size");
704 if (!info->type->IsA(table_info->
type)) {
705 FAIL(
"Function table definition doesn't match use");
708 0,
static_cast<uint32_t
>(table_info->
index +
count), info->index,
721 count !=
static_cast<uint64_t
>(table_info->
mask) + 1) {
722 FAIL(
"Function table size does not match uses");
734 FAIL(
"Expected function name");
746 FAIL(
"Function name collides with variable");
748 FAIL(
"Function redefined");
758 function_start_position);
765 FAIL(
"Number of parameters exceeds internal limit");
772 params.size() + locals.
size());
776 bool last_statement_is_return =
false;
779 last_statement_is_return =
Peek(
TOK(
return));
788 if (!last_statement_is_return) {
792 FAIL(
"Expected return at end of non-void function");
801 for (
auto local : locals) {
811 FAIL(
"Number of local variables exceeds internal limit");
819 function_end_position);
822 FAIL(
"Size of function body exceeds internal limit");
826 for (
auto t : params) {
827 function_type->AsFunctionType()->AddArgument(t);
830 if (function_info->
type->
IsA(AsmType::None())) {
832 function_info->
type = function_type;
833 }
else if (!function_type->
IsA(function_info->
type)) {
835 FAIL(
"Function definition doesn't match use");
853 FAIL(
"Expected parameter name");
864 for (
auto p : function_parameters) {
869 FAIL(
"Duplicate parameter name");
874 FAIL(
"Bad integer parameter annotation.");
877 info->type = AsmType::Int();
878 info->index =
static_cast<uint32_t
>(params->size());
879 params->push_back(AsmType::Int());
880 }
else if (
Check(
'+')) {
883 info->type = AsmType::Double();
884 info->index =
static_cast<uint32_t
>(params->size());
885 params->push_back(AsmType::Double());
889 FAIL(
"Expected fround");
895 info->type = AsmType::Float();
896 info->index =
static_cast<uint32_t
>(params->size());
897 params->push_back(AsmType::Float());
914 FAIL(
"Expected local variable identifier");
918 FAIL(
"Duplicate local variable name");
927 info->type = AsmType::Double();
928 info->index =
static_cast<uint32_t
>(param_count + locals->
size());
933 if (uvalue > 0x7FFFFFFF) {
934 FAIL(
"Numeric literal out of range");
937 info->type = AsmType::Int();
938 info->index =
static_cast<uint32_t
>(param_count + locals->
size());
940 int32_t value = -
static_cast<int32_t
>(uvalue);
944 FAIL(
"Expected variable initial value");
950 FAIL(
"Initializing from global requires const variable");
953 info->type = sinfo->
type;
954 info->index =
static_cast<uint32_t
>(param_count + locals->
size());
955 if (sinfo->
type->
IsA(AsmType::Int())) {
957 }
else if (sinfo->
type->
IsA(AsmType::Float())) {
959 }
else if (sinfo->
type->
IsA(AsmType::Double())) {
962 FAIL(
"Bad local variable definition");
975 info->type = AsmType::Float();
976 info->index =
static_cast<uint32_t
>(param_count + locals->
size());
985 if (uvalue > 0x7FFFFFFF) {
986 FAIL(
"Numeric literal out of range");
989 info->type = AsmType::Float();
990 info->index =
static_cast<uint32_t
>(param_count + locals->
size());
992 int32_t value =
static_cast<int32_t
>(uvalue);
996 float fvalue =
static_cast<float>(
value);
1000 FAIL(
"Expected variable initial value");
1004 FAIL(
"expected fround or const global");
1008 info->type = AsmType::Double();
1009 info->index =
static_cast<uint32_t
>(param_count + locals->
size());
1015 info->type = AsmType::Int();
1016 info->index =
static_cast<uint32_t
>(param_count + locals->
size());
1018 int32_t value =
static_cast<int32_t
>(uvalue);
1022 FAIL(
"Expected variable initial value");
1040 }
else if (
Peek(
';')) {
1045 }
else if (
Peek(
TOK(
return))) {
1050 }
else if (
Peek(
TOK(
break))) {
1052 }
else if (
Peek(
TOK(
continue))) {
1054 }
else if (
Peek(
TOK(
switch))) {
1064 if (can_break_to_block) {
1074 if (can_break_to_block) {
1093 if (!ret->
IsA(AsmType::Void())) {
1128 if (ret->
IsA(AsmType::Double())) {
1130 }
else if (ret->
IsA(AsmType::Float())) {
1132 }
else if (ret->
IsA(AsmType::Signed())) {
1135 FAIL(
"Invalid return type");
1140 FAIL(
"Invalid void return type");
1222 if (!ret->
IsA(AsmType::Void())) {
1276 FAIL(
"Illegal break");
1292 FAIL(
"Illegal continue");
1303 FAIL(
"Double label unsupported");
1317 if (!test->IsA(AsmType::Signed())) {
1318 FAIL(
"Expected signed for switch value");
1330 for (
size_t i = 0;
i <
count; ++
i) {
1335 for (
auto c : cases) {
1359 bool negate =
false;
1365 FAIL(
"Expected numeric literal");
1368 if ((negate && uvalue > 0x80000000) || (!negate && uvalue > 0x7FFFFFFF)) {
1369 FAIL(
"Numeric literal out of range");
1371 int32_t value =
static_cast<int32_t
>(uvalue);
1373 if (negate && value !=
kMinInt) {
1404 if (a->IsA(AsmType::None())) {
1405 FAILn(
"Expected actual type");
1407 if (!a->IsA(AsmType::Void())) {
1415 if (expected !=
nullptr && !a->
IsA(expected)) {
1416 FAILn(
"Unexpected type");
1424 double dvalue = 0.0;
1425 uint32_t uvalue = 0;
1428 return AsmType::Double();
1430 if (uvalue <= 0x7FFFFFFF) {
1432 return AsmType::FixNum();
1435 return AsmType::Unsigned();
1438 FAILn(
"Expected numeric literal.");
1448 FAILn(
"Undefined local variable");
1455 FAILn(
"Undefined global variable");
1469 return AsmType::Float();
1473 }
else if (
Peek(
'(')) {
1494#define V(array_type, wasmload, wasmstore, type) \
1495 if (heap_access_type_->IsA(AsmType::array_type())) { \
1496 current_function_builder_->EmitWithPrefix( \
1497 kExpr##type##AsmjsLoad##wasmload); \
1498 return heap_access_type_->LoadType(); \
1502 FAILn(
"Expected valid heap load");
1514 FAILn(
"Invalid assignment target");
1522 if (!value->IsA(ret)) {
1523 FAILn(
"Illegal type stored to heap view");
1526 if (heap_type->
IsA(AsmType::Float32Array()) &&
1527 value->IsA(AsmType::DoubleQ())) {
1530 ret = AsmType::FloatQ();
1532 if (heap_type->
IsA(AsmType::Float64Array()) &&
1533 value->IsA(AsmType::FloatQ())) {
1536 ret = AsmType::DoubleQ();
1538#define V(array_type, wasmload, wasmstore, type) \
1539 if (heap_type->IsA(AsmType::array_type())) { \
1540 current_function_builder_->EmitWithPrefix( \
1541 kExpr##type##AsmjsStore##wasmstore); \
1557 FAILn(
"Undeclared assignment target");
1559 if (!info->mutable_variable) {
1560 FAILn(
"Expected mutable variable in assignment");
1566 if (!value->IsA(ret)) {
1567 FAILn(
"Type mismatch in assignment");
1595 ret = AsmType::Double();
1596 }
else if (uvalue <= 0x80000000) {
1600 ret = AsmType::Signed();
1602 FAILn(
"Integer numeric literal out of range.");
1606 if (ret->
IsA(AsmType::Int())) {
1612 ret = AsmType::Intish();
1613 }
else if (ret->
IsA(AsmType::DoubleQ())) {
1615 ret = AsmType::Double();
1616 }
else if (ret->
IsA(AsmType::FloatQ())) {
1618 ret = AsmType::Floatish();
1620 FAILn(
"expected int/double?/float?");
1623 }
else if (
Peek(
'+')) {
1629 if (ret->
IsA(AsmType::Signed())) {
1631 ret = AsmType::Double();
1632 }
else if (ret->
IsA(AsmType::Unsigned())) {
1634 ret = AsmType::Double();
1635 }
else if (ret->
IsA(AsmType::DoubleQ())) {
1636 ret = AsmType::Double();
1637 }
else if (ret->
IsA(AsmType::FloatQ())) {
1639 ret = AsmType::Double();
1641 FAILn(
"expected signed/unsigned/double?/float?");
1643 }
else if (
Check(
'!')) {
1645 if (!ret->
IsA(AsmType::Int())) {
1646 FAILn(
"expected int");
1649 }
else if (
Check(
'~')) {
1652 if (ret->
IsA(AsmType::Double())) {
1654 }
else if (ret->
IsA(AsmType::FloatQ())) {
1657 FAILn(
"expected double or float?");
1659 ret = AsmType::Signed();
1662 if (!ret->
IsA(AsmType::Intish())) {
1663 FAILn(
"operator ~ expects intish");
1667 ret = AsmType::Signed();
1683 if (!type->IsA(AsmType::Int())) {
1684 FAILn(
"Expected int");
1686 int32_t value =
static_cast<int32_t
>(uvalue);
1689 return AsmType::Intish();
1694 }
else if (
Check(
'-')) {
1696 int32_t value = -
static_cast<int32_t
>(uvalue);
1701 if (!type->IsA(AsmType::Int())) {
1702 FAILn(
"Expected int");
1705 return AsmType::Intish();
1707 a = AsmType::Signed();
1719 if (uvalue >= 0x100000) {
1720 FAILn(
"Constant multiple out of range");
1722 if (!a->IsA(AsmType::Int())) {
1723 FAILn(
"Integer multiply of expects int");
1725 int32_t value = -
static_cast<int32_t
>(uvalue);
1728 return AsmType::Intish();
1732 if (uvalue >= 0x100000) {
1733 FAILn(
"Constant multiple out of range");
1735 if (!a->IsA(AsmType::Int())) {
1736 FAILn(
"Integer multiply of expects int");
1738 int32_t value =
static_cast<int32_t
>(uvalue);
1741 return AsmType::Intish();
1745 if (a->IsA(AsmType::DoubleQ()) && b->
IsA(AsmType::DoubleQ())) {
1747 a = AsmType::Double();
1748 }
else if (a->IsA(AsmType::FloatQ()) && b->
IsA(AsmType::FloatQ())) {
1750 a = AsmType::Floatish();
1752 FAILn(
"expected doubles or floats");
1754 }
else if (
Check(
'/')) {
1757 if (a->IsA(AsmType::DoubleQ()) && b->
IsA(AsmType::DoubleQ())) {
1759 a = AsmType::Double();
1760 }
else if (a->IsA(AsmType::FloatQ()) && b->
IsA(AsmType::FloatQ())) {
1762 a = AsmType::Floatish();
1763 }
else if (a->IsA(AsmType::Signed()) && b->
IsA(AsmType::Signed())) {
1765 a = AsmType::Intish();
1766 }
else if (a->IsA(AsmType::Unsigned()) && b->
IsA(AsmType::Unsigned())) {
1768 a = AsmType::Intish();
1770 FAILn(
"expected doubles or floats");
1772 }
else if (
Check(
'%')) {
1775 if (a->IsA(AsmType::DoubleQ()) && b->
IsA(AsmType::DoubleQ())) {
1777 a = AsmType::Double();
1778 }
else if (a->IsA(AsmType::Signed()) && b->
IsA(AsmType::Signed())) {
1780 a = AsmType::Intish();
1781 }
else if (a->IsA(AsmType::Unsigned()) && b->
IsA(AsmType::Unsigned())) {
1783 a = AsmType::Intish();
1785 FAILn(
"expected doubles or floats");
1803 if (a->IsA(AsmType::Double()) && b->
IsA(AsmType::Double())) {
1805 a = AsmType::Double();
1806 }
else if (a->IsA(AsmType::FloatQ()) && b->
IsA(AsmType::FloatQ())) {
1808 a = AsmType::Floatish();
1809 }
else if (a->IsA(AsmType::Int()) && b->
IsA(AsmType::Int())) {
1811 a = AsmType::Intish();
1813 }
else if (a->IsA(AsmType::Intish()) && b->
IsA(AsmType::Intish())) {
1817 if (n > (1 << 20)) {
1818 FAILn(
"more than 2^20 additive values");
1822 FAILn(
"illegal types for +");
1824 }
else if (
Check(
'-')) {
1827 if (a->IsA(AsmType::Double()) && b->
IsA(AsmType::Double())) {
1829 a = AsmType::Double();
1830 }
else if (a->IsA(AsmType::FloatQ()) && b->
IsA(AsmType::FloatQ())) {
1832 a = AsmType::Floatish();
1833 }
else if (a->IsA(AsmType::Int()) && b->
IsA(AsmType::Int())) {
1835 a = AsmType::Intish();
1837 }
else if (a->IsA(AsmType::Intish()) && b->
IsA(AsmType::Intish())) {
1841 if (n > (1 << 20)) {
1842 FAILn(
"more than 2^20 additive values");
1846 FAILn(
"illegal types for +");
1886 if (!(a->IsA(AsmType::Intish()) && b->
IsA(AsmType::Intish()))) {
1887 FAILn(
"Expected intish for operator >>.");
1890 a = AsmType::Signed();
1893#define HANDLE_CASE(op, opcode, name, result) \
1895 EXPECT_TOKENn(TOK(op)); \
1896 heap_access_shift_position_ = kNoHeapAccessShift; \
1897 AsmType* b = nullptr; \
1898 RECURSEn(b = AdditiveExpression()); \
1899 if (!(a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish()))) { \
1900 FAILn("Expected intish for operator " #name "."); \
1902 current_function_builder_->Emit(kExpr##opcode); \
1903 a = AsmType::result(); \
1921#define HANDLE_CASE(op, sop, uop, dop, fop, name) \
1923 EXPECT_TOKENn(op); \
1924 AsmType* b = nullptr; \
1925 RECURSEn(b = ShiftExpression()); \
1926 if (a->IsA(AsmType::Signed()) && b->IsA(AsmType::Signed())) { \
1927 current_function_builder_->Emit(kExpr##sop); \
1928 } else if (a->IsA(AsmType::Unsigned()) && b->IsA(AsmType::Unsigned())) { \
1929 current_function_builder_->Emit(kExpr##uop); \
1930 } else if (a->IsA(AsmType::Double()) && b->IsA(AsmType::Double())) { \
1931 current_function_builder_->Emit(kExpr##dop); \
1932 } else if (a->IsA(AsmType::Float()) && b->IsA(AsmType::Float())) { \
1933 current_function_builder_->Emit(kExpr##fop); \
1935 FAILn("Expected signed, unsigned, double, or float for operator " #name \
1938 a = AsmType::Int(); \
1941 HANDLE_CASE(
'<', I32LtS, I32LtU, F64Lt, F32Lt,
"<");
1943 HANDLE_CASE(
'>', I32GtS, I32GtU, F64Gt, F32Gt,
">");
1958#define HANDLE_CASE(op, sop, uop, dop, fop, name) \
1960 EXPECT_TOKENn(op); \
1961 AsmType* b = nullptr; \
1962 RECURSEn(b = RelationalExpression()); \
1963 if (a->IsA(AsmType::Signed()) && b->IsA(AsmType::Signed())) { \
1964 current_function_builder_->Emit(kExpr##sop); \
1965 } else if (a->IsA(AsmType::Unsigned()) && b->IsA(AsmType::Unsigned())) { \
1966 current_function_builder_->Emit(kExpr##uop); \
1967 } else if (a->IsA(AsmType::Double()) && b->IsA(AsmType::Double())) { \
1968 current_function_builder_->Emit(kExpr##dop); \
1969 } else if (a->IsA(AsmType::Float()) && b->IsA(AsmType::Float())) { \
1970 current_function_builder_->Emit(kExpr##fop); \
1972 FAILn("Expected signed, unsigned, double, or float for operator " #name \
1975 a = AsmType::Int(); \
1991 while (
Check(
'&')) {
1994 if (a->IsA(AsmType::Intish()) && b->
IsA(AsmType::Intish())) {
1996 a = AsmType::Signed();
1998 FAILn(
"Expected intish for operator &.");
2008 while (
Check(
'^')) {
2011 if (a->IsA(AsmType::Intish()) && b->
IsA(AsmType::Intish())) {
2013 a = AsmType::Signed();
2015 FAILn(
"Expected intish for operator &.");
2026 while (
Check(
'|')) {
2031 bool requires_zero =
2048 a = AsmType::Signed();
2052 if (requires_zero) {
2053 FAILn(
"Expected |0 type annotation for call");
2055 if (a->IsA(AsmType::Intish()) && b->
IsA(AsmType::Intish())) {
2057 a = AsmType::Signed();
2059 FAILn(
"Expected intish for operator |.");
2071 if (!test->IsA(AsmType::Int())) {
2072 FAILn(
"Expected int in condition of ternary operator.");
2084 if (cons->
IsA(AsmType::Int()) && alt->
IsA(AsmType::Int())) {
2086 return AsmType::Int();
2087 }
else if (cons->
IsA(AsmType::Double()) && alt->
IsA(AsmType::Double())) {
2089 return AsmType::Double();
2090 }
else if (cons->
IsA(AsmType::Float()) && alt->
IsA(AsmType::Float())) {
2092 return AsmType::Float();
2094 FAILn(
"Type mismatch in ternary operator.");
2124 std::optional<TemporaryVariableScope> tmp_scope;
2128 if (!index->IsA(AsmType::Intish())) {
2129 FAILn(
"Expected intish index");
2134 FAILn(
"Expected mask literal");
2137 FAILn(
"Expected power of 2 mask");
2148 if (func_index == std::numeric_limits<uint32_t>::max()) {
2149 FAILn(
"Exceeded maximum function table size");
2153 function_info->
index = func_index;
2157 FAILn(
"Expected call table");
2160 FAILn(
"Mask size mismatch");
2166 tmp_scope.emplace(
this);
2180 FAILn(
"Expected function as call target");
2193 if (t->IsA(AsmType::Int())) {
2195 }
else if (t->IsA(AsmType::Float())) {
2196 param_types.
push_back(AsmType::Float());
2197 }
else if (t->IsA(AsmType::Double())) {
2198 param_types.
push_back(AsmType::Double());
2200 FAILn(
"Bad function argument type");
2227 if (allow_peek &&
Peek(
'|') &&
2229 (return_type ==
nullptr || return_type->
IsA(AsmType::Float()))) {
2233 return_type = AsmType::Signed();
2234 }
else if (return_type ==
nullptr) {
2235 to_number_pos = call_pos;
2236 return_type = AsmType::Void();
2241 for (
auto t : param_types) {
2242 function_type->AsFunctionType()->AddArgument(t);
2252 FAILn(
"Number of parameters exceeds internal limit");
2254 for (
auto t : param_specific_types) {
2255 if (!t->IsA(AsmType::Extern())) {
2256 FAILn(
"Imported function args must be type extern");
2259 if (return_type->
IsA(AsmType::Float())) {
2260 FAILn(
"Imported function can't be called as float");
2265 auto it = function_info->import->cache.find(*
sig);
2266 if (it != function_info->import->cache.end()) {
2272 function_info->import->cache[*
sig] =
index;
2280 FAILn(
"Expected callable function");
2286 param_specific_types)) {
2287 return_type = AsmType::Float();
2289 param_specific_types)) {
2290 return_type = AsmType::Floatish();
2292 param_specific_types)) {
2293 return_type = AsmType::Double();
2295 param_specific_types)) {
2296 return_type = AsmType::Signed();
2298 param_specific_types)) {
2299 return_type = AsmType::Unsigned();
2301 FAILn(
"Function use doesn't match definition");
2303 switch (function_info->
kind) {
2304#define V(name, Name, op, sig) \
2305 case VarKind::kMath##Name: \
2306 if ((op) <= 0xff) { \
2307 current_function_builder_->Emit(op); \
2309 current_function_builder_->EmitWithPrefix(op); \
2314#define V(name, Name, op, sig) \
2315 case VarKind::kMath##Name: \
2316 if (param_specific_types[0]->IsA(AsmType::DoubleQ())) { \
2317 current_function_builder_->Emit(kExprF64##Name); \
2318 } else if (param_specific_types[0]->IsA(AsmType::FloatQ())) { \
2319 current_function_builder_->Emit(kExprF32##Name); \
2326 case VarKind::kMathMin:
2327 case VarKind::kMathMax:
2328 if (param_specific_types[0]->IsA(AsmType::Double())) {
2329 for (
size_t i = 1;
i < param_specific_types.
size(); ++
i) {
2330 if (function_info->
kind == VarKind::kMathMin) {
2336 }
else if (param_specific_types[0]->IsA(AsmType::Float())) {
2339 for (
size_t i = 1;
i < param_specific_types.
size(); ++
i) {
2340 if (function_info->
kind == VarKind::kMathMin) {
2346 }
else if (param_specific_types[0]->IsA(AsmType::Signed())) {
2349 for (
size_t i = 1;
i < param_specific_types.
size(); ++
i) {
2353 if (function_info->
kind == VarKind::kMathMin) {
2369 case VarKind::kMathAbs:
2370 if (param_specific_types[0]->IsA(AsmType::Signed())) {
2380 }
else if (param_specific_types[0]->IsA(AsmType::DoubleQ())) {
2382 }
else if (param_specific_types[0]->IsA(AsmType::FloatQ())) {
2389 case VarKind::kMathFround:
2400 if (function_info->
type->
IsA(AsmType::None())) {
2401 function_info->
type = function_type;
2406 FAILn(
"Function use doesn't match definition");
2451 int32_t size = info->type->ElementSizeInBytes();
2458 if (
offset > 0x7FFFFFFF ||
2459 static_cast<uint64_t
>(
offset) *
static_cast<uint64_t
>(size) >
2461 FAIL(
"Heap access out of range");
2465 static_cast<uint32_t
>(
offset * size));
2474 if (info->type->IsA(AsmType::Int8Array()) ||
2475 info->type->IsA(AsmType::Uint8Array())) {
2480 FAIL(
"Expected shift of word size");
2483 FAIL(
"Expected valid heap access shift");
2486 FAIL(
"Expected heap access shift to match heap view");
2494 if (!index_type->
IsA(AsmType::Intish())) {
2495 FAIL(
"Expected intish index");
2506 FAIL(
"Expected fround");
2516 if (ret->
IsA(AsmType::Floatish())) {
2518 }
else if (ret->
IsA(AsmType::DoubleQ())) {
2520 }
else if (ret->
IsA(AsmType::Signed())) {
2522 }
else if (ret->
IsA(AsmType::Unsigned())) {
2525 FAIL(
"Illegal conversion to float");
2535 }
else if (
Peek(
')')) {
2540 }
else if (
Peek(AsmJsScanner::kEndOfInput)) {
2553 }
else if (
Peek(
'}')) {
2558 }
else if (depth == 1 &&
Peek(
TOK(
case))) {
2561 bool negate =
false;
2562 if (
Check(
'-')) negate =
true;
2566 int32_t value =
static_cast<int32_t
>(uvalue);
2568 if (negate && value !=
kMinInt) {
2572 }
else if (
Peek(AsmJsScanner::kEndOfInput) ||
2573 Peek(AsmJsScanner::kParseError)) {
2584#undef RECURSE_OR_RETURN
2587#undef EXPECT_TOKEN_OR_RETURN
2590#undef FAIL_AND_RETURN
2591#undef TRACE_ASM_PARSER
#define STDLIB_ARRAY_TYPE_LIST(V)
#define STDLIB_MATH_VALUE_LIST(V)
#define STDLIB_MATH_FUNCTION_LIST(V)
#define STDLIB_MATH_FUNCTION_CEIL_LIKE_LIST(V)
#define STDLIB_MATH_FUNCTION_MONOMORPHIC_LIST(V)
#define EXPECT_TOKEN(token)
#define EXPECT_TOKENn(token)
#define HANDLE_CASE(op, opcode, name, result)
constexpr void Add(E element)
constexpr size_t size() const
constexpr T * begin() const
constexpr T * end() const
static size_t GlobalIndex(token_t token)
static size_t LocalIndex(token_t token)
const std::string & GetIdentifierString() const
bool IsPrecededByNewline() const
static const char *const kSingleFunctionName
SignatureBuilder< Signature< T >, T > Builder
void push_back(const T &value)
base::Vector< std::remove_const_t< T > > CloneVector(base::Vector< T > v)
base::Vector< T > NewVector(size_t length)
virtual bool CanBeInvokedWith(AsmType *return_type, const ZoneVector< AsmType * > &args)=0
TemporaryVariableScope(AsmJsParser *parser)
~TemporaryVariableScope()
ZoneVector< BlockInfo > block_stack_
int function_temp_locals_depth_
AsmType * NumericLiteral()
bool CheckForUnsigned(uint32_t *value)
AsmJsScanner::token_t Consume()
void InitializeStdlibTypes()
CachedVectors< AsmJsScanner::token_t > cached_token_t_vectors_
bool Peek(AsmJsScanner::token_t token)
void ValidateFunctionTable()
AsmType * AdditiveExpression()
void ValidateModuleVar(bool mutable_variable)
void ValidateFunctionLocals(size_t param_count, ZoneVector< ValueType > *locals)
void ValidateModuleVarNewStdlib(VarInfo *info)
void Begin(AsmJsScanner::token_t label=0)
AsmType * BitwiseANDExpression()
void GatherCases(ZoneVector< int32_t > *cases)
void ValidateModuleVarImport(VarInfo *info, bool mutable_variable)
base::Vector< VarInfo > local_var_info_
AsmJsScanner::token_t foreign_name_
AsmType * CallExpression()
int function_temp_locals_offset_
WasmModuleBuilder * module_builder_
size_t call_coercion_deferred_position_
int FindBreakLabelDepth(AsmJsScanner::token_t label)
AsmType * ParenthesizedExpression()
AsmType * MultiplicativeExpression()
AsmJsScanner::token_t stdlib_name_
void ValidateModuleVarStdlib(VarInfo *info)
CachedVectors< int32_t > cached_int_vectors_
size_t call_coercion_position_
int function_temp_locals_used_
AsmJsScanner::token_t pending_label_
AsmType * RelationalExpression()
bool CheckForUnsignedBelow(uint32_t limit, uint32_t *value)
void DeclareStdlibFunc(VarInfo *info, VarKind kind, AsmType *type)
static const AsmJsScanner::token_t kTokenNone
uint32_t heap_access_shift_value_
AsmType * call_coercion_deferred_
size_t heap_access_shift_position_
void ValidateModuleVarFromGlobal(VarInfo *info, bool mutable_variable)
AsmType * Expression(AsmType *expect)
AsmType * MemberExpression()
AsmJsScanner::token_t heap_name_
AsmType * BitwiseXORExpression()
base::Vector< VarInfo > global_var_info_
AsmType * ConditionalExpression()
AsmType * UnaryExpression()
bool Check(AsmJsScanner::token_t token)
AsmType * EqualityExpression()
bool CheckForDouble(double *value)
void ValidateFloatCoercion()
WasmFunctionBuilder * current_function_builder_
uint32_t VarIndex(VarInfo *info)
void BareBegin(BlockKind kind, AsmJsScanner::token_t label=0)
AsmType * BitwiseORExpression()
CachedVectors< AsmType * > cached_asm_type_p_vectors_
AsmJsParser(Zone *zone, uintptr_t stack_limit, Utf16CharacterStream *stream)
ZoneLinkedList< GlobalImport > global_imports_
void ValidateHeapAccess()
void ValidateFunctionParams(ZoneVector< AsmType * > *params)
CachedVectors< ValueType > cached_valuetype_vectors_
int FindContinueLabelDepth(AsmJsScanner::token_t label)
base::Vector< const char > CopyCurrentIdentifierString()
void ScanToClosingParenthesis()
bool IterationStatement()
void AddGlobalImport(base::Vector< const char > name, AsmType *type, ValueType vtype, bool mutable_variable, VarInfo *info)
static const size_t kNoHeapAccessShift
AsmType * stdlib_ceil_like_
void ExpressionStatement()
void DeclareGlobal(VarInfo *info, bool mutable_variable, AsmType *type, ValueType vtype, WasmInitExpr init)
AsmType * AssignmentExpression()
void Loop(AsmJsScanner::token_t label=0)
FunctionSig * ConvertSignature(AsmType *return_type, const ZoneVector< AsmType * > ¶ms)
void ValidateModuleParameters()
bool inside_heap_assignment_
void ValidateModuleVars()
VarInfo * GetVarInfo(AsmJsScanner::token_t token)
AsmType * ShiftExpression()
AsmType * ValidateExpression()
AsmType * heap_access_type_
uint32_t TempVariable(int index)
static AsmType * FroundType(Zone *zone)
static AsmType * OverloadedFunction(Zone *zone)
static AsmType * MinMaxType(Zone *zone, AsmType *dest, AsmType *src)
static AsmType * Function(Zone *zone, AsmType *ret)
AsmCallableType * AsCallableType()
static bool IsExactly(AsmType *x, AsmType *y)
void EmitTeeLocal(uint32_t index)
void EmitGetLocal(uint32_t index)
void EmitF64Const(double val)
void EmitF32Const(float val)
void SetSignature(const FunctionSig *sig)
void EmitU32V(uint32_t val)
void EmitDirectCallIndex(uint32_t index)
void EmitWithPrefix(WasmOpcode opcode)
void SetAsmFunctionStartPosition(size_t function_position)
uint32_t func_index() const
size_t GetPosition() const
void AddAsmWasmOffset(size_t call_position, size_t to_number_position)
void EmitSetLocal(uint32_t index)
void EmitWithU32V(WasmOpcode opcode, uint32_t immediate)
void EmitWithU8(WasmOpcode opcode, const uint8_t immediate)
void SetName(base::Vector< const char > name)
void FixupByte(size_t position, uint8_t value)
void EmitI32Const(int32_t val)
uint32_t AddLocal(ValueType type)
void DeleteCodeAfter(size_t position)
void Emit(WasmOpcode opcode)
static WasmInitExpr DefaultValue(ValueType type)
@ kRelativeToDeclaredFunctions
ModuleTypeIndex AddSignature(const FunctionSig *sig, bool is_final, ModuleTypeIndex supertype=kNoSuperType)
uint32_t AddImport(base::Vector< const char > name, const FunctionSig *sig, base::Vector< const char > module={})
void AddExport(base::Vector< const char > name, ImportExportKindCode kind, uint32_t index)
uint32_t AddGlobal(ValueType type, bool mutability, WasmInitExpr init)
void MarkStartFunction(WasmFunctionBuilder *builder)
uint32_t IncreaseTableMinSize(uint32_t table_index, uint32_t count)
uint32_t AddMemory(uint32_t min_pages)
WasmFunctionBuilder * AddFunction(const FunctionSig *sig=nullptr)
uint32_t AddTable(ValueType type, uint32_t min_size)
void SetIndirectFunction(uint32_t table_index, uint32_t index_in_table, uint32_t direct_function_index, WasmElemSegment::FunctionIndexingMode indexing_mode)
uint32_t AddGlobalImport(base::Vector< const char > name, ValueType type, bool mutability, base::Vector< const char > module={})
Handle< SharedFunctionInfo > info
std::optional< TNode< JSArray > > a
constexpr bool IsPowerOfTwo(T value)
signed_type NegateWithWraparound(signed_type a)
constexpr Vector< T > VectorOf(T *start, size_t size)
Vector< const char > CStrVector(const char *data)
constexpr size_t kV8MaxWasmFunctionLocals
constexpr size_t kV8MaxWasmFunctionSize
constexpr IndependentValueType kWasmF32
constexpr IndependentValueType kWasmI32
constexpr IndependentHeapType kWasmFuncRef
constexpr IndependentValueType kWasmF64
constexpr size_t kV8MaxWasmFunctionParams
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in name
kWasmInternalFunctionIndirectPointerTag kProtectedInstanceDataOffset sig
float DoubleToFloat32(double x)
RegExpParserImpl< CharT > *const parser_
const uintptr_t stack_limit_
#define DCHECK_NOT_NULL(val)
#define DCHECK_IMPLIES(v1, v2)
#define DCHECK(condition)
#define DCHECK_EQ(v1, v2)
#define DCHECK_GT(v1, v2)
WasmFunctionBuilder * function_builder
FunctionImportInfo *uint32_t mask