@@ -1472,7 +1472,7 @@ ScopedOperand Generator::add_constant(Value value)
14721472 return append_new_constant ();
14731473}
14741474
1475- CodeGenerationErrorOr<void > Generator::generate_builtin_abstract_operation (Identifier const & builtin_identifier, ReadonlySpan<CallExpression::Argument> arguments, ScopedOperand const &)
1475+ CodeGenerationErrorOr<void > Generator::generate_builtin_abstract_operation (Identifier const & builtin_identifier, ReadonlySpan<CallExpression::Argument> arguments, ScopedOperand const & dst )
14761476{
14771477 VERIFY (m_builtin_abstract_operations_enabled);
14781478 for (auto const & argument : arguments) {
@@ -1486,6 +1486,249 @@ CodeGenerationErrorOr<void> Generator::generate_builtin_abstract_operation(Ident
14861486
14871487 auto const & operation_name = builtin_identifier.string ();
14881488
1489+ if (operation_name == " IsCallable" sv) {
1490+ if (arguments.size () != 1 ) {
1491+ return CodeGenerationError {
1492+ &builtin_identifier,
1493+ " IsCallable only accepts one argument" sv,
1494+ };
1495+ }
1496+
1497+ auto source = TRY (arguments[0 ].value ->generate_bytecode (*this )).value ();
1498+ emit<Op::IsCallable>(dst, source);
1499+ return {};
1500+ }
1501+
1502+ if (operation_name == " IsConstructor" sv) {
1503+ if (arguments.size () != 1 ) {
1504+ return CodeGenerationError {
1505+ &builtin_identifier,
1506+ " IsConstructor only accepts one argument" sv,
1507+ };
1508+ }
1509+
1510+ auto source = TRY (arguments[0 ].value ->generate_bytecode (*this )).value ();
1511+ emit<Op::IsConstructor>(dst, source);
1512+ return {};
1513+ }
1514+
1515+ if (operation_name == " ToBoolean" sv) {
1516+ if (arguments.size () != 1 ) {
1517+ return CodeGenerationError {
1518+ &builtin_identifier,
1519+ " ToBoolean only accepts one argument" sv,
1520+ };
1521+ }
1522+
1523+ auto source = TRY (arguments[0 ].value ->generate_bytecode (*this )).value ();
1524+ emit<Op::ToBoolean>(dst, source);
1525+ return {};
1526+ }
1527+
1528+ if (operation_name == " ToObject" sv) {
1529+ if (arguments.size () != 1 ) {
1530+ return CodeGenerationError {
1531+ &builtin_identifier,
1532+ " ToObject only accepts one argument" sv,
1533+ };
1534+ }
1535+
1536+ auto source = TRY (arguments[0 ].value ->generate_bytecode (*this )).value ();
1537+ emit<Op::ToObject>(dst, source);
1538+ return {};
1539+ }
1540+
1541+ if (operation_name == " ThrowTypeError" sv) {
1542+ if (arguments.size () != 1 ) {
1543+ return CodeGenerationError {
1544+ &builtin_identifier,
1545+ " throw_type_error only accepts one argument" sv,
1546+ };
1547+ }
1548+
1549+ auto const * message = as_if<StringLiteral>(*arguments[0 ].value );
1550+ if (!message) {
1551+ return CodeGenerationError {
1552+ &builtin_identifier,
1553+ " ThrowTypeError's message must be a string literal" sv,
1554+ };
1555+ }
1556+
1557+ auto message_string = intern_string (message->value ());
1558+ auto type_error_register = allocate_register ();
1559+ emit<Op::NewTypeError>(type_error_register, message_string);
1560+ perform_needed_unwinds<Op::Throw>();
1561+ emit<Op::Throw>(type_error_register);
1562+ return {};
1563+ }
1564+
1565+ if (operation_name == " ThrowIfNotObject" sv) {
1566+ if (arguments.size () != 1 ) {
1567+ return CodeGenerationError {
1568+ &builtin_identifier,
1569+ " ThrowIfNotObject only accepts one argument" sv,
1570+ };
1571+ }
1572+
1573+ auto source = TRY (arguments[0 ].value ->generate_bytecode (*this )).value ();
1574+ emit<Op::ThrowIfNotObject>(source);
1575+ return {};
1576+ }
1577+
1578+ if (operation_name == " Call" sv) {
1579+ if (arguments.size () < 2 ) {
1580+ return CodeGenerationError {
1581+ &builtin_identifier,
1582+ " Call must have at least two arguments" sv,
1583+ };
1584+ }
1585+
1586+ auto const & callee_argument = arguments[0 ].value ;
1587+ auto callee = TRY (callee_argument->generate_bytecode (*this )).value ();
1588+ auto this_value = TRY (arguments[1 ].value ->generate_bytecode (*this )).value ();
1589+ auto arguments_to_call_with = arguments.slice (2 );
1590+
1591+ Vector<ScopedOperand> argument_operands;
1592+ argument_operands.ensure_capacity (arguments_to_call_with.size ());
1593+ for (auto const & argument : arguments_to_call_with) {
1594+ auto argument_value = TRY (argument.value ->generate_bytecode (*this )).value ();
1595+ argument_operands.unchecked_append (copy_if_needed_to_preserve_evaluation_order (argument_value));
1596+ }
1597+
1598+ auto expression_string = ([&callee_argument] -> Optional<Utf16String> {
1599+ if (auto const * identifier = as_if<Identifier>(*callee_argument))
1600+ return identifier->string ().to_utf16_string ();
1601+
1602+ if (auto const * member_expression = as_if<MemberExpression>(*callee_argument))
1603+ return member_expression->to_string_approximation ();
1604+
1605+ return {};
1606+ })();
1607+
1608+ Optional<Bytecode::StringTableIndex> expression_string_index;
1609+ if (expression_string.has_value ())
1610+ expression_string_index = intern_string (expression_string.release_value ());
1611+
1612+ emit_with_extra_operand_slots<Bytecode::Op::Call>(
1613+ argument_operands.size (),
1614+ dst,
1615+ callee,
1616+ this_value,
1617+ expression_string_index,
1618+ argument_operands);
1619+ return {};
1620+ }
1621+
1622+ if (operation_name == " NewObjectWithNoPrototype" sv) {
1623+ if (!arguments.is_empty ()) {
1624+ return CodeGenerationError {
1625+ &builtin_identifier,
1626+ " NewObjectWithNoPrototype does not take any arguments" sv,
1627+ };
1628+ }
1629+
1630+ emit<Op::NewObjectWithNoPrototype>(dst);
1631+ return {};
1632+ }
1633+
1634+ if (operation_name == " CreateAsyncFromSyncIterator" sv) {
1635+ if (arguments.size () != 3 ) {
1636+ return CodeGenerationError {
1637+ &builtin_identifier,
1638+ " CreateAsyncFromSyncIterator only accepts exactly three arguments" sv,
1639+ };
1640+ }
1641+
1642+ auto iterator = TRY (arguments[0 ].value ->generate_bytecode (*this )).value ();
1643+ auto next_method = TRY (arguments[1 ].value ->generate_bytecode (*this )).value ();
1644+ auto done = TRY (arguments[2 ].value ->generate_bytecode (*this )).value ();
1645+
1646+ emit<Op::CreateAsyncFromSyncIterator>(dst, iterator, next_method, done);
1647+ return {};
1648+ }
1649+
1650+ if (operation_name == " ToLength" sv) {
1651+ if (arguments.size () != 1 ) {
1652+ return CodeGenerationError {
1653+ &builtin_identifier,
1654+ " ToLength only accepts exactly one argument" sv,
1655+ };
1656+ }
1657+
1658+ auto value = TRY (arguments[0 ].value ->generate_bytecode (*this )).value ();
1659+ emit<Op::ToLength>(dst, value);
1660+ return {};
1661+ }
1662+
1663+ if (operation_name == " NewTypeError" sv) {
1664+ if (arguments.size () != 1 ) {
1665+ return CodeGenerationError {
1666+ &builtin_identifier,
1667+ " NewTypeError only accepts one argument" sv,
1668+ };
1669+ }
1670+
1671+ auto const * message = as_if<StringLiteral>(*arguments[0 ].value );
1672+ if (!message) {
1673+ return CodeGenerationError {
1674+ &builtin_identifier,
1675+ " new_type_error's message must be a string literal" sv,
1676+ };
1677+ }
1678+
1679+ auto message_string = intern_string (message->value ());
1680+ emit<Op::NewTypeError>(dst, message_string);
1681+ return {};
1682+ }
1683+
1684+ if (operation_name == " NewArrayWithLength" sv) {
1685+ if (arguments.size () != 1 ) {
1686+ return CodeGenerationError {
1687+ &builtin_identifier,
1688+ " NewArrayWithLength only accepts one argument" sv,
1689+ };
1690+ }
1691+
1692+ auto length = TRY (arguments[0 ].value ->generate_bytecode (*this )).value ();
1693+ emit<Op::NewArrayWithLength>(dst, length);
1694+ return {};
1695+ }
1696+
1697+ if (operation_name == " CreateDataPropertyOrThrow" sv) {
1698+ if (arguments.size () != 3 ) {
1699+ return CodeGenerationError {
1700+ &builtin_identifier,
1701+ " CreateDataPropertyOrThrow only accepts three arguments" sv,
1702+ };
1703+ }
1704+
1705+ auto object = TRY (arguments[0 ].value ->generate_bytecode (*this )).value ();
1706+ auto property = TRY (arguments[1 ].value ->generate_bytecode (*this )).value ();
1707+ auto value = TRY (arguments[2 ].value ->generate_bytecode (*this )).value ();
1708+ emit<Op::CreateDataPropertyOrThrow>(object, property, value);
1709+ return {};
1710+ }
1711+
1712+ #define __JS_ENUMERATE (snake_name, functionName, length ) \
1713+ if (operation_name == #functionName##sv) { \
1714+ Vector<ScopedOperand> argument_operands; \
1715+ argument_operands.ensure_capacity (arguments.size ()); \
1716+ for (auto const & argument : arguments) { \
1717+ auto argument_value = TRY (argument.value ->generate_bytecode (*this )).value (); \
1718+ argument_operands.unchecked_append (copy_if_needed_to_preserve_evaluation_order (argument_value)); \
1719+ } \
1720+ emit_with_extra_operand_slots<Bytecode::Op::Call>( \
1721+ argument_operands.size (), \
1722+ dst, \
1723+ add_constant (m_vm.current_realm ()->intrinsics ().snake_name ##_abstract_operation_function ()), \
1724+ add_constant (js_undefined ()), \
1725+ intern_string (builtin_identifier.string ().to_utf16_string ()), \
1726+ argument_operands); \
1727+ return {}; \
1728+ }
1729+ JS_ENUMERATE_NATIVE_JAVASCRIPT_BACKED_ABSTRACT_OPERATIONS
1730+ #undef __JS_ENUMERATE
1731+
14891732 dbgln (" Unknown builtin abstract operation: '{}'" , operation_name);
14901733 return CodeGenerationError {
14911734 &builtin_identifier,
@@ -1504,6 +1747,18 @@ CodeGenerationErrorOr<Optional<ScopedOperand>> Generator::maybe_generate_builtin
15041747 if (!m_builtin_abstract_operations_enabled)
15051748 return OptionalNone {};
15061749
1750+ if (constant_name == " SYMBOL_ITERATOR" sv) {
1751+ return add_constant (vm ().well_known_symbol_iterator ());
1752+ }
1753+
1754+ if (constant_name == " SYMBOL_ASYNC_ITERATOR" sv) {
1755+ return add_constant (vm ().well_known_symbol_async_iterator ());
1756+ }
1757+
1758+ if (constant_name == " MAX_ARRAY_LIKE_INDEX" sv) {
1759+ return add_constant (Value (MAX_ARRAY_LIKE_INDEX));
1760+ }
1761+
15071762 dbgln (" Unknown builtin constant: '{}'" , constant_name);
15081763 return CodeGenerationError {
15091764 &builtin_identifier,
0 commit comments