Commit b5f146a0 authored by caitp's avatar caitp Committed by Commit bot

[ignition] desugar GetIterator() via bytecode rather than via AST

Introduces:
- a new AST node representing the GetIterator() algorithm in the specification, to be used by ForOfStatement, YieldExpression (in the case of delegating yield*), and the future `for-await-of` loop proposed in http://tc39.github.io/proposal-async-iteration/#sec-async-iterator-value-unwrap-functions.
- a new opcode (JumpIfJSReceiver), which is useful for `if Type(object) is not Object` checks which are common throughout the specification. This node is easily eliminated by TurboFan.

The AST node is desugared specially in bytecode, rather than manually when building the AST. The benefit of this is that desugaring in the BytecodeGenerator is much simpler and easier to understand than desugaring the AST.

This also reduces parse time very slightly, and allows us to use LoadIC rather than KeyedLoadIC, which seems to have  better baseline performance. This results in a ~20% improvement in test/js-perf-test/Iterators micro-benchmarks, which I believe owes to the use of the slightly faster LoadIC as opposed to the KeyedLoadIC in the baseline case. Both produce identical optimized code via TurboFan when the type check can be eliminated, and the load can be replaced with a constant value.

BUG=v8:4280
R=bmeurer@chromium.org, rmcilroy@chromium.org, adamk@chromium.org, neis@chromium.org, jarin@chromium.org
TBR=rossberg@chromium.org

Review-Url: https://codereview.chromium.org/2557593004
Cr-Commit-Position: refs/heads/master@{#41555}
parent 378b6b22
......@@ -273,6 +273,8 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
void VisitEmptyParentheses(EmptyParentheses* paren) { UNREACHABLE(); }
void VisitGetIterator(GetIterator* expr) { UNREACHABLE(); }
void VisitIfStatement(IfStatement* stmt) {
DCHECK_EQ(kFuncScope, scope_);
RECURSE(Visit(stmt->condition()));
......
......@@ -372,6 +372,9 @@ void AstExpressionRewriter::VisitEmptyParentheses(EmptyParentheses* node) {
NOTHING();
}
void AstExpressionRewriter::VisitGetIterator(GetIterator* node) {
AST_REWRITE_PROPERTY(Expression, node, iterable);
}
void AstExpressionRewriter::VisitDoExpression(DoExpression* node) {
REWRITE_THIS(node);
......
......@@ -186,6 +186,9 @@ void AstLiteralReindexer::VisitSpread(Spread* node) {
void AstLiteralReindexer::VisitEmptyParentheses(EmptyParentheses* node) {}
void AstLiteralReindexer::VisitGetIterator(GetIterator* node) {
Visit(node->iterable());
}
void AstLiteralReindexer::VisitForInStatement(ForInStatement* node) {
Visit(node->each());
......
......@@ -414,6 +414,13 @@ void AstNumberingVisitor::VisitEmptyParentheses(EmptyParentheses* node) {
UNREACHABLE();
}
void AstNumberingVisitor::VisitGetIterator(GetIterator* node) {
IncrementNodeCount();
DisableFullCodegenAndCrankshaft(kGetIterator);
node->set_base_id(ReserveIdRange(GetIterator::num_ids()));
Visit(node->iterable());
ReserveFeedbackSlots(node);
}
void AstNumberingVisitor::VisitForInStatement(ForInStatement* node) {
IncrementNodeCount();
......
......@@ -470,6 +470,12 @@ void AstTraversalVisitor<Subclass>::VisitEmptyParentheses(
PROCESS_EXPRESSION(expr);
}
template <class Subclass>
void AstTraversalVisitor<Subclass>::VisitGetIterator(GetIterator* expr) {
PROCESS_EXPRESSION(expr);
RECURSE_EXPRESSION(Visit(expr->iterable()));
}
template <class Subclass>
void AstTraversalVisitor<Subclass>::VisitSuperPropertyReference(
SuperPropertyReference* expr) {
......
......@@ -102,6 +102,7 @@ namespace internal {
V(SuperCallReference) \
V(CaseClause) \
V(EmptyParentheses) \
V(GetIterator) \
V(DoExpression) \
V(RewritableExpression)
......@@ -2936,7 +2937,43 @@ class EmptyParentheses final : public Expression {
explicit EmptyParentheses(int pos) : Expression(pos, kEmptyParentheses) {}
};
// Represents the spec operation `GetIterator()`
// (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.
class GetIterator final : public Expression {
public:
Expression* iterable() const { return iterable_; }
void set_iterable(Expression* iterable) { iterable_ = iterable; }
static int num_ids() { return parent_num_ids(); }
void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
FeedbackVectorSlotCache* cache) {
iterator_property_feedback_slot_ =
spec->AddSlot(FeedbackVectorSlotKind::LOAD_IC);
iterator_call_feedback_slot_ =
spec->AddSlot(FeedbackVectorSlotKind::CALL_IC);
}
FeedbackVectorSlot IteratorPropertyFeedbackSlot() const {
return iterator_property_feedback_slot_;
}
FeedbackVectorSlot IteratorCallFeedbackSlot() const {
return iterator_call_feedback_slot_;
}
private:
friend class AstNodeFactory;
explicit GetIterator(Expression* iterable, int pos)
: Expression(pos, kGetIterator), iterable_(iterable) {}
Expression* iterable_;
FeedbackVectorSlot iterator_property_feedback_slot_;
FeedbackVectorSlot iterator_call_feedback_slot_;
};
// ----------------------------------------------------------------------------
// Basic visitor
......@@ -3519,6 +3556,10 @@ class AstNodeFactory final BASE_EMBEDDED {
return new (zone_) EmptyParentheses(pos);
}
GetIterator* NewGetIterator(Expression* iterable, int pos) {
return new (zone_) GetIterator(iterable, pos);
}
Zone* zone() const { return zone_; }
void set_zone(Zone* zone) { zone_ = zone; }
......
......@@ -370,6 +370,11 @@ void CallPrinter::VisitEmptyParentheses(EmptyParentheses* node) {
UNREACHABLE();
}
void CallPrinter::VisitGetIterator(GetIterator* node) {
Print("GetIterator(");
Find(node->iterable(), true);
Print(")");
}
void CallPrinter::VisitThisFunction(ThisFunction* node) {}
......@@ -1181,6 +1186,10 @@ void AstPrinter::VisitEmptyParentheses(EmptyParentheses* node) {
IndentedScope indent(this, "()", node->position());
}
void AstPrinter::VisitGetIterator(GetIterator* node) {
IndentedScope indent(this, "GET-ITERATOR", node->position());
Visit(node->iterable());
}
void AstPrinter::VisitThisFunction(ThisFunction* node) {
IndentedScope indent(this, "THIS-FUNCTION", node->position());
......
......@@ -88,6 +88,7 @@ namespace internal {
"The function_data field should be a BytecodeArray on interpreter entry") \
V(kGeneratedCodeIsTooLarge, "Generated code is too large") \
V(kGenerator, "Generator") \
V(kGetIterator, "GetIterator") \
V(kGlobalFunctionsMustHaveInitialMap, \
"Global functions must have initial map") \
V(kGraphBuildingFailed, "Optimized graph construction failed") \
......
......@@ -2165,6 +2165,10 @@ void AstGraphBuilder::VisitEmptyParentheses(EmptyParentheses* expr) {
UNREACHABLE();
}
void AstGraphBuilder::VisitGetIterator(GetIterator* expr) {
// GetIterator is supported only by going through Ignition first.
UNREACHABLE();
}
void AstGraphBuilder::VisitThisFunction(ThisFunction* expr) {
Node* value = GetFunctionClosure();
......
......@@ -201,6 +201,7 @@ void ALAA::VisitSpread(Spread* e) { UNREACHABLE(); }
void ALAA::VisitEmptyParentheses(EmptyParentheses* e) { UNREACHABLE(); }
void ALAA::VisitGetIterator(GetIterator* e) { UNREACHABLE(); }
void ALAA::VisitCaseClause(CaseClause* cc) {
if (!cc->is_default()) Visit(cc->label());
......
......@@ -1715,6 +1715,12 @@ void BytecodeGraphBuilder::VisitJumpIfNotHoleConstant() {
BuildJumpIfNotHole();
}
void BytecodeGraphBuilder::VisitJumpIfJSReceiver() { BuildJumpIfJSReceiver(); }
void BytecodeGraphBuilder::VisitJumpIfJSReceiverConstant() {
BuildJumpIfJSReceiver();
}
void BytecodeGraphBuilder::VisitJumpIfNull() {
BuildJumpIfEqual(jsgraph()->NullConstant());
}
......@@ -2026,6 +2032,12 @@ void BytecodeGraphBuilder::BuildJumpIfNotHole() {
BuildJumpIfNot(condition);
}
void BytecodeGraphBuilder::BuildJumpIfJSReceiver() {
Node* accumulator = environment()->LookupAccumulator();
Node* condition = NewNode(simplified()->ObjectIsReceiver(), accumulator);
BuildJumpIf(condition);
}
Node** BytecodeGraphBuilder::EnsureInputBufferSize(int size) {
if (size > input_buffer_size_) {
size = size + kInputBufferSizeIncrement + input_buffer_size_;
......
......@@ -182,6 +182,7 @@ class BytecodeGraphBuilder {
void BuildJumpIfToBooleanTrue();
void BuildJumpIfToBooleanFalse();
void BuildJumpIfNotHole();
void BuildJumpIfJSReceiver();
// Simulates control flow by forward-propagating environments.
void MergeIntoSuccessorEnvironment(int target_offset);
......@@ -229,6 +230,9 @@ class BytecodeGraphBuilder {
Zone* graph_zone() const { return graph()->zone(); }
JSGraph* jsgraph() const { return jsgraph_; }
JSOperatorBuilder* javascript() const { return jsgraph_->javascript(); }
SimplifiedOperatorBuilder* simplified() const {
return jsgraph_->simplified();
}
Zone* local_zone() const { return local_zone_; }
const Handle<BytecodeArray>& bytecode_array() const {
return bytecode_array_;
......
......@@ -11489,6 +11489,9 @@ void HOptimizedGraphBuilder::VisitEmptyParentheses(EmptyParentheses* expr) {
UNREACHABLE();
}
void HOptimizedGraphBuilder::VisitGetIterator(GetIterator* expr) {
UNREACHABLE();
}
HValue* HOptimizedGraphBuilder::AddThisFunction() {
return AddInstruction(BuildThisFunction());
......
......@@ -756,6 +756,7 @@ void AstTyper::VisitEmptyParentheses(EmptyParentheses* expr) {
UNREACHABLE();
}
void AstTyper::VisitGetIterator(GetIterator* expr) { UNREACHABLE(); }
void AstTyper::VisitThisFunction(ThisFunction* expr) {}
......
......@@ -1446,6 +1446,7 @@ void FullCodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) {
UNREACHABLE();
}
void FullCodeGenerator::VisitGetIterator(GetIterator* expr) { UNREACHABLE(); }
void FullCodeGenerator::VisitRewritableExpression(RewritableExpression* expr) {
Visit(expr->expression());
......
......@@ -725,6 +725,12 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNotHole(
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfJSReceiver(
BytecodeLabel* label) {
OutputJumpIfJSReceiver(label, 0);
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::JumpLoop(BytecodeLabel* label,
int loop_depth) {
OutputJumpLoop(label, 0, loop_depth);
......
......@@ -279,6 +279,7 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final
BytecodeArrayBuilder& JumpIfTrue(BytecodeLabel* label);
BytecodeArrayBuilder& JumpIfFalse(BytecodeLabel* label);
BytecodeArrayBuilder& JumpIfNotHole(BytecodeLabel* label);
BytecodeArrayBuilder& JumpIfJSReceiver(BytecodeLabel* label);
BytecodeArrayBuilder& JumpIfNull(BytecodeLabel* label);
BytecodeArrayBuilder& JumpIfUndefined(BytecodeLabel* label);
BytecodeArrayBuilder& JumpLoop(BytecodeLabel* label, int loop_depth);
......
......@@ -163,6 +163,8 @@ Bytecode GetJumpWithConstantOperand(Bytecode jump_bytecode) {
return Bytecode::kJumpIfNullConstant;
case Bytecode::kJumpIfUndefined:
return Bytecode::kJumpIfUndefinedConstant;
case Bytecode::kJumpIfJSReceiver:
return Bytecode::kJumpIfJSReceiverConstant;
default:
UNREACHABLE();
return Bytecode::kIllegal;
......
......@@ -583,6 +583,7 @@ BytecodeGenerator::BytecodeGenerator(CompilationInfo* info)
generator_state_(),
loop_depth_(0),
home_object_symbol_(info->isolate()->factory()->home_object_symbol()),
iterator_symbol_(info->isolate()->factory()->iterator_symbol()),
empty_fixed_array_(info->isolate()->factory()->empty_fixed_array()) {
AstValueFactory* ast_value_factory = info->parse_info()->ast_value_factory();
const AstRawString* prototype_string = ast_value_factory->prototype_string();
......@@ -2852,6 +2853,33 @@ void BytecodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) {
UNREACHABLE();
}
void BytecodeGenerator::VisitGetIterator(GetIterator* expr) {
FeedbackVectorSlot load_slot = expr->IteratorPropertyFeedbackSlot();
FeedbackVectorSlot call_slot = expr->IteratorCallFeedbackSlot();
RegisterList args = register_allocator()->NewRegisterList(1);
Register method = register_allocator()->NewRegister();
Register obj = args[0];
VisitForAccumulatorValue(expr->iterable());
// Let method be GetMethod(obj, @@iterator).
builder()
->StoreAccumulatorInRegister(obj)
.LoadNamedProperty(obj, iterator_symbol(), 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) {
builder()->LoadAccumulatorWithRegister(Register::function_closure());
}
......
......@@ -194,6 +194,7 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
int feedback_index(FeedbackVectorSlot slot) const;
Handle<Name> home_object_symbol() const { return home_object_symbol_; }
Handle<Name> iterator_symbol() const { return iterator_symbol_; }
Handle<Name> prototype_string() const { return prototype_string_; }
Handle<FixedArray> empty_fixed_array() const { return empty_fixed_array_; }
const AstRawString* undefined_string() const { return undefined_string_; }
......@@ -218,6 +219,7 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
int loop_depth_;
Handle<Name> home_object_symbol_;
Handle<Name> iterator_symbol_;
Handle<Name> prototype_string_;
Handle<FixedArray> empty_fixed_array_;
const AstRawString* undefined_string_;
......
......@@ -231,6 +231,7 @@ namespace interpreter {
V(JumpIfUndefinedConstant, AccumulatorUse::kRead, OperandType::kIdx) \
V(JumpIfTrueConstant, AccumulatorUse::kRead, OperandType::kIdx) \
V(JumpIfFalseConstant, AccumulatorUse::kRead, OperandType::kIdx) \
V(JumpIfJSReceiverConstant, AccumulatorUse::kRead, OperandType::kIdx) \
V(JumpIfNotHoleConstant, AccumulatorUse::kRead, OperandType::kIdx) \
/* - [Start ToBoolean jumps] */ \
V(JumpIfToBooleanTrueConstant, AccumulatorUse::kRead, OperandType::kIdx) \
......@@ -244,6 +245,7 @@ namespace interpreter {
V(JumpIfFalse, AccumulatorUse::kRead, OperandType::kImm) \
V(JumpIfNull, AccumulatorUse::kRead, OperandType::kImm) \
V(JumpIfUndefined, AccumulatorUse::kRead, OperandType::kImm) \
V(JumpIfJSReceiver, AccumulatorUse::kRead, OperandType::kImm) \
V(JumpIfNotHole, AccumulatorUse::kRead, OperandType::kImm) \
\
/* Complex flow control For..in */ \
......@@ -336,6 +338,7 @@ namespace interpreter {
V(JumpIfFalse) \
V(JumpIfNull) \
V(JumpIfUndefined) \
V(JumpIfJSReceiver) \
V(JumpIfNotHole)
#define JUMP_CONDITIONAL_CONSTANT_BYTECODE_LIST(V) \
......@@ -344,6 +347,7 @@ namespace interpreter {
V(JumpIfUndefinedConstant) \
V(JumpIfTrueConstant) \
V(JumpIfFalseConstant) \
V(JumpIfJSReceiverConstant) \
V(JumpIfNotHoleConstant)
#define JUMP_CONSTANT_BYTECODE_LIST(V) \
......
......@@ -2147,6 +2147,49 @@ void Interpreter::DoJumpIfUndefinedConstant(InterpreterAssembler* assembler) {
__ JumpIfWordEqual(accumulator, undefined_value, relative_jump);
}
// JumpIfJSReceiver <imm>
//
// Jump by number of bytes represented by an immediate operand if the object
// referenced by the accumulator is a JSReceiver.
void Interpreter::DoJumpIfJSReceiver(InterpreterAssembler* assembler) {
Node* accumulator = __ GetAccumulator();
Node* relative_jump = __ BytecodeOperandImm(0);
Label if_object(assembler), if_notobject(assembler, Label::kDeferred),
if_notsmi(assembler);
__ Branch(__ TaggedIsSmi(accumulator), &if_notobject, &if_notsmi);
__ Bind(&if_notsmi);
__ Branch(__ IsJSReceiver(accumulator), &if_object, &if_notobject);
__ Bind(&if_object);
__ Jump(relative_jump);
__ Bind(&if_notobject);
__ Dispatch();
}
// JumpIfJSReceiverConstant <idx>
//
// Jump by number of bytes in the Smi in the |idx| entry in the constant pool if
// the object referenced by the accumulator is a JSReceiver.
void Interpreter::DoJumpIfJSReceiverConstant(InterpreterAssembler* assembler) {
Node* accumulator = __ GetAccumulator();
Node* index = __ BytecodeOperandIdx(0);
Node* relative_jump = __ LoadAndUntagConstantPoolEntry(index);
Label if_object(assembler), if_notobject(assembler), if_notsmi(assembler);
__ Branch(__ TaggedIsSmi(accumulator), &if_notobject, &if_notsmi);
__ Bind(&if_notsmi);
__ Branch(__ IsJSReceiver(accumulator), &if_object, &if_notobject);
__ Bind(&if_object);
__ Jump(relative_jump);
__ Bind(&if_notobject);
__ Dispatch();
}
// JumpIfNotHole <imm>
//
// Jump by number of bytes represented by an immediate operand if the object
......
......@@ -504,15 +504,6 @@ Literal* Parser::ExpressionFromLiteral(Token::Value token, int pos) {
return NULL;
}
Expression* Parser::GetIterator(Expression* iterable, int pos) {
Expression* iterator_symbol_literal =
factory()->NewSymbolLiteral("iterator_symbol", kNoSourcePosition);
Expression* prop =
factory()->NewProperty(iterable, iterator_symbol_literal, pos);
ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(0, zone());
return factory()->NewCall(prop, args, pos);
}
void Parser::MarkTailPosition(Expression* expression) {
expression->MarkTail();
}
......@@ -2073,12 +2064,13 @@ Statement* Parser::InitializeForOfStatement(ForOfStatement* for_of,
Variable* result = NewTemporary(ast_value_factory()->dot_result_string());
Variable* completion = NewTemporary(avfactory->empty_string());
// iterator = iterable[Symbol.iterator]()
// iterator = GetIterator(iterable)
Expression* assign_iterator;
{
assign_iterator = factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(iterator),
GetIterator(iterable, iterable->position()), iterable->position());
factory()->NewGetIterator(iterable, iterable->position()),
iterable->position());
}
// !%_IsJSReceiver(result = iterator.next()) &&
......@@ -4573,8 +4565,7 @@ void Parser::SetFunctionName(Expression* value, const AstRawString* name) {
// let mode = kNext;
// let output = undefined;
//
// let iterator = iterable[Symbol.iterator]();
// if (!IS_RECEIVER(iterator)) throw MakeTypeError(kSymbolIteratorInvalid);
// let iterator = GetIterator(iterable);
//
// while (true) {
// // From the generator to the iterator:
......@@ -4677,41 +4668,17 @@ Expression* Parser::RewriteYieldStar(Expression* generator,
initialize_output = factory()->NewExpressionStatement(assignment, nopos);
}
// let iterator = iterable[Symbol.iterator];
// let iterator = GetIterator(iterable);
Variable* var_iterator = NewTemporary(ast_value_factory()->empty_string());
Statement* get_iterator;
{
Expression* iterator = GetIterator(iterable, nopos);
Expression* iterator = factory()->NewGetIterator(iterable, nopos);
Expression* iterator_proxy = factory()->NewVariableProxy(var_iterator);
Expression* assignment = factory()->NewAssignment(
Token::ASSIGN, iterator_proxy, iterator, nopos);
get_iterator = factory()->NewExpressionStatement(assignment, nopos);
}
// if (!IS_RECEIVER(iterator)) throw MakeTypeError(kSymbolIteratorInvalid);
Statement* validate_iterator;
{
Expression* is_receiver_call;
{
auto args = new (zone()) ZoneList<Expression*>(1, zone());
args->Add(factory()->NewVariableProxy(var_iterator), zone());
is_receiver_call =
factory()->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
}
Statement* throw_call;
{
Expression* call =
NewThrowTypeError(MessageTemplate::kSymbolIteratorInvalid,
ast_value_factory()->empty_string(), nopos);
throw_call = factory()->NewExpressionStatement(call, nopos);
}
validate_iterator = factory()->NewIfStatement(
is_receiver_call, factory()->NewEmptyStatement(nopos), throw_call,
nopos);
}
// output = iterator.next(input);
Statement* call_next;
{
......@@ -5016,12 +4983,11 @@ Expression* Parser::RewriteYieldStar(Expression* generator,
// The rewriter needs to process the get_value statement only, hence we
// put the preceding statements into an init block.
Block* do_block_ = factory()->NewBlock(nullptr, 7, true, nopos);
Block* do_block_ = factory()->NewBlock(nullptr, 6, true, nopos);
do_block_->statements()->Add(initialize_input, zone());
do_block_->statements()->Add(initialize_mode, zone());
do_block_->statements()->Add(initialize_output, zone());
do_block_->statements()->Add(get_iterator, zone());
do_block_->statements()->Add(validate_iterator, zone());
do_block_->statements()->Add(loop, zone());
do_block_->statements()->Add(maybe_return_value, zone());
......
......@@ -450,8 +450,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
Expression* BuildIteratorNextResult(Expression* iterator, Variable* result,
int pos);
Expression* GetIterator(Expression* iterable, int pos);
// Initialize the components of a for-in / for-of statement.
Statement* InitializeForEachStatement(ForEachStatement* stmt,
Expression* each, Expression* subject,
......
......@@ -359,7 +359,7 @@ void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node,
DCHECK(block_->ignore_completion_value());
auto temp = *temp_var = CreateTempVar(current_value_);
auto iterator = CreateTempVar(parser_->GetIterator(
auto iterator = CreateTempVar(factory()->NewGetIterator(
factory()->NewVariableProxy(temp), kNoSourcePosition));
auto done =
CreateTempVar(factory()->NewBooleanLiteral(false, kNoSourcePosition));
......@@ -673,6 +673,7 @@ NOT_A_PATTERN(ForOfStatement)
NOT_A_PATTERN(ForStatement)
NOT_A_PATTERN(FunctionDeclaration)
NOT_A_PATTERN(FunctionLiteral)
NOT_A_PATTERN(GetIterator)
NOT_A_PATTERN(IfStatement)
NOT_A_PATTERN(Literal)
NOT_A_PATTERN(NativeFunctionLiteral)
......
......@@ -209,6 +209,13 @@ RUNTIME_FUNCTION(Runtime_ThrowIteratorResultNotAnObject) {
NewTypeError(MessageTemplate::kIteratorResultNotAnObject, value));
}
RUNTIME_FUNCTION(Runtime_ThrowSymbolIteratorInvalid) {
HandleScope scope(isolate);
DCHECK(args.length() == 0);
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kSymbolIteratorInvalid));
}
RUNTIME_FUNCTION(Runtime_ThrowNotGeneric) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
......
......@@ -330,6 +330,7 @@ namespace internal {
F(ThrowIncompatibleMethodReceiver, 2, 1) \
F(ThrowInvalidStringLength, 0, 1) \
F(ThrowIteratorResultNotAnObject, 1, 1) \
F(ThrowSymbolIteratorInvalid, 0, 1) \
F(ThrowNotGeneric, 1, 1) \
F(ThrowReferenceError, 1, 1) \
F(ThrowStackOverflow, 0, 1) \
......
......@@ -71,27 +71,8 @@ TEST(SimpleLoop1) {
f.CheckLoopAssignedCount(0, "x");
}
TEST(SimpleLoop2) {
const char* loops[] = {
"while (x) { var x = 0; }", "for(;;) { var x = 0; }",
"for(;x;) { var x = 0; }", "for(;x;x) { var x = 0; }",
"for(var i = x; x; x) { var x = 0; }", "for(y in 0) { var x = 0; }",
"for(y of 0) { var x = 0; }", "for(var x = 0; x; x++) { }",
"for(var x = 0; x++;) { }", "var x; for(;x;x++) { }",
"var x; do { x = 1; } while (0);", "do { var x = 1; } while (0);"};
for (size_t i = 0; i < arraysize(loops); i++) {
TestHelper f(loops[i]);
f.CheckLoopAssignedCount(1, "x");
}
}
TEST(ForInOf1) {
const char* loops[] = {
"for(x in 0) { }", "for(x of 0) { }",
};
TEST(ForIn1) {
const char* loops[] = {"for(x in 0) { }"};
for (size_t i = 0; i < arraysize(loops); i++) {
TestHelper f(loops[i]);
......
......@@ -11,7 +11,7 @@ snippet: "
"
frame size: 15
parameter count: 1
bytecode array length: 266
bytecode array length: 272
bytecodes: [
/* 30 E> */ B(StackCheck),
B(LdaZero),
......@@ -19,11 +19,12 @@ bytecodes: [
B(Mov), R(context), R(11),
B(Mov), R(context), R(12),
/* 48 S> */ B(CreateArrayLiteral), U8(0), U8(0), U8(9),
B(Star), R(14),
B(LdaConstant), U8(1),
/* 48 E> */ B(LdaKeyedProperty), R(14), U8(4),
B(Star), R(13),
/* 48 E> */ B(CallProperty), R(13), R(14), U8(1), U8(2),
B(LdaNamedProperty), R(13), U8(1), U8(2),
B(Star), R(14),
B(CallProperty), R(14), R(13), U8(1), U8(4),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(2),
/* 45 S> */ B(LdaNamedProperty), R(2), U8(2), U8(8),
B(Star), R(14),
......@@ -141,9 +142,9 @@ constant pool: [
FIXED_ARRAY_TYPE,
]
handlers: [
[7, 120, 126],
[10, 84, 86],
[193, 203, 205],
[7, 126, 132],
[10, 90, 92],
[199, 209, 211],
]
---
......@@ -153,7 +154,7 @@ snippet: "
"
frame size: 16
parameter count: 1
bytecode array length: 277
bytecode array length: 286
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaConstant), U8(0),
......@@ -162,10 +163,12 @@ bytecodes: [
B(Star), R(5),
B(Mov), R(context), R(12),
B(Mov), R(context), R(13),
/* 68 S> */ B(LdaConstant), U8(1),
/* 68 E> */ B(LdaKeyedProperty), R(0), U8(4),
B(Star), R(14),
/* 68 E> */ B(CallProperty), R(14), R(0), U8(1), U8(2),
/* 68 S> */ B(LdaNamedProperty), R(0), U8(1), U8(2),
B(Star), R(15),
B(CallProperty), R(15), R(0), U8(1), U8(4),
B(Mov), R(0), R(14),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(3),
/* 65 S> */ B(LdaNamedProperty), R(3), U8(2), U8(8),
B(Star), R(15),
......@@ -289,9 +292,9 @@ constant pool: [
FIXED_ARRAY_TYPE,
]
handlers: [
[11, 120, 126],
[14, 84, 86],
[194, 204, 206],
[11, 129, 135],
[14, 93, 95],
[203, 213, 215],
]
---
......@@ -303,7 +306,7 @@ snippet: "
"
frame size: 15
parameter count: 1
bytecode array length: 284
bytecode array length: 290
bytecodes: [
/* 30 E> */ B(StackCheck),
B(LdaZero),
......@@ -311,11 +314,12 @@ bytecodes: [
B(Mov), R(context), R(11),
B(Mov), R(context), R(12),
/* 48 S> */ B(CreateArrayLiteral), U8(0), U8(0), U8(9),
B(Star), R(14),
B(LdaConstant), U8(1),
/* 48 E> */ B(LdaKeyedProperty), R(14), U8(4),
B(Star), R(13),
/* 48 E> */ B(CallProperty), R(13), R(14), U8(1), U8(2),
B(LdaNamedProperty), R(13), U8(1), U8(2),
B(Star), R(14),
B(CallProperty), R(14), R(13), U8(1), U8(4),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(2),
/* 45 S> */ B(LdaNamedProperty), R(2), U8(2), U8(8),
B(Star), R(14),
......@@ -441,9 +445,9 @@ constant pool: [
FIXED_ARRAY_TYPE,
]
handlers: [
[7, 138, 144],
[10, 102, 104],
[211, 221, 223],
[7, 144, 150],
[10, 108, 110],
[217, 227, 229],
]
---
......@@ -453,7 +457,7 @@ snippet: "
"
frame size: 14
parameter count: 1
bytecode array length: 291
bytecode array length: 297
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(CreateObjectLiteral), U8(0), U8(0), U8(1), R(8),
......@@ -463,11 +467,12 @@ bytecodes: [
B(Mov), R(context), R(10),
B(Mov), R(context), R(11),
/* 77 S> */ B(CreateArrayLiteral), U8(1), U8(1), U8(9),
B(Star), R(13),
B(LdaConstant), U8(2),
/* 77 E> */ B(LdaKeyedProperty), R(13), U8(4),
B(Star), R(12),
/* 77 E> */ B(CallProperty), R(12), R(13), U8(1), U8(2),
B(LdaNamedProperty), R(12), U8(2), U8(2),
B(Star), R(13),
B(CallProperty), R(13), R(12), U8(1), U8(4),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(1),
/* 74 S> */ B(LdaNamedProperty), R(1), U8(3), U8(8),
B(Star), R(13),
......@@ -595,8 +600,8 @@ constant pool: [
FIXED_ARRAY_TYPE,
]
handlers: [
[15, 134, 140],
[18, 98, 100],
[208, 218, 220],
[15, 140, 146],
[18, 104, 106],
[214, 224, 226],
]
......@@ -22,7 +22,7 @@ bytecodes: [
B(LdaZero),
B(TestEqualStrict), R(1), U8(0),
B(JumpIfTrue), U8(53),
B(LdaSmi), U8(77),
B(LdaSmi), U8(78),
B(Star), R(2),
B(CallRuntime), U16(Runtime::kAbort), R(2), U8(1),
B(LdaSmi), U8(-2),
......@@ -135,7 +135,7 @@ bytecodes: [
B(LdaSmi), U8(1),
B(TestEqualStrict), R(1), U8(0),
B(JumpIfTrueConstant), U8(0),
B(LdaSmi), U8(77),
B(LdaSmi), U8(78),
B(Star), R(2),
B(CallRuntime), U16(Runtime::kAbort), R(2), U8(1),
B(LdaSmi), U8(-2),
......@@ -277,7 +277,7 @@ snippet: "
"
frame size: 17
parameter count: 1
bytecode array length: 769
bytecode array length: 775
bytecodes: [
B(Ldar), R(new_target),
B(JumpIfUndefined), U8(28),
......@@ -289,7 +289,7 @@ bytecodes: [
B(LdaSmi), U8(1),
B(TestEqualStrict), R(3), U8(0),
B(JumpIfTrueConstant), U8(3),
B(LdaSmi), U8(77),
B(LdaSmi), U8(78),
B(Star), R(4),
B(CallRuntime), U16(Runtime::kAbort), R(4), U8(1),
B(LdaSmi), U8(-2),
......@@ -345,11 +345,12 @@ bytecodes: [
B(Mov), R(context), R(9),
B(Mov), R(context), R(10),
/* 30 S> */ B(CreateArrayLiteral), U8(1), U8(0), U8(9),
B(Star), R(12),
B(LdaConstant), U8(2),
/* 30 E> */ B(LdaKeyedProperty), R(12), U8(4),
B(Star), R(11),
/* 30 E> */ B(CallProperty), R(11), R(12), U8(1), U8(2),
B(LdaNamedProperty), R(11), U8(2), U8(2),
B(Star), R(12),
B(CallProperty), R(12), R(11), U8(1), U8(4),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
/* 30 E> */ B(StaContextSlot), R(1), U8(7), U8(0),
B(LdaSmi), U8(-2),
B(TestEqual), R(3), U8(0),
......@@ -357,7 +358,7 @@ bytecodes: [
B(LdaSmi), U8(1),
B(TestEqualStrict), R(3), U8(0),
B(JumpIfTrueConstant), U8(8),
B(LdaSmi), U8(77),
B(LdaSmi), U8(78),
B(Star), R(11),
B(CallRuntime), U16(Runtime::kAbort), R(11), U8(1),
/* 27 S> */ B(LdaContextSlot), R(1), U8(7), U8(0),
......@@ -605,7 +606,7 @@ constant pool: [
FIXED_ARRAY_TYPE,
FIXED_ARRAY_TYPE,
SYMBOL_TYPE,
Smi [149],
Smi [155],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
......@@ -620,12 +621,12 @@ constant pool: [
FIXED_ARRAY_TYPE,
Smi [133],
Smi [159],
Smi [579],
Smi [585],
]
handlers: [
[46, 688, 694],
[143, 438, 444],
[146, 394, 396],
[540, 556, 558],
[46, 694, 700],
[143, 444, 450],
[146, 400, 402],
[546, 562, 564],
]
......@@ -22,7 +22,7 @@ bytecodes: [
B(LdaZero),
B(TestEqualStrict), R(1), U8(0),
B(JumpIfTrue), U8(63),
B(LdaSmi), U8(77),
B(LdaSmi), U8(78),
B(Star), R(2),
B(CallRuntime), U16(Runtime::kAbort), R(2), U8(1),
B(LdaSmi), U8(-2),
......@@ -92,7 +92,7 @@ bytecodes: [
B(LdaZero),
B(TestEqualStrict), R(1), U8(0),
B(JumpIfTrue), U8(63),
B(LdaSmi), U8(77),
B(LdaSmi), U8(78),
B(Star), R(2),
B(CallRuntime), U16(Runtime::kAbort), R(2), U8(1),
B(LdaSmi), U8(-2),
......@@ -164,7 +164,7 @@ bytecodes: [
B(LdaZero),
B(TestEqualStrict), R(2), U8(0),
B(JumpIfTrue), U8(63),
B(LdaSmi), U8(77),
B(LdaSmi), U8(78),
B(Star), R(3),
B(CallRuntime), U16(Runtime::kAbort), R(3), U8(1),
B(LdaSmi), U8(-2),
......@@ -268,7 +268,7 @@ bytecodes: [
B(LdaZero),
B(TestEqualStrict), R(2), U8(0),
B(JumpIfTrue), U8(63),
B(LdaSmi), U8(77),
B(LdaSmi), U8(78),
B(Star), R(3),
B(CallRuntime), U16(Runtime::kAbort), R(3), U8(1),
B(LdaSmi), U8(-2),
......@@ -357,7 +357,7 @@ bytecodes: [
B(LdaZero),
B(TestEqualStrict), R(2), U8(0),
B(JumpIfTrue), U8(67),
B(LdaSmi), U8(77),
B(LdaSmi), U8(78),
B(Star), R(3),
B(CallRuntime), U16(Runtime::kAbort), R(3), U8(1),
B(LdaSmi), U8(-2),
......@@ -448,7 +448,7 @@ bytecodes: [
B(LdaZero),
B(TestEqualStrict), R(2), U8(0),
B(JumpIfTrue), U8(67),
B(LdaSmi), U8(77),
B(LdaSmi), U8(78),
B(Star), R(3),
B(CallRuntime), U16(Runtime::kAbort), R(3), U8(1),
B(LdaSmi), U8(-2),
......@@ -537,7 +537,7 @@ bytecodes: [
B(LdaZero),
B(TestEqualStrict), R(1), U8(0),
B(JumpIfTrue), U8(67),
B(LdaSmi), U8(77),
B(LdaSmi), U8(78),
B(Star), R(2),
B(CallRuntime), U16(Runtime::kAbort), R(2), U8(1),
B(LdaSmi), U8(-2),
......@@ -612,7 +612,7 @@ bytecodes: [
B(LdaZero),
B(TestEqualStrict), R(1), U8(0),
B(JumpIfTrue), U8(67),
B(LdaSmi), U8(77),
B(LdaSmi), U8(78),
B(Star), R(2),
B(CallRuntime), U16(Runtime::kAbort), R(2), U8(1),
B(LdaSmi), U8(-2),
......@@ -703,7 +703,7 @@ bytecodes: [
B(LdaZero),
B(TestEqualStrict), R(1), U8(0),
B(JumpIfTrue), U8(63),
B(LdaSmi), U8(77),
B(LdaSmi), U8(78),
B(Star), R(2),
B(CallRuntime), U16(Runtime::kAbort), R(2), U8(1),
B(LdaSmi), U8(-2),
......@@ -773,7 +773,7 @@ bytecodes: [
B(LdaZero),
B(TestEqualStrict), R(1), U8(0),
B(JumpIfTrue), U8(63),
B(LdaSmi), U8(77),
B(LdaSmi), U8(78),
B(Star), R(2),
B(CallRuntime), U16(Runtime::kAbort), R(2), U8(1),
B(LdaSmi), U8(-2),
......@@ -844,7 +844,7 @@ bytecodes: [
B(LdaZero),
B(TestEqualStrict), R(1), U8(0),
B(JumpIfTrue), U8(73),
B(LdaSmi), U8(77),
B(LdaSmi), U8(78),
B(Star), R(2),
B(CallRuntime), U16(Runtime::kAbort), R(2), U8(1),
B(LdaSmi), U8(-2),
......
......@@ -209,7 +209,8 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
// Short jumps with Imm8 operands
{
BytecodeLabel start, after_jump1, after_jump2, after_jump3, after_jump4;
BytecodeLabel start, after_jump1, after_jump2, after_jump3, after_jump4,
after_jump5;
builder.Bind(&start)
.Jump(&after_jump1)
.Bind(&after_jump1)
......@@ -219,11 +220,13 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.Bind(&after_jump3)
.JumpIfNotHole(&after_jump4)
.Bind(&after_jump4)
.JumpIfJSReceiver(&after_jump5)
.Bind(&after_jump5)
.JumpLoop(&start, 0);
}
// Longer jumps with constant operands
BytecodeLabel end[8];
BytecodeLabel end[9];
{
BytecodeLabel after_jump;
builder.Jump(&end[0])
......@@ -238,7 +241,9 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.JumpIfFalse(&end[4])
.JumpIfNull(&end[5])
.JumpIfUndefined(&end[6])
.JumpIfNotHole(&end[7]);
.JumpIfNotHole(&end[7])
.LoadLiteral(factory->prototype_string())
.JumpIfJSReceiver(&end[8]);
}
// Perform an operation that returns boolean value to
......
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