Commit 76ab55e3 authored by caitp's avatar caitp Committed by Commit bot

[async-iteration] add support for for-await-of loops in Async Functions

When --harmony-async-iteration is enabled, it is now possible to
use the for-await-of loop, which uses the Async Iteration protocol
rather than the ordinary ES6 Iteration protocol.

the Async-from-Sync Iterator object is not implemented in this CL,
and so for-await-of loops will abort execution if the iterated object
does not have a Symbol.asyncIterator() method. Async-from-Sync
Iterators are implemented seperately in https://codereview.chromium.org/2645313003/

BUG=v8:5855, v8:4483
R=neis@chromium.org, littledan@chromium.org, adamk@chromium.org

Review-Url: https://codereview.chromium.org/2637403008
Cr-Commit-Position: refs/heads/master@{#43224}
parent 70105d5d
......@@ -2961,8 +2961,11 @@ class EmptyParentheses final : public Expression {
// (defined at https://tc39.github.io/ecma262/#sec-getiterator). Ignition
// desugars this into a LoadIC / JSLoadNamed, CallIC, and a type-check to
// validate return value of the Symbol.iterator() call.
enum class IteratorType { kNormal, kAsync };
class GetIterator final : public Expression {
public:
IteratorType hint() const { return hint_; }
Expression* iterable() const { return iterable_; }
void set_iterable(Expression* iterable) { iterable_ = iterable; }
......@@ -2972,6 +2975,10 @@ class GetIterator final : public Expression {
FeedbackSlotCache* cache) {
iterator_property_feedback_slot_ = spec->AddLoadICSlot();
iterator_call_feedback_slot_ = spec->AddCallICSlot();
if (hint() == IteratorType::kAsync) {
async_iterator_property_feedback_slot_ = spec->AddLoadICSlot();
async_iterator_call_feedback_slot_ = spec->AddCallICSlot();
}
}
FeedbackSlot IteratorPropertyFeedbackSlot() const {
......@@ -2982,15 +2989,26 @@ class GetIterator final : public Expression {
return iterator_call_feedback_slot_;
}
FeedbackSlot AsyncIteratorPropertyFeedbackSlot() const {
return async_iterator_property_feedback_slot_;
}
FeedbackSlot AsyncIteratorCallFeedbackSlot() const {
return async_iterator_call_feedback_slot_;
}
private:
friend class AstNodeFactory;
explicit GetIterator(Expression* iterable, int pos)
: Expression(pos, kGetIterator), iterable_(iterable) {}
explicit GetIterator(Expression* iterable, IteratorType hint, int pos)
: Expression(pos, kGetIterator), hint_(hint), iterable_(iterable) {}
IteratorType hint_;
Expression* iterable_;
FeedbackSlot iterator_property_feedback_slot_;
FeedbackSlot iterator_call_feedback_slot_;
FeedbackSlot async_iterator_property_feedback_slot_;
FeedbackSlot async_iterator_call_feedback_slot_;
};
// ----------------------------------------------------------------------------
......@@ -3206,6 +3224,11 @@ class AstNodeFactory final BASE_EMBEDDED {
return NULL;
}
ForOfStatement* NewForOfStatement(ZoneList<const AstRawString*>* labels,
int pos) {
return new (zone_) ForOfStatement(labels, pos);
}
ExpressionStatement* NewExpressionStatement(Expression* expression, int pos) {
return new (zone_) ExpressionStatement(expression, pos);
}
......@@ -3572,8 +3595,9 @@ class AstNodeFactory final BASE_EMBEDDED {
return new (zone_) EmptyParentheses(pos);
}
GetIterator* NewGetIterator(Expression* iterable, int pos) {
return new (zone_) GetIterator(iterable, pos);
GetIterator* NewGetIterator(Expression* iterable, IteratorType hint,
int pos) {
return new (zone_) GetIterator(iterable, hint, pos);
}
Zone* zone() const { return zone_; }
......
......@@ -620,6 +620,13 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadIteratorProperty(
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadAsyncIteratorProperty(
Register object, int feedback_slot) {
size_t name_index = AsyncIteratorSymbolConstantPoolEntry();
OutputLdaNamedProperty(object, name_index, feedback_slot);
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::StoreDataPropertyInLiteral(
Register object, Register name, DataPropertyInLiteralFlags flags,
int feedback_slot) {
......
......@@ -127,6 +127,9 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final
// Named load property of the @@iterator symbol.
BytecodeArrayBuilder& LoadIteratorProperty(Register object,
int feedback_slot);
// Named load property of the @@asyncIterator symbol.
BytecodeArrayBuilder& LoadAsyncIteratorProperty(Register object,
int feedback_slot);
// Store properties. Flag for NeedsSetFunctionName() should
// be in the accumulator.
......
......@@ -2973,21 +2973,64 @@ void BytecodeGenerator::VisitGetIterator(GetIterator* expr) {
VisitForAccumulatorValue(expr->iterable());
// Let method be GetMethod(obj, @@iterator).
builder()
->StoreAccumulatorInRegister(obj)
.LoadIteratorProperty(obj, feedback_index(load_slot))
.StoreAccumulatorInRegister(method);
// Let iterator be Call(method, obj).
builder()->Call(method, args, feedback_index(call_slot),
Call::NAMED_PROPERTY_CALL);
// If Type(iterator) is not Object, throw a TypeError exception.
BytecodeLabel no_type_error;
builder()->JumpIfJSReceiver(&no_type_error);
builder()->CallRuntime(Runtime::kThrowSymbolIteratorInvalid);
builder()->Bind(&no_type_error);
if (expr->hint() == IteratorType::kAsync) {
FeedbackSlot async_load_slot = expr->AsyncIteratorPropertyFeedbackSlot();
FeedbackSlot async_call_slot = expr->AsyncIteratorCallFeedbackSlot();
// Set method to GetMethod(obj, @@asyncIterator)
builder()->StoreAccumulatorInRegister(obj).LoadAsyncIteratorProperty(
obj, feedback_index(async_load_slot));
BytecodeLabel async_iterator_undefined, async_iterator_null, done;
// TODO(ignition): Add a single opcode for JumpIfNullOrUndefined
builder()->JumpIfUndefined(&async_iterator_undefined);
builder()->JumpIfNull(&async_iterator_null);
// Let iterator be Call(method, obj)
builder()->StoreAccumulatorInRegister(method).Call(
method, args, feedback_index(async_call_slot),
Call::NAMED_PROPERTY_CALL);
// If Type(iterator) is not Object, throw a TypeError exception.
builder()->JumpIfJSReceiver(&done);
builder()->CallRuntime(Runtime::kThrowSymbolAsyncIteratorInvalid);
builder()->Bind(&async_iterator_undefined);
builder()->Bind(&async_iterator_null);
// If method is undefined,
// Let syncMethod be GetMethod(obj, @@iterator)
builder()
->LoadIteratorProperty(obj, feedback_index(load_slot))
.StoreAccumulatorInRegister(method);
// Let syncIterator be Call(syncMethod, obj)
builder()->Call(method, args, feedback_index(call_slot),
Call::NAMED_PROPERTY_CALL);
// Return CreateAsyncFromSyncIterator(syncIterator)
// alias `method` register as it's no longer used
Register sync_iter = method;
builder()->StoreAccumulatorInRegister(sync_iter).CallRuntime(
Runtime::kInlineCreateAsyncFromSyncIterator, sync_iter);
builder()->Bind(&done);
} else {
// Let method be GetMethod(obj, @@iterator).
builder()
->StoreAccumulatorInRegister(obj)
.LoadIteratorProperty(obj, feedback_index(load_slot))
.StoreAccumulatorInRegister(method);
// Let iterator be Call(method, obj).
builder()->Call(method, args, feedback_index(call_slot),
Call::NAMED_PROPERTY_CALL);
// If Type(iterator) is not Object, throw a TypeError exception.
BytecodeLabel no_type_error;
builder()->JumpIfJSReceiver(&no_type_error);
builder()->CallRuntime(Runtime::kThrowSymbolIteratorInvalid);
builder()->Bind(&no_type_error);
}
}
void BytecodeGenerator::VisitThisFunction(ThisFunction* expr) {
......
......@@ -319,12 +319,11 @@ Handle<Object> ConstantArrayBuilder::Entry::ToHandle(Isolate* isolate) const {
return heap_number_->value();
case Tag::kScope:
return scope_->scope_info();
case Tag::kIteratorSymbol:
return isolate->factory()->iterator_symbol();
case Tag::kHomeObjectSymbol:
return isolate->factory()->home_object_symbol();
case Tag::kEmptyFixedArray:
return isolate->factory()->empty_fixed_array();
#define ENTRY_LOOKUP(Name, name) \
case Tag::k##Name: \
return isolate->factory()->name();
SINGLETON_CONSTANT_ENTRY_TYPES(ENTRY_LOOKUP);
#undef ENTRY_LOOKUP
}
UNREACHABLE();
return Handle<Object>::null();
......
......@@ -20,9 +20,10 @@ class AstValue;
namespace interpreter {
// Constant array entries that represent singletons.
#define SINGLETON_CONSTANT_ENTRY_TYPES(V) \
V(IteratorSymbol, iterator_symbol) \
V(HomeObjectSymbol, home_object_symbol) \
#define SINGLETON_CONSTANT_ENTRY_TYPES(V) \
V(IteratorSymbol, iterator_symbol) \
V(AsyncIteratorSymbol, async_iterator_symbol) \
V(HomeObjectSymbol, home_object_symbol) \
V(EmptyFixedArray, empty_fixed_array)
// A helper class for constructing constant arrays for the
......
......@@ -475,6 +475,8 @@ class ErrorUtils : public AllStatic {
T(StrictCannotCreateProperty, "Cannot create property '%' on % '%'") \
T(SymbolIteratorInvalid, \
"Result of the Symbol.iterator method is not an object") \
T(SymbolAsyncIteratorInvalid, \
"Result of the Symbol.asyncIterator method is not an object") \
T(SymbolKeyFor, "% is not a symbol") \
T(SymbolToNumber, "Cannot convert a Symbol value to a number") \
T(SymbolToString, "Cannot convert a Symbol value to a string") \
......
......@@ -225,7 +225,8 @@ class ParserBase {
allow_harmony_trailing_commas_(false),
allow_harmony_class_fields_(false),
allow_harmony_object_rest_spread_(false),
allow_harmony_dynamic_import_(false) {}
allow_harmony_dynamic_import_(false),
allow_harmony_async_iteration_(false) {}
#define ALLOW_ACCESSORS(name) \
bool allow_##name() const { return allow_##name##_; } \
......@@ -240,6 +241,7 @@ class ParserBase {
ALLOW_ACCESSORS(harmony_class_fields);
ALLOW_ACCESSORS(harmony_object_rest_spread);
ALLOW_ACCESSORS(harmony_dynamic_import);
ALLOW_ACCESSORS(harmony_async_iteration);
#undef ALLOW_ACCESSORS
......@@ -1292,6 +1294,8 @@ class ParserBase {
ForInfo* for_info, BlockState* for_state,
ZoneList<const AstRawString*>* labels,
bool* ok);
StatementT ParseForAwaitStatement(ZoneList<const AstRawString*>* labels,
bool* ok);
bool IsNextLetKeyword();
bool IsTrivialExpression();
......@@ -1488,6 +1492,7 @@ class ParserBase {
bool allow_harmony_class_fields_;
bool allow_harmony_object_rest_spread_;
bool allow_harmony_dynamic_import_;
bool allow_harmony_async_iteration_;
friend class DiscardableZoneScope;
};
......@@ -4795,6 +4800,10 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement(
case Token::WHILE:
return ParseWhileStatement(labels, ok);
case Token::FOR:
if (V8_UNLIKELY(allow_harmony_async_iteration() && is_async_function() &&
PeekAhead() == Token::AWAIT)) {
return ParseForAwaitStatement(labels, ok);
}
return ParseForStatement(labels, ok);
case Token::CONTINUE:
case Token::BREAK:
......@@ -5700,6 +5709,151 @@ void ParserBase<Impl>::MarkLoopVariableAsAssigned(Scope* scope, Variable* var) {
}
}
template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement(
ZoneList<const AstRawString*>* labels, bool* ok) {
// for await '(' ForDeclaration of AssignmentExpression ')'
DCHECK(is_async_function());
DCHECK(allow_harmony_async_iteration());
int stmt_pos = peek_position();
ForInfo for_info(this);
for_info.mode = ForEachStatement::ITERATE;
// Create an in-between scope for let-bound iteration variables.
BlockState for_state(zone(), &scope_state_);
Expect(Token::FOR, CHECK_OK);
Expect(Token::AWAIT, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK);
for_state.set_start_position(scanner()->location().beg_pos);
for_state.set_is_hidden();
auto loop = factory()->NewForOfStatement(labels, stmt_pos);
typename Types::Target target(this, loop);
ExpressionT each_variable = impl()->EmptyExpression();
bool has_declarations = false;
if (peek() == Token::VAR || peek() == Token::CONST ||
(peek() == Token::LET && IsNextLetKeyword())) {
// The initializer contains declarations
// 'for' 'await' '(' ForDeclaration 'of' AssignmentExpression ')'
// Statement
// 'for' 'await' '(' 'var' ForBinding 'of' AssignmentExpression ')'
// Statement
has_declarations = true;
ParseVariableDeclarations(kForStatement, &for_info.parsing_result, nullptr,
CHECK_OK);
for_info.position = scanner()->location().beg_pos;
// Only a single declaration is allowed in for-await-of loops
if (for_info.parsing_result.declarations.length() != 1) {
impl()->ReportMessageAt(for_info.parsing_result.bindings_loc,
MessageTemplate::kForInOfLoopMultiBindings,
"for-await-of");
*ok = false;
return impl()->NullStatement();
}
// for-await-of's declarations do not permit initializers.
if (for_info.parsing_result.first_initializer_loc.IsValid()) {
impl()->ReportMessageAt(for_info.parsing_result.first_initializer_loc,
MessageTemplate::kForInOfLoopInitializer,
"for-await-of");
*ok = false;
return impl()->NullStatement();
}
} else {
// The initializer does not contain declarations.
// 'for' 'await' '(' LeftHandSideExpression 'of' AssignmentExpression ')'
// Statement
int lhs_beg_pos = peek_position();
ExpressionClassifier classifier(this);
ExpressionT lhs = each_variable = ParseLeftHandSideExpression(CHECK_OK);
int lhs_end_pos = scanner()->location().end_pos;
if (lhs->IsArrayLiteral() || lhs->IsObjectLiteral()) {
ValidateAssignmentPattern(CHECK_OK);
} else {
impl()->RewriteNonPattern(CHECK_OK);
each_variable = impl()->CheckAndRewriteReferenceExpression(
lhs, lhs_beg_pos, lhs_end_pos, MessageTemplate::kInvalidLhsInFor,
kSyntaxError, CHECK_OK);
}
}
ExpectContextualKeyword(CStrVector("of"), CHECK_OK);
int each_keyword_pos = scanner()->location().beg_pos;
const bool kAllowIn = true;
ExpressionT iterable = impl()->EmptyExpression();
{
ExpressionClassifier classifier(this);
iterable = ParseAssignmentExpression(kAllowIn, CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK);
}
Expect(Token::RPAREN, CHECK_OK);
StatementT final_loop = impl()->NullStatement();
{
ReturnExprScope no_tail_calls(function_state_,
ReturnExprContext::kInsideForInOfBody);
BlockState block_state(zone(), &scope_state_);
block_state.set_start_position(scanner()->location().beg_pos);
const bool kDisallowLabelledFunctionStatement = true;
StatementT body = ParseScopedStatement(
nullptr, kDisallowLabelledFunctionStatement, CHECK_OK);
block_state.set_end_position(scanner()->location().end_pos);
if (has_declarations) {
BlockT body_block = impl()->NullBlock();
impl()->DesugarBindingInForEachStatement(&for_info, &body_block,
&each_variable, CHECK_OK);
body_block->statements()->Add(body, zone());
body_block->set_scope(block_state.FinalizedBlockScope());
for_state.set_end_position(scanner()->location().end_pos);
const bool finalize = true;
final_loop = impl()->InitializeForOfStatement(
loop, each_variable, iterable, body_block, finalize,
IteratorType::kAsync, each_keyword_pos);
} else {
const bool finalize = true;
final_loop = impl()->InitializeForOfStatement(
loop, each_variable, iterable, body, finalize, IteratorType::kAsync,
each_keyword_pos);
Scope* for_scope = for_state.FinalizedBlockScope();
DCHECK_NULL(for_scope);
USE(for_scope);
Scope* block_scope = block_state.FinalizedBlockScope();
DCHECK_NULL(block_scope);
USE(block_scope);
return final_loop;
}
}
DCHECK(has_declarations);
BlockT init_block =
impl()->CreateForEachStatementTDZ(impl()->NullBlock(), for_info, ok);
for_state.set_end_position(scanner()->location().end_pos);
Scope* for_scope = for_state.FinalizedBlockScope();
// Parsed for-in loop w/ variable declarations.
if (!impl()->IsNullStatement(init_block)) {
init_block->statements()->Add(final_loop, zone());
init_block->set_scope(for_scope);
return init_block;
}
DCHECK_NULL(for_scope);
return final_loop;
}
template <typename Impl>
void ParserBase<Impl>::ObjectLiteralChecker::CheckDuplicateProto(
Token::Value property) {
......
This diff is collapsed.
......@@ -462,10 +462,15 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
DEFINE_AST_VISITOR_MEMBERS_WITHOUT_STACKOVERFLOW()
};
// !%_IsJSReceiver(result = iterator.next()) &&
// %ThrowIteratorResultNotAnObject(result)
// [if (IteratorType == kAsync)]
// !%_IsJSReceiver(result = Await(iterator.next()) &&
// %ThrowIteratorResultNotAnObject(result)
// [else]
// !%_IsJSReceiver(result = iterator.next()) &&
// %ThrowIteratorResultNotAnObject(result)
// [endif]
Expression* BuildIteratorNextResult(Expression* iterator, Variable* result,
int pos);
IteratorType type, int pos);
// Initialize the components of a for-in / for-of statement.
Statement* InitializeForEachStatement(ForEachStatement* stmt,
......@@ -473,8 +478,9 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
Statement* body, int each_keyword_pos);
Statement* InitializeForOfStatement(ForOfStatement* stmt, Expression* each,
Expression* iterable, Statement* body,
bool finalize,
bool finalize, IteratorType type,
int next_result_pos = kNoSourcePosition);
Block* RewriteForVarInLegacy(const ForInfo& for_info);
void DesugarBindingInForEachStatement(ForInfo* for_info, Block** body_block,
Expression** each_variable, bool* ok);
......@@ -646,16 +652,18 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
void FinalizeIteratorUse(Scope* use_scope, Variable* completion,
Expression* condition, Variable* iter,
Block* iterator_use, Block* result);
Block* iterator_use, Block* result,
IteratorType type);
Statement* FinalizeForOfStatement(ForOfStatement* loop, Variable* completion,
int pos);
IteratorType type, int pos);
void BuildIteratorClose(ZoneList<Statement*>* statements, Variable* iterator,
Variable* input, Variable* output);
void BuildIteratorCloseForCompletion(Scope* scope,
ZoneList<Statement*>* statements,
Variable* iterator,
Expression* completion);
Expression* completion,
IteratorType type);
Statement* CheckCallable(Variable* var, Expression* error, int pos);
V8_INLINE Expression* RewriteAwaitExpression(Expression* value, int pos);
......
......@@ -430,8 +430,9 @@ void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node,
DCHECK(block_->ignore_completion_value());
auto temp = *temp_var = CreateTempVar(current_value_);
auto iterator = CreateTempVar(factory()->NewGetIterator(
factory()->NewVariableProxy(temp), kNoSourcePosition));
auto iterator = CreateTempVar(
factory()->NewGetIterator(factory()->NewVariableProxy(temp),
IteratorType::kNormal, kNoSourcePosition));
auto done =
CreateTempVar(factory()->NewBooleanLiteral(false, kNoSourcePosition));
auto result = CreateTempVar();
......@@ -517,7 +518,7 @@ void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node,
factory()->NewExpressionStatement(
parser_->BuildIteratorNextResult(
factory()->NewVariableProxy(iterator), result,
kNoSourcePosition),
IteratorType::kNormal, kNoSourcePosition),
kNoSourcePosition),
zone());
next_block->statements()->Add(inner_if, zone());
......@@ -588,7 +589,7 @@ void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node,
// result = IteratorNext(iterator);
Statement* get_next = factory()->NewExpressionStatement(
parser_->BuildIteratorNextResult(factory()->NewVariableProxy(iterator),
result, nopos),
result, IteratorType::kNormal, nopos),
nopos);
// %AppendElement(array, result.value);
......@@ -657,7 +658,7 @@ void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node,
Token::NOT, factory()->NewVariableProxy(done), nopos);
parser_->FinalizeIteratorUse(scope(), completion, closing_condition, iterator,
block_, target);
block_, target, IteratorType::kNormal);
block_ = target;
}
......
......@@ -765,6 +765,11 @@ class PreParserFactory {
return PreParserStatement::Default();
}
PreParserStatement NewForOfStatement(ZoneList<const AstRawString*>* labels,
int pos) {
return PreParserStatement::Default();
}
PreParserExpression NewCallRuntime(Runtime::FunctionId id,
ZoneList<PreParserExpression>* arguments,
int pos) {
......@@ -1317,6 +1322,14 @@ class PreParser : public ParserBase<PreParser> {
return stmt;
}
V8_INLINE PreParserStatement InitializeForOfStatement(
PreParserStatement stmt, PreParserExpression each,
PreParserExpression iterable, PreParserStatement body, bool finalize,
IteratorType type, int next_result_pos = kNoSourcePosition) {
MarkExpressionAsAssigned(each);
return stmt;
}
V8_INLINE PreParserStatement RewriteForVarInLegacy(const ForInfo& for_info) {
return PreParserStatement::Null();
}
......
......@@ -88,6 +88,13 @@ RUNTIME_FUNCTION(Runtime_ThrowStackOverflow) {
return isolate->StackOverflow();
}
RUNTIME_FUNCTION(Runtime_ThrowSymbolAsyncIteratorInvalid) {
HandleScope scope(isolate);
DCHECK_EQ(0, args.length());
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kSymbolAsyncIteratorInvalid));
}
RUNTIME_FUNCTION(Runtime_ThrowTypeError) {
HandleScope scope(isolate);
DCHECK_LE(1, args.length());
......@@ -503,5 +510,12 @@ RUNTIME_FUNCTION(Runtime_AllowDynamicFunction) {
Builtins::AllowDynamicFunction(isolate, target, global_proxy));
}
RUNTIME_FUNCTION(Runtime_CreateAsyncFromSyncIterator) {
// TODO(caitp): split AsyncFromSyncIterator functionality out of
// https://codereview.chromium.org/2622833002
UNREACHABLE();
return isolate->heap()->undefined_value();
}
} // namespace internal
} // namespace v8
......@@ -289,6 +289,7 @@ namespace internal {
F(AllocateSeqOneByteString, 1, 1) \
F(AllocateSeqTwoByteString, 1, 1) \
F(CheckIsBootstrapping, 0, 1) \
F(CreateAsyncFromSyncIterator, 1, 1) \
F(CreateListFromArrayLike, 1, 1) \
F(GetAndResetRuntimeCallStats, -1 /* <= 2 */, 1) \
F(ExportFromRuntime, 1, 1) \
......@@ -324,6 +325,7 @@ namespace internal {
F(ThrowNotGeneric, 1, 1) \
F(ThrowReferenceError, 1, 1) \
F(ThrowStackOverflow, 0, 1) \
F(ThrowSymbolAsyncIteratorInvalid, 0, 1) \
F(ThrowTypeError, -1 /* >= 1 */, 1) \
F(ThrowUndefinedOrNullToObject, 1, 1) \
F(Typeof, 1, 1) \
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment