| Index: runtime/vm/flow_graph_builder.cc
|
| diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
|
| index a90c9faa09c61c788dd5ff2d4c6519d563ed6deb..2f98cfc779350ab0180d947fa380644b2e1926be 100644
|
| --- a/runtime/vm/flow_graph_builder.cc
|
| +++ b/runtime/vm/flow_graph_builder.cc
|
| @@ -1335,6 +1335,36 @@ void EffectGraphVisitor::VisitBinaryOpNode(BinaryOpNode* node) {
|
| }
|
| }
|
| return;
|
| + } else if (node->kind() == Token::kIFNULL) {
|
| + // left ?? right. This operation cannot be overloaded.
|
| + // temp = left; temp === null ? right : temp
|
| + ValueGraphVisitor for_left_value(owner());
|
| + node->left()->Visit(&for_left_value);
|
| + Append(for_left_value);
|
| + Do(BuildStoreExprTemp(for_left_value.value()));
|
| +
|
| + LocalVariable* temp_var = owner()->parsed_function().expression_temp_var();
|
| + LoadLocalNode* load_temp =
|
| + new(Z) LoadLocalNode(Scanner::kNoSourcePos, temp_var);
|
| + LiteralNode* null_constant =
|
| + new(Z) LiteralNode(Scanner::kNoSourcePos, Object::null_instance());
|
| + ComparisonNode* check_is_null =
|
| + new(Z) ComparisonNode(Scanner::kNoSourcePos,
|
| + Token::kEQ_STRICT,
|
| + load_temp,
|
| + null_constant);
|
| + TestGraphVisitor for_test(owner(), Scanner::kNoSourcePos);
|
| + check_is_null->Visit(&for_test);
|
| +
|
| + ValueGraphVisitor for_right_value(owner());
|
| + node->right()->Visit(&for_right_value);
|
| + for_right_value.Do(BuildStoreExprTemp(for_right_value.value()));
|
| +
|
| + ValueGraphVisitor for_temp(owner());
|
| + // Nothing to do, left value is already loaded into temp.
|
| +
|
| + Join(for_test, for_right_value, for_temp);
|
| + return;
|
| }
|
| ValueGraphVisitor for_left_value(owner());
|
| node->left()->Visit(&for_left_value);
|
| @@ -1410,7 +1440,39 @@ void ValueGraphVisitor::VisitBinaryOpNode(BinaryOpNode* node) {
|
| }
|
| ReturnDefinition(BuildLoadExprTemp());
|
| return;
|
| + } else if (node->kind() == Token::kIFNULL) {
|
| + // left ?? right. This operation cannot be overloaded.
|
| + // temp = left; temp === null ? right : temp
|
| + ValueGraphVisitor for_left_value(owner());
|
| + node->left()->Visit(&for_left_value);
|
| + Append(for_left_value);
|
| + Do(BuildStoreExprTemp(for_left_value.value()));
|
| +
|
| + LocalVariable* temp_var = owner()->parsed_function().expression_temp_var();
|
| + LoadLocalNode* load_temp =
|
| + new(Z) LoadLocalNode(Scanner::kNoSourcePos, temp_var);
|
| + LiteralNode* null_constant =
|
| + new(Z) LiteralNode(Scanner::kNoSourcePos, Object::null_instance());
|
| + ComparisonNode* check_is_null =
|
| + new(Z) ComparisonNode(Scanner::kNoSourcePos,
|
| + Token::kEQ_STRICT,
|
| + load_temp,
|
| + null_constant);
|
| + TestGraphVisitor for_test(owner(), Scanner::kNoSourcePos);
|
| + check_is_null->Visit(&for_test);
|
| +
|
| + ValueGraphVisitor for_right_value(owner());
|
| + node->right()->Visit(&for_right_value);
|
| + for_right_value.Do(BuildStoreExprTemp(for_right_value.value()));
|
| +
|
| + ValueGraphVisitor for_temp(owner());
|
| + // Nothing to do, left value is already loaded into temp.
|
| +
|
| + Join(for_test, for_right_value, for_temp);
|
| + ReturnDefinition(BuildLoadExprTemp());
|
| + return;
|
| }
|
| +
|
| EffectGraphVisitor::VisitBinaryOpNode(node);
|
| }
|
|
|
| @@ -2703,22 +2765,58 @@ void EffectGraphVisitor::VisitInstanceCallNode(InstanceCallNode* node) {
|
| ValueGraphVisitor for_receiver(owner());
|
| node->receiver()->Visit(&for_receiver);
|
| Append(for_receiver);
|
| - PushArgumentInstr* push_receiver = PushArgument(for_receiver.value());
|
| - ZoneGrowableArray<PushArgumentInstr*>* arguments =
|
| - new(Z) ZoneGrowableArray<PushArgumentInstr*>(
|
| - node->arguments()->length() + 1);
|
| - arguments->Add(push_receiver);
|
| + if (node->is_conditional()) {
|
| + Do(BuildStoreExprTemp(for_receiver.value()));
|
| + LocalVariable* temp_var = owner()->parsed_function().expression_temp_var();
|
| + LoadLocalNode* load_temp =
|
| + new(Z) LoadLocalNode(Scanner::kNoSourcePos, temp_var);
|
| +
|
| + LiteralNode* null_constant =
|
| + new(Z) LiteralNode(Scanner::kNoSourcePos, Object::null_instance());
|
| + ComparisonNode* check_is_null =
|
| + new(Z) ComparisonNode(Scanner::kNoSourcePos,
|
| + Token::kEQ,
|
| + load_temp,
|
| + null_constant);
|
| + TestGraphVisitor for_test(owner(), Scanner::kNoSourcePos);
|
| + check_is_null->Visit(&for_test);
|
| +
|
| + EffectGraphVisitor for_true(owner());
|
| + EffectGraphVisitor for_false(owner());
|
| +
|
| + StoreLocalNode* store_null =
|
| + new(Z) StoreLocalNode(Scanner::kNoSourcePos, temp_var, null_constant);
|
| + store_null->Visit(&for_true);
|
| +
|
| + InstanceCallNode* call =
|
| + new(Z) InstanceCallNode(node->token_pos(),
|
| + load_temp,
|
| + node->function_name(),
|
| + node->arguments());
|
| + StoreLocalNode* store_result =
|
| + new(Z) StoreLocalNode(Scanner::kNoSourcePos, temp_var, call);
|
| + store_result->Visit(&for_false);
|
| +
|
| + Join(for_test, for_true, for_false);
|
| + ReturnDefinition(BuildLoadExprTemp());
|
| + } else {
|
| + PushArgumentInstr* push_receiver = PushArgument(for_receiver.value());
|
| + ZoneGrowableArray<PushArgumentInstr*>* arguments =
|
| + new(Z) ZoneGrowableArray<PushArgumentInstr*>(
|
| + node->arguments()->length() + 1);
|
| + arguments->Add(push_receiver);
|
|
|
| - BuildPushArguments(*node->arguments(), arguments);
|
| - InstanceCallInstr* call = new(Z) InstanceCallInstr(
|
| - node->token_pos(),
|
| - node->function_name(),
|
| - Token::kILLEGAL,
|
| - arguments,
|
| - node->arguments()->names(),
|
| - 1,
|
| - owner()->ic_data_array());
|
| - ReturnDefinition(call);
|
| + BuildPushArguments(*node->arguments(), arguments);
|
| + InstanceCallInstr* call = new(Z) InstanceCallInstr(
|
| + node->token_pos(),
|
| + node->function_name(),
|
| + Token::kILLEGAL,
|
| + arguments,
|
| + node->arguments()->names(),
|
| + 1,
|
| + owner()->ic_data_array());
|
| + ReturnDefinition(call);
|
| + }
|
| }
|
|
|
|
|
| @@ -3063,20 +3161,55 @@ void EffectGraphVisitor::VisitInstanceGetterNode(InstanceGetterNode* node) {
|
| ValueGraphVisitor for_receiver(owner());
|
| node->receiver()->Visit(&for_receiver);
|
| Append(for_receiver);
|
| - PushArgumentInstr* push_receiver = PushArgument(for_receiver.value());
|
| - ZoneGrowableArray<PushArgumentInstr*>* arguments =
|
| - new(Z) ZoneGrowableArray<PushArgumentInstr*>(1);
|
| - arguments->Add(push_receiver);
|
| - const String& name =
|
| - String::ZoneHandle(Z, Field::GetterSymbol(node->field_name()));
|
| - InstanceCallInstr* call = new(Z) InstanceCallInstr(
|
| - node->token_pos(),
|
| - name,
|
| - Token::kGET,
|
| - arguments, Object::null_array(),
|
| - 1,
|
| - owner()->ic_data_array());
|
| - ReturnDefinition(call);
|
| + if (node->is_conditional()) {
|
| + Do(BuildStoreExprTemp(for_receiver.value()));
|
| + LocalVariable* temp_var = owner()->parsed_function().expression_temp_var();
|
| + LoadLocalNode* load_temp =
|
| + new(Z) LoadLocalNode(Scanner::kNoSourcePos, temp_var);
|
| +
|
| + LiteralNode* null_constant =
|
| + new(Z) LiteralNode(Scanner::kNoSourcePos, Object::null_instance());
|
| + ComparisonNode* check_is_null =
|
| + new(Z) ComparisonNode(Scanner::kNoSourcePos,
|
| + Token::kEQ,
|
| + load_temp,
|
| + null_constant);
|
| + TestGraphVisitor for_test(owner(), Scanner::kNoSourcePos);
|
| + check_is_null->Visit(&for_test);
|
| +
|
| + EffectGraphVisitor for_true(owner());
|
| + EffectGraphVisitor for_false(owner());
|
| +
|
| + StoreLocalNode* store_null =
|
| + new(Z) StoreLocalNode(Scanner::kNoSourcePos, temp_var, null_constant);
|
| + store_null->Visit(&for_true);
|
| +
|
| + InstanceGetterNode* getter =
|
| + new(Z) InstanceGetterNode(node->token_pos(),
|
| + load_temp,
|
| + node->field_name());
|
| + StoreLocalNode* store_getter =
|
| + new(Z) StoreLocalNode(Scanner::kNoSourcePos, temp_var, getter);
|
| + store_getter->Visit(&for_false);
|
| +
|
| + Join(for_test, for_true, for_false);
|
| + ReturnDefinition(BuildLoadExprTemp());
|
| + } else {
|
| + PushArgumentInstr* push_receiver = PushArgument(for_receiver.value());
|
| + ZoneGrowableArray<PushArgumentInstr*>* arguments =
|
| + new(Z) ZoneGrowableArray<PushArgumentInstr*>(1);
|
| + arguments->Add(push_receiver);
|
| + const String& name =
|
| + String::ZoneHandle(Z, Field::GetterSymbol(node->field_name()));
|
| + InstanceCallInstr* call = new(Z) InstanceCallInstr(
|
| + node->token_pos(),
|
| + name,
|
| + Token::kGET,
|
| + arguments, Object::null_array(),
|
| + 1,
|
| + owner()->ic_data_array());
|
| + ReturnDefinition(call);
|
| + }
|
| }
|
|
|
|
|
| @@ -3104,6 +3237,37 @@ void EffectGraphVisitor::BuildInstanceSetterArguments(
|
|
|
|
|
| void EffectGraphVisitor::VisitInstanceSetterNode(InstanceSetterNode* node) {
|
| + if (node->is_conditional()) {
|
| + ValueGraphVisitor for_receiver(owner());
|
| + node->receiver()->Visit(&for_receiver);
|
| + Append(for_receiver);
|
| + Do(BuildStoreExprTemp(for_receiver.value()));
|
| +
|
| + LocalVariable* temp_var = owner()->parsed_function().expression_temp_var();
|
| + LoadLocalNode* load_temp =
|
| + new(Z) LoadLocalNode(Scanner::kNoSourcePos, temp_var);
|
| + LiteralNode* null_constant =
|
| + new(Z) LiteralNode(Scanner::kNoSourcePos, Object::null_instance());
|
| + ComparisonNode* check_is_null =
|
| + new(Z) ComparisonNode(Scanner::kNoSourcePos,
|
| + Token::kEQ,
|
| + load_temp,
|
| + null_constant);
|
| + TestGraphVisitor for_test(owner(), Scanner::kNoSourcePos);
|
| + check_is_null->Visit(&for_test);
|
| +
|
| + EffectGraphVisitor for_true(owner());
|
| + EffectGraphVisitor for_false(owner());
|
| +
|
| + InstanceSetterNode* setter =
|
| + new(Z) InstanceSetterNode(node->token_pos(),
|
| + load_temp,
|
| + node->field_name(),
|
| + node->value());
|
| + setter->Visit(&for_false);
|
| + Join(for_test, for_true, for_false);
|
| + return;
|
| + }
|
| ZoneGrowableArray<PushArgumentInstr*>* arguments =
|
| new(Z) ZoneGrowableArray<PushArgumentInstr*>(2);
|
| BuildInstanceSetterArguments(node, arguments, kResultNotNeeded);
|
| @@ -3122,6 +3286,42 @@ void EffectGraphVisitor::VisitInstanceSetterNode(InstanceSetterNode* node) {
|
|
|
|
|
| void ValueGraphVisitor::VisitInstanceSetterNode(InstanceSetterNode* node) {
|
| + if (node->is_conditional()) {
|
| + ValueGraphVisitor for_receiver(owner());
|
| + node->receiver()->Visit(&for_receiver);
|
| + Append(for_receiver);
|
| + Do(BuildStoreExprTemp(for_receiver.value()));
|
| +
|
| + LocalVariable* temp_var = owner()->parsed_function().expression_temp_var();
|
| + LoadLocalNode* load_temp =
|
| + new(Z) LoadLocalNode(Scanner::kNoSourcePos, temp_var);
|
| + LiteralNode* null_constant =
|
| + new(Z) LiteralNode(Scanner::kNoSourcePos, Object::null_instance());
|
| + ComparisonNode* check_is_null =
|
| + new(Z) ComparisonNode(Scanner::kNoSourcePos,
|
| + Token::kEQ,
|
| + load_temp,
|
| + null_constant);
|
| + TestGraphVisitor for_test(owner(), Scanner::kNoSourcePos);
|
| + check_is_null->Visit(&for_test);
|
| +
|
| + ValueGraphVisitor for_true(owner());
|
| + null_constant->Visit(&for_true);
|
| + for_true.Do(BuildStoreExprTemp(for_true.value()));
|
| +
|
| + ValueGraphVisitor for_false(owner());
|
| + InstanceSetterNode* setter =
|
| + new(Z) InstanceSetterNode(node->token_pos(),
|
| + load_temp,
|
| + node->field_name(),
|
| + node->value());
|
| + setter->Visit(&for_false);
|
| + for_false.Do(BuildStoreExprTemp(for_false.value()));
|
| +
|
| + Join(for_test, for_true, for_false);
|
| + ReturnDefinition(BuildLoadExprTemp());
|
| + return;
|
| + }
|
| ZoneGrowableArray<PushArgumentInstr*>* arguments =
|
| new(Z) ZoneGrowableArray<PushArgumentInstr*>(2);
|
| BuildInstanceSetterArguments(node, arguments, kResultNeeded);
|
|
|