| Index: runtime/vm/flow_graph_optimizer.cc
|
| diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
|
| index 747d2a54fe0d613299d72b2319291bf02ea7f2ee..8e49cd350ded5782e9ab0447c2f45a9e37456f10 100644
|
| --- a/runtime/vm/flow_graph_optimizer.cc
|
| +++ b/runtime/vm/flow_graph_optimizer.cc
|
| @@ -49,20 +49,20 @@ void FlowGraphOptimizer::ApplyClassIds() {
|
| ForwardInstructionIterator it(entry);
|
| current_iterator_ = ⁢
|
| for (; !it.Done(); it.Advance()) {
|
| - if (it.Current()->IsInstanceCall()) {
|
| - InstanceCallInstr* call = it.Current()->AsInstanceCall();
|
| + Instruction* instr = it.Current();
|
| + if (instr->IsInstanceCall()) {
|
| + InstanceCallInstr* call = instr->AsInstanceCall();
|
| if (call->HasICData()) {
|
| if (TryCreateICData(call)) {
|
| VisitInstanceCall(call);
|
| }
|
| }
|
| - } else if (it.Current()->IsPolymorphicInstanceCall()) {
|
| - SpecializePolymorphicInstanceCall(
|
| - it.Current()->AsPolymorphicInstanceCall());
|
| - } else if (it.Current()->IsStrictCompare()) {
|
| - VisitStrictCompare(it.Current()->AsStrictCompare());
|
| - } else if (it.Current()->IsBranch()) {
|
| - ComparisonInstr* compare = it.Current()->AsBranch()->comparison();
|
| + } else if (instr->IsPolymorphicInstanceCall()) {
|
| + SpecializePolymorphicInstanceCall(instr->AsPolymorphicInstanceCall());
|
| + } else if (instr->IsStrictCompare()) {
|
| + VisitStrictCompare(instr->AsStrictCompare());
|
| + } else if (instr->IsBranch()) {
|
| + ComparisonInstr* compare = instr->AsBranch()->comparison();
|
| if (compare->IsStrictCompare()) {
|
| VisitStrictCompare(compare->AsStrictCompare());
|
| }
|
| @@ -84,7 +84,7 @@ bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) {
|
| GrowableArray<intptr_t> class_ids(call->ic_data()->num_args_tested());
|
| ASSERT(call->ic_data()->num_args_tested() <= call->ArgumentCount());
|
| for (intptr_t i = 0; i < call->ic_data()->num_args_tested(); i++) {
|
| - intptr_t cid = call->ArgumentAt(i)->value()->Type()->ToCid();
|
| + intptr_t cid = call->PushArgumentAt(i)->value()->Type()->ToCid();
|
| class_ids.Add(cid);
|
| }
|
| // TODO(srdjan): Test for other class_ids > 1.
|
| @@ -150,7 +150,8 @@ void FlowGraphOptimizer::SpecializePolymorphicInstanceCall(
|
| return; // Already specialized.
|
| }
|
|
|
| - const intptr_t receiver_cid = call->ArgumentAt(0)->value()->Type()->ToCid();
|
| + const intptr_t receiver_cid =
|
| + call->PushArgumentAt(0)->value()->Type()->ToCid();
|
| if (receiver_cid == kDynamicCid) {
|
| return; // No information about receiver was infered.
|
| }
|
| @@ -234,24 +235,32 @@ void FlowGraphOptimizer::InsertConversion(Representation from,
|
| (use->Type()->ToCid() == kDoubleCid));
|
| const intptr_t deopt_id = (deopt_target != NULL) ?
|
| deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId;
|
| - converted = new UnboxIntegerInstr(new Value(use->definition()), deopt_id);
|
| + converted = new UnboxIntegerInstr(use->Copy(), deopt_id);
|
| +
|
| } else if ((from == kUnboxedMint) && (to == kTagged)) {
|
| - converted = new BoxIntegerInstr(new Value(use->definition()));
|
| + converted = new BoxIntegerInstr(use->Copy());
|
| +
|
| } else if (from == kUnboxedMint && to == kUnboxedDouble) {
|
| // Convert by boxing/unboxing.
|
| // TODO(fschneider): Implement direct unboxed mint-to-double conversion.
|
| - BoxIntegerInstr* boxed = new BoxIntegerInstr(new Value(use->definition()));
|
| + BoxIntegerInstr* boxed = new BoxIntegerInstr(use->Copy());
|
| + use->RemoveFromUseList();
|
| + use->set_definition(boxed);
|
| + boxed->AddInputUse(use);
|
| InsertBefore(insert_before, boxed, NULL, Definition::kValue);
|
| +
|
| const intptr_t deopt_id = (deopt_target != NULL) ?
|
| deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId;
|
| converted = new UnboxDoubleInstr(new Value(boxed), deopt_id);
|
| +
|
| } else if ((from == kUnboxedDouble) && (to == kTagged)) {
|
| - converted = new BoxDoubleInstr(new Value(use->definition()), NULL);
|
| + converted = new BoxDoubleInstr(use->Copy(), NULL);
|
| +
|
| } else if ((from == kTagged) && (to == kUnboxedDouble)) {
|
| - const intptr_t deopt_id = (deopt_target != NULL) ?
|
| - deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId;
|
| ASSERT((deopt_target != NULL) ||
|
| (use->Type()->ToCid() == kDoubleCid));
|
| + const intptr_t deopt_id = (deopt_target != NULL) ?
|
| + deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId;
|
| ConstantInstr* constant = use->definition()->AsConstant();
|
| if ((constant != NULL) && constant->value().IsSmi()) {
|
| const double dbl_val = Smi::Cast(constant->value()).AsDoubleValue();
|
| @@ -261,13 +270,15 @@ void FlowGraphOptimizer::InsertConversion(Representation from,
|
| InsertBefore(insert_before, double_const, NULL, Definition::kValue);
|
| converted = new UnboxDoubleInstr(new Value(double_const), deopt_id);
|
| } else {
|
| - converted = new UnboxDoubleInstr(new Value(use->definition()), deopt_id);
|
| + converted = new UnboxDoubleInstr(use->Copy(), deopt_id);
|
| }
|
| }
|
| ASSERT(converted != NULL);
|
| + use->RemoveFromUseList();
|
| + use->set_definition(converted);
|
| + converted->AddInputUse(use);
|
| InsertBefore(insert_before, converted, use->instruction()->env(),
|
| Definition::kValue);
|
| - use->set_definition(converted);
|
| }
|
|
|
|
|
| @@ -459,23 +470,16 @@ static bool ShouldSpecializeForDouble(const ICData& ic_data) {
|
| }
|
|
|
|
|
| -static void RemovePushArguments(InstanceCallInstr* call) {
|
| - // Remove original push arguments.
|
| +void FlowGraphOptimizer::ReplaceCall(Definition* call,
|
| + Definition* replacement) {
|
| + // Remove the original push arguments.
|
| for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
|
| - PushArgumentInstr* push = call->ArgumentAt(i);
|
| - push->ReplaceUsesWith(push->value()->definition());
|
| - push->RemoveFromGraph();
|
| - }
|
| -}
|
| -
|
| -
|
| -static void RemovePushArguments(StaticCallInstr* call) {
|
| - // Remove original push arguments.
|
| - for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
|
| - PushArgumentInstr* push = call->ArgumentAt(i);
|
| + PushArgumentInstr* push = call->PushArgumentAt(i);
|
| push->ReplaceUsesWith(push->value()->definition());
|
| + push->UnuseAllInputs();
|
| push->RemoveFromGraph();
|
| }
|
| + call->ReplaceWith(replacement, current_iterator());
|
| }
|
|
|
|
|
| @@ -496,19 +500,29 @@ static intptr_t ReceiverClassId(InstanceCallInstr* call) {
|
| }
|
|
|
|
|
| -void FlowGraphOptimizer::AddCheckClass(InstanceCallInstr* call,
|
| - Value* value) {
|
| +void FlowGraphOptimizer::AddCheckClass(Definition* to_check,
|
| + const ICData& unary_checks,
|
| + intptr_t deopt_id,
|
| + Environment* deopt_environment,
|
| + Instruction* insert_before) {
|
| // Type propagation has not run yet, we cannot eliminate the check.
|
| - const ICData& unary_checks =
|
| - ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks());
|
| Instruction* check = NULL;
|
| if ((unary_checks.NumberOfChecks() == 1) &&
|
| (unary_checks.GetReceiverClassIdAt(0) == kSmiCid)) {
|
| - check = new CheckSmiInstr(value, call->deopt_id());
|
| + check = new CheckSmiInstr(new Value(to_check), deopt_id);
|
| } else {
|
| - check = new CheckClassInstr(value, call->deopt_id(), unary_checks);
|
| + check = new CheckClassInstr(new Value(to_check), deopt_id, unary_checks);
|
| }
|
| - InsertBefore(call, check, call->env(), Definition::kEffect);
|
| + InsertBefore(insert_before, check, deopt_environment, Definition::kEffect);
|
| +}
|
| +
|
| +
|
| +void FlowGraphOptimizer::AddReceiverCheck(InstanceCallInstr* call) {
|
| + AddCheckClass(call->ArgumentAt(0),
|
| + ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()),
|
| + call->deopt_id(),
|
| + call->env(),
|
| + call);
|
| }
|
|
|
|
|
| @@ -530,46 +544,43 @@ static bool ArgIsAlwaysSmi(const ICData& ic_data, intptr_t arg_n) {
|
|
|
| intptr_t FlowGraphOptimizer::PrepareIndexedOp(InstanceCallInstr* call,
|
| intptr_t class_id,
|
| - Value** array,
|
| - Value** index) {
|
| - *array = call->ArgumentAt(0)->value();
|
| - *index = call->ArgumentAt(1)->value();
|
| + Definition** array,
|
| + Definition** index) {
|
| // Insert class check and index smi checks and attach a copy of the
|
| // original environment because the operation can still deoptimize.
|
| - AddCheckClass(call, (*array)->Copy());
|
| + AddReceiverCheck(call);
|
| InsertBefore(call,
|
| - new CheckSmiInstr((*index)->Copy(), call->deopt_id()),
|
| + new CheckSmiInstr(new Value(*index), call->deopt_id()),
|
| call->env(),
|
| Definition::kEffect);
|
| +
|
| // If both index and array are constants, then do a compile-time check.
|
| // TODO(srdjan): Remove once constant propagation handles bounds checks.
|
| bool skip_check = false;
|
| - if ((*array)->BindsToConstant() && (*index)->BindsToConstant()) {
|
| - ConstantInstr* array_def = (*array)->definition()->AsConstant();
|
| + if ((*array)->IsConstant() && (*index)->IsConstant()) {
|
| const ImmutableArray& constant_array =
|
| - ImmutableArray::Cast(array_def->value());
|
| - ConstantInstr* index_def = (*index)->definition()->AsConstant();
|
| - if (index_def->value().IsSmi()) {
|
| - intptr_t constant_index = Smi::Cast(index_def->value()).Value();
|
| - skip_check = (constant_index < constant_array.Length());
|
| - }
|
| + ImmutableArray::Cast((*array)->AsConstant()->value());
|
| + const Object& constant_index = (*index)->AsConstant()->value();
|
| + skip_check = constant_index.IsSmi() &&
|
| + (Smi::Cast(constant_index).Value() < constant_array.Length());
|
| }
|
| if (!skip_check) {
|
| // Insert array length load and bounds check.
|
| const bool is_immutable =
|
| CheckArrayBoundInstr::IsFixedLengthArrayType(class_id);
|
| - LoadFieldInstr* length = new LoadFieldInstr(
|
| - (*array)->Copy(),
|
| - CheckArrayBoundInstr::LengthOffsetFor(class_id),
|
| - Type::ZoneHandle(Type::SmiType()),
|
| - is_immutable);
|
| + LoadFieldInstr* length =
|
| + new LoadFieldInstr(new Value(*array),
|
| + CheckArrayBoundInstr::LengthOffsetFor(class_id),
|
| + Type::ZoneHandle(Type::SmiType()),
|
| + is_immutable);
|
| length->set_result_cid(kSmiCid);
|
| length->set_recognized_kind(
|
| LoadFieldInstr::RecognizedKindFromArrayCid(class_id));
|
| InsertBefore(call, length, NULL, Definition::kValue);
|
| +
|
| InsertBefore(call,
|
| new CheckArrayBoundInstr(new Value(length),
|
| - (*index)->Copy(),
|
| + new Value(*index),
|
| class_id,
|
| call),
|
| call->env(),
|
| @@ -578,12 +589,12 @@ intptr_t FlowGraphOptimizer::PrepareIndexedOp(InstanceCallInstr* call,
|
| if (class_id == kGrowableObjectArrayCid) {
|
| // Insert data elements load.
|
| LoadFieldInstr* elements =
|
| - new LoadFieldInstr((*array)->Copy(),
|
| + new LoadFieldInstr(new Value(*array),
|
| GrowableObjectArray::data_offset(),
|
| Type::ZoneHandle(Type::DynamicType()));
|
| elements->set_result_cid(kArrayCid);
|
| InsertBefore(call, elements, NULL, Definition::kValue);
|
| - *array = new Value(elements);
|
| + *array = elements;
|
| return kArrayCid;
|
| }
|
| return class_id;
|
| @@ -651,9 +662,10 @@ bool FlowGraphOptimizer::TryReplaceWithStoreIndexed(InstanceCallInstr* call) {
|
| return false;
|
| }
|
|
|
| + Definition* array = call->ArgumentAt(0);
|
| + Definition* index = call->ArgumentAt(1);
|
| + Definition* stored_value = call->ArgumentAt(2);
|
| if (FLAG_enable_type_checks) {
|
| - Value* array = call->ArgumentAt(0)->value();
|
| - Value* value = call->ArgumentAt(2)->value();
|
| // Only type check for the value. A type check for the index is not
|
| // needed here because we insert a deoptimizing smi-check for the case
|
| // the index is not a smi.
|
| @@ -661,8 +673,8 @@ bool FlowGraphOptimizer::TryReplaceWithStoreIndexed(InstanceCallInstr* call) {
|
| Function::ZoneHandle(call->ic_data()->GetTargetAt(0));
|
| const AbstractType& value_type =
|
| AbstractType::ZoneHandle(target.ParameterTypeAt(2));
|
| - Value* instantiator = NULL;
|
| - Value* type_args = NULL;
|
| + Definition* instantiator = NULL;
|
| + Definition* type_args = NULL;
|
| switch (class_id) {
|
| case kArrayCid:
|
| case kGrowableObjectArrayCid: {
|
| @@ -670,12 +682,12 @@ bool FlowGraphOptimizer::TryReplaceWithStoreIndexed(InstanceCallInstr* call) {
|
| intptr_t type_arguments_field_offset =
|
| instantiator_class.type_arguments_field_offset();
|
| LoadFieldInstr* load_type_args =
|
| - new LoadFieldInstr(array->Copy(),
|
| + new LoadFieldInstr(new Value(array),
|
| type_arguments_field_offset,
|
| Type::ZoneHandle()); // No type.
|
| InsertBefore(call, load_type_args, NULL, Definition::kValue);
|
| - instantiator = array->Copy();
|
| - type_args = new Value(load_type_args);
|
| + instantiator = array;
|
| + type_args = load_type_args;
|
| break;
|
| }
|
| case kInt8ArrayCid:
|
| @@ -691,8 +703,7 @@ bool FlowGraphOptimizer::TryReplaceWithStoreIndexed(InstanceCallInstr* call) {
|
| // Fall through.
|
| case kFloat32ArrayCid:
|
| case kFloat64ArrayCid: {
|
| - instantiator = new Value(flow_graph_->constant_null());
|
| - type_args = new Value(flow_graph_->constant_null());
|
| + type_args = instantiator = flow_graph_->constant_null();
|
| ASSERT((class_id != kFloat32ArrayCid && class_id != kFloat64ArrayCid) ||
|
| value_type.IsDoubleType());
|
| ASSERT(value_type.IsInstantiated());
|
| @@ -704,9 +715,9 @@ bool FlowGraphOptimizer::TryReplaceWithStoreIndexed(InstanceCallInstr* call) {
|
| }
|
| AssertAssignableInstr* assert_value =
|
| new AssertAssignableInstr(call->token_pos(),
|
| - value->Copy(),
|
| - instantiator,
|
| - type_args,
|
| + new Value(stored_value),
|
| + new Value(instantiator),
|
| + new Value(type_args),
|
| value_type,
|
| Symbols::Value());
|
| // Newly inserted instructions that can deoptimize or throw an exception
|
| @@ -716,35 +727,22 @@ bool FlowGraphOptimizer::TryReplaceWithStoreIndexed(InstanceCallInstr* call) {
|
| InsertBefore(call, assert_value, call->env(), Definition::kValue);
|
| }
|
|
|
| - Value* array = NULL;
|
| - Value* index = NULL;
|
| intptr_t array_cid = PrepareIndexedOp(call, class_id, &array, &index);
|
| - Value* value = call->ArgumentAt(2)->value();
|
| // Check if store barrier is needed.
|
| bool needs_store_barrier = true;
|
| if (!value_check.IsNull()) {
|
| needs_store_barrier = false;
|
| - if (value_check.NumberOfChecks() == 1 &&
|
| - value_check.GetReceiverClassIdAt(0) == kSmiCid) {
|
| - InsertBefore(call,
|
| - new CheckSmiInstr(value->Copy(), call->deopt_id()),
|
| - call->env(),
|
| - Definition::kEffect);
|
| - } else {
|
| - InsertBefore(call,
|
| - new CheckClassInstr(value->Copy(),
|
| - call->deopt_id(),
|
| - value_check),
|
| - call->env(),
|
| - Definition::kEffect);
|
| - }
|
| + AddCheckClass(stored_value, value_check, call->deopt_id(), call->env(),
|
| + call);
|
| }
|
|
|
| - Definition* array_op =
|
| - new StoreIndexedInstr(array, index, value,
|
| - needs_store_barrier, array_cid, call->deopt_id());
|
| - call->ReplaceWith(array_op, current_iterator());
|
| - RemovePushArguments(call);
|
| + Definition* array_op = new StoreIndexedInstr(new Value(array),
|
| + new Value(index),
|
| + new Value(stored_value),
|
| + needs_store_barrier,
|
| + array_cid,
|
| + call->deopt_id());
|
| + ReplaceCall(call, array_op);
|
| return true;
|
| }
|
|
|
| @@ -787,49 +785,20 @@ bool FlowGraphOptimizer::TryReplaceWithLoadIndexed(InstanceCallInstr* call) {
|
| default:
|
| return false;
|
| }
|
| - Value* array = NULL;
|
| - Value* index = NULL;
|
| + Definition* array = call->ArgumentAt(0);
|
| + Definition* index = call->ArgumentAt(1);
|
| intptr_t array_cid = PrepareIndexedOp(call, class_id, &array, &index);
|
| Definition* array_op =
|
| - new LoadIndexedInstr(array,
|
| - index,
|
| + new LoadIndexedInstr(new Value(array),
|
| + new Value(index),
|
| FlowGraphCompiler::ElementSizeFor(array_cid),
|
| array_cid,
|
| deopt_id);
|
| - call->ReplaceWith(array_op, current_iterator());
|
| - RemovePushArguments(call);
|
| + ReplaceCall(call, array_op);
|
| return true;
|
| }
|
|
|
|
|
| -void FlowGraphOptimizer::InsertBefore(Instruction* next,
|
| - Instruction* instr,
|
| - Environment* env,
|
| - Definition::UseKind use_kind) {
|
| - if (env != NULL) env->DeepCopyTo(instr);
|
| - if (use_kind == Definition::kValue) {
|
| - ASSERT(instr->IsDefinition());
|
| - instr->AsDefinition()->set_ssa_temp_index(
|
| - flow_graph_->alloc_ssa_temp_index());
|
| - }
|
| - instr->InsertBefore(next);
|
| -}
|
| -
|
| -
|
| -void FlowGraphOptimizer::InsertAfter(Instruction* prev,
|
| - Instruction* instr,
|
| - Environment* env,
|
| - Definition::UseKind use_kind) {
|
| - if (env != NULL) env->DeepCopyTo(instr);
|
| - if (use_kind == Definition::kValue) {
|
| - ASSERT(instr->IsDefinition());
|
| - instr->AsDefinition()->set_ssa_temp_index(
|
| - flow_graph_->alloc_ssa_temp_index());
|
| - }
|
| - instr->InsertAfter(prev);
|
| -}
|
| -
|
| -
|
| bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
|
| Token::Kind op_kind) {
|
| intptr_t operands_type = kIllegalCid;
|
| @@ -926,89 +895,83 @@ bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
|
| break;
|
| default:
|
| UNREACHABLE();
|
| - };
|
| + }
|
|
|
| ASSERT(call->ArgumentCount() == 2);
|
| + Definition* left = call->ArgumentAt(0);
|
| + Definition* right = call->ArgumentAt(1);
|
| if (operands_type == kDoubleCid) {
|
| - Value* left = call->ArgumentAt(0)->value();
|
| - Value* right = call->ArgumentAt(1)->value();
|
| -
|
| // Check that either left or right are not a smi. Result or a
|
| // binary operation with two smis is a smi not a double.
|
| InsertBefore(call,
|
| - new CheckEitherNonSmiInstr(left->Copy(),
|
| - right->Copy(),
|
| + new CheckEitherNonSmiInstr(new Value(left),
|
| + new Value(right),
|
| call),
|
| call->env(),
|
| Definition::kEffect);
|
|
|
| BinaryDoubleOpInstr* double_bin_op =
|
| - new BinaryDoubleOpInstr(op_kind, left->Copy(), right->Copy(), call);
|
| - call->ReplaceWith(double_bin_op, current_iterator());
|
| - RemovePushArguments(call);
|
| + new BinaryDoubleOpInstr(op_kind, new Value(left), new Value(right),
|
| + call);
|
| + ReplaceCall(call, double_bin_op);
|
| } else if (operands_type == kMintCid) {
|
| if (!FlowGraphCompiler::SupportsUnboxedMints()) return false;
|
| - Value* left = call->ArgumentAt(0)->value();
|
| - Value* right = call->ArgumentAt(1)->value();
|
| if ((op_kind == Token::kSHR) || (op_kind == Token::kSHL)) {
|
| ShiftMintOpInstr* shift_op =
|
| - new ShiftMintOpInstr(op_kind, left, right, call);
|
| - call->ReplaceWith(shift_op, current_iterator());
|
| + new ShiftMintOpInstr(op_kind, new Value(left), new Value(right),
|
| + call);
|
| + ReplaceCall(call, shift_op);
|
| } else {
|
| BinaryMintOpInstr* bin_op =
|
| - new BinaryMintOpInstr(op_kind, left, right, call);
|
| - call->ReplaceWith(bin_op, current_iterator());
|
| + new BinaryMintOpInstr(op_kind, new Value(left), new Value(right),
|
| + call);
|
| + ReplaceCall(call, bin_op);
|
| }
|
| - RemovePushArguments(call);
|
| } else if (op_kind == Token::kMOD) {
|
| // TODO(vegorov): implement fast path code for modulo.
|
| ASSERT(operands_type == kSmiCid);
|
| - if (!call->ArgumentAt(1)->value()->BindsToConstant()) return false;
|
| - const Object& obj = call->ArgumentAt(1)->value()->BoundConstant();
|
| + if (!right->IsConstant()) return false;
|
| + const Object& obj = right->AsConstant()->value();
|
| if (!obj.IsSmi()) return false;
|
| const intptr_t value = Smi::Cast(obj).Value();
|
| - if ((value > 0) && Utils::IsPowerOfTwo(value)) {
|
| - Value* left = call->ArgumentAt(0)->value();
|
| - // Insert smi check and attach a copy of the original
|
| - // environment because the smi operation can still deoptimize.
|
| - InsertBefore(call,
|
| - new CheckSmiInstr(left->Copy(), call->deopt_id()),
|
| - call->env(),
|
| - Definition::kEffect);
|
| - ConstantInstr* c = new ConstantInstr(Smi::Handle(Smi::New(value - 1)));
|
| - InsertBefore(call, c, NULL, Definition::kValue);
|
| - BinarySmiOpInstr* bin_op =
|
| - new BinarySmiOpInstr(Token::kBIT_AND, call, left, new Value(c));
|
| - call->ReplaceWith(bin_op, current_iterator());
|
| - RemovePushArguments(call);
|
| - } else {
|
| - // Did not replace.
|
| - return false;
|
| - }
|
| + if ((value <= 0) || !Utils::IsPowerOfTwo(value)) return false;
|
| +
|
| + // Insert smi check and attach a copy of the original environment
|
| + // because the smi operation can still deoptimize.
|
| + InsertBefore(call,
|
| + new CheckSmiInstr(new Value(left), call->deopt_id()),
|
| + call->env(),
|
| + Definition::kEffect);
|
| + ConstantInstr* constant =
|
| + new ConstantInstr(Smi::Handle(Smi::New(value - 1)));
|
| + InsertBefore(call, constant, NULL, Definition::kValue);
|
| + BinarySmiOpInstr* bin_op =
|
| + new BinarySmiOpInstr(Token::kBIT_AND, call,
|
| + new Value(left),
|
| + new Value(constant));
|
| + ReplaceCall(call, bin_op);
|
| } else {
|
| ASSERT(operands_type == kSmiCid);
|
| - Value* left = call->ArgumentAt(0)->value();
|
| - Value* right = call->ArgumentAt(1)->value();
|
| // Insert two smi checks and attach a copy of the original
|
| // environment because the smi operation can still deoptimize.
|
| InsertBefore(call,
|
| - new CheckSmiInstr(left->Copy(), call->deopt_id()),
|
| + new CheckSmiInstr(new Value(left), call->deopt_id()),
|
| call->env(),
|
| Definition::kEffect);
|
| InsertBefore(call,
|
| - new CheckSmiInstr(right->Copy(), call->deopt_id()),
|
| + new CheckSmiInstr(new Value(right), call->deopt_id()),
|
| call->env(),
|
| Definition::kEffect);
|
| - if (left->BindsToConstant() &&
|
| + if (left->IsConstant() &&
|
| ((op_kind == Token::kADD) || (op_kind == Token::kMUL))) {
|
| // Constant should be on the right side.
|
| - Value* temp = left;
|
| + Definition* temp = left;
|
| left = right;
|
| right = temp;
|
| }
|
| - BinarySmiOpInstr* bin_op = new BinarySmiOpInstr(op_kind, call, left, right);
|
| - call->ReplaceWith(bin_op, current_iterator());
|
| - RemovePushArguments(call);
|
| + BinarySmiOpInstr* bin_op =
|
| + new BinarySmiOpInstr(op_kind, call, new Value(left), new Value(right));
|
| + ReplaceCall(call, bin_op);
|
| }
|
| return true;
|
| }
|
| @@ -1017,35 +980,32 @@ bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
|
| bool FlowGraphOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call,
|
| Token::Kind op_kind) {
|
| ASSERT(call->ArgumentCount() == 1);
|
| + Definition* input = call->ArgumentAt(0);
|
| Definition* unary_op = NULL;
|
| if (HasOnlyOneSmi(*call->ic_data())) {
|
| - Value* value = call->ArgumentAt(0)->value();
|
| InsertBefore(call,
|
| - new CheckSmiInstr(value->Copy(), call->deopt_id()),
|
| + new CheckSmiInstr(new Value(input), call->deopt_id()),
|
| call->env(),
|
| Definition::kEffect);
|
| - unary_op = new UnarySmiOpInstr(op_kind, call, value);
|
| + unary_op = new UnarySmiOpInstr(op_kind, call, new Value(input));
|
| } else if ((op_kind == Token::kBIT_NOT) &&
|
| HasOnlySmiOrMint(*call->ic_data()) &&
|
| FlowGraphCompiler::SupportsUnboxedMints()) {
|
| - Value* value = call->ArgumentAt(0)->value();
|
| - unary_op = new UnaryMintOpInstr(op_kind, value, call);
|
| + unary_op = new UnaryMintOpInstr(op_kind, new Value(input), call);
|
| } else if (HasOnlyOneDouble(*call->ic_data()) &&
|
| (op_kind == Token::kNEGATE)) {
|
| - Value* value = call->ArgumentAt(0)->value();
|
| - AddCheckClass(call, value->Copy());
|
| + AddReceiverCheck(call);
|
| ConstantInstr* minus_one =
|
| new ConstantInstr(Double::ZoneHandle(Double::NewCanonical(-1)));
|
| InsertBefore(call, minus_one, NULL, Definition::kValue);
|
| unary_op = new BinaryDoubleOpInstr(Token::kMUL,
|
| - value,
|
| + new Value(input),
|
| new Value(minus_one),
|
| call);
|
| }
|
| if (unary_op == NULL) return false;
|
|
|
| - call->ReplaceWith(unary_op, current_iterator());
|
| - RemovePushArguments(call);
|
| + ReplaceCall(call, unary_op);
|
| return true;
|
| }
|
|
|
| @@ -1071,7 +1031,7 @@ static RawField* GetField(intptr_t class_id, const String& field_name) {
|
| bool FlowGraphOptimizer::InstanceCallNeedsClassCheck(
|
| InstanceCallInstr* call) const {
|
| if (!FLAG_use_cha) return true;
|
| - Definition* callee_receiver = call->ArgumentAt(0)->value()->definition();
|
| + Definition* callee_receiver = call->ArgumentAt(0);
|
| ASSERT(callee_receiver != NULL);
|
| const Function& function = flow_graph_->parsed_function().function();
|
| if (function.IsDynamicFunction() &&
|
| @@ -1087,7 +1047,7 @@ bool FlowGraphOptimizer::InstanceCallNeedsClassCheck(
|
| bool FlowGraphOptimizer::MethodExtractorNeedsClassCheck(
|
| InstanceCallInstr* call) const {
|
| if (!FLAG_use_cha) return true;
|
| - Definition* callee_receiver = call->ArgumentAt(0)->value()->definition();
|
| + Definition* callee_receiver = call->ArgumentAt(0);
|
| ASSERT(callee_receiver != NULL);
|
| const Function& function = flow_graph_->parsed_function().function();
|
| if (function.IsDynamicFunction() &&
|
| @@ -1115,18 +1075,20 @@ void FlowGraphOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) {
|
| ASSERT(!field.IsNull());
|
|
|
| if (InstanceCallNeedsClassCheck(call)) {
|
| - AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
|
| + AddReceiverCheck(call);
|
| }
|
| - // Detach environment from the original instruction because it can't
|
| - // deoptimize.
|
| - call->set_env(NULL);
|
| LoadFieldInstr* load = new LoadFieldInstr(
|
| - call->ArgumentAt(0)->value(),
|
| + new Value(call->ArgumentAt(0)),
|
| field.Offset(),
|
| AbstractType::ZoneHandle(field.type()),
|
| field.is_final());
|
| - call->ReplaceWith(load, current_iterator());
|
| - RemovePushArguments(call);
|
| + // Detach environment from the original instruction because it can't
|
| + // deoptimize.
|
| + for (Environment::DeepIterator it(call->env()); !it.Done(); it.Advance()) {
|
| + it.CurrentValue()->RemoveFromUseList();
|
| + }
|
| + call->set_env(NULL);
|
| + ReplaceCall(call, load);
|
| }
|
|
|
|
|
| @@ -1134,29 +1096,26 @@ void FlowGraphOptimizer::InlineArrayLengthGetter(InstanceCallInstr* call,
|
| intptr_t length_offset,
|
| bool is_immutable,
|
| MethodRecognizer::Kind kind) {
|
| - // Check receiver class.
|
| - AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
|
| + AddReceiverCheck(call);
|
|
|
| LoadFieldInstr* load = new LoadFieldInstr(
|
| - call->ArgumentAt(0)->value(),
|
| + new Value(call->ArgumentAt(0)),
|
| length_offset,
|
| Type::ZoneHandle(Type::SmiType()),
|
| is_immutable);
|
| load->set_result_cid(kSmiCid);
|
| load->set_recognized_kind(kind);
|
| - call->ReplaceWith(load, current_iterator());
|
| - RemovePushArguments(call);
|
| + ReplaceCall(call, load);
|
| }
|
|
|
|
|
| void FlowGraphOptimizer::InlineGrowableArrayCapacityGetter(
|
| InstanceCallInstr* call) {
|
| - // Check receiver class.
|
| - AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
|
| + AddReceiverCheck(call);
|
|
|
| // TODO(srdjan): type of load should be GrowableObjectArrayType.
|
| LoadFieldInstr* data_load = new LoadFieldInstr(
|
| - call->ArgumentAt(0)->value(),
|
| + new Value(call->ArgumentAt(0)),
|
| Array::data_offset(),
|
| Type::ZoneHandle(Type::DynamicType()));
|
| data_load->set_result_cid(kArrayCid);
|
| @@ -1169,18 +1128,17 @@ void FlowGraphOptimizer::InlineGrowableArrayCapacityGetter(
|
| length_load->set_result_cid(kSmiCid);
|
| length_load->set_recognized_kind(MethodRecognizer::kObjectArrayLength);
|
|
|
| - call->ReplaceWith(length_load, current_iterator());
|
| - RemovePushArguments(call);
|
| + ReplaceCall(call, length_load);
|
| }
|
|
|
|
|
| -static LoadFieldInstr* BuildLoadStringLength(Value* str) {
|
| +static LoadFieldInstr* BuildLoadStringLength(Definition* str) {
|
| // Treat length loads as mutable (i.e. affected by side effects) to avoid
|
| // hoisting them since we can't hoist the preceding class-check. This
|
| // is because of externalization of strings that affects their class-id.
|
| const bool is_immutable = false;
|
| LoadFieldInstr* load = new LoadFieldInstr(
|
| - str,
|
| + new Value(str),
|
| String::length_offset(),
|
| Type::ZoneHandle(Type::SmiType()),
|
| is_immutable);
|
| @@ -1191,20 +1149,16 @@ static LoadFieldInstr* BuildLoadStringLength(Value* str) {
|
|
|
|
|
| void FlowGraphOptimizer::InlineStringLengthGetter(InstanceCallInstr* call) {
|
| - // Check receiver class.
|
| - AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
|
| -
|
| - LoadFieldInstr* load = BuildLoadStringLength(call->ArgumentAt(0)->value());
|
| - call->ReplaceWith(load, current_iterator());
|
| - RemovePushArguments(call);
|
| + AddReceiverCheck(call);
|
| + LoadFieldInstr* load = BuildLoadStringLength(call->ArgumentAt(0));
|
| + ReplaceCall(call, load);
|
| }
|
|
|
|
|
| void FlowGraphOptimizer::InlineStringIsEmptyGetter(InstanceCallInstr* call) {
|
| - // Check receiver class.
|
| - AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
|
| + AddReceiverCheck(call);
|
|
|
| - LoadFieldInstr* load = BuildLoadStringLength(call->ArgumentAt(0)->value());
|
| + LoadFieldInstr* load = BuildLoadStringLength(call->ArgumentAt(0));
|
| InsertBefore(call, load, NULL, Definition::kValue);
|
|
|
| ConstantInstr* zero = new ConstantInstr(Smi::Handle(Smi::New(0)));
|
| @@ -1214,8 +1168,7 @@ void FlowGraphOptimizer::InlineStringIsEmptyGetter(InstanceCallInstr* call) {
|
| new StrictCompareInstr(Token::kEQ_STRICT,
|
| new Value(load),
|
| new Value(zero));
|
| - call->ReplaceWith(compare, current_iterator());
|
| - RemovePushArguments(call);
|
| + ReplaceCall(call, compare);
|
| }
|
|
|
|
|
| @@ -1306,40 +1259,37 @@ bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) {
|
| LoadIndexedInstr* FlowGraphOptimizer::BuildStringCharCodeAt(
|
| InstanceCallInstr* call,
|
| intptr_t cid) {
|
| - Value* str = call->ArgumentAt(0)->value();
|
| - Value* index = call->ArgumentAt(1)->value();
|
| - AddCheckClass(call, str->Copy());
|
| + Definition* str = call->ArgumentAt(0);
|
| + Definition* index = call->ArgumentAt(1);
|
| + AddReceiverCheck(call);
|
| InsertBefore(call,
|
| - new CheckSmiInstr(index->Copy(), call->deopt_id()),
|
| + new CheckSmiInstr(new Value(index), call->deopt_id()),
|
| call->env(),
|
| Definition::kEffect);
|
| // If both index and string are constants, then do a compile-time check.
|
| // TODO(srdjan): Remove once constant propagation handles bounds checks.
|
| bool skip_check = false;
|
| - if (str->BindsToConstant() && index->BindsToConstant()) {
|
| - ConstantInstr* string_def = str->definition()->AsConstant();
|
| + if (str->IsConstant() && index->IsConstant()) {
|
| const String& constant_string =
|
| - String::Cast(string_def->value());
|
| - ConstantInstr* index_def = index->definition()->AsConstant();
|
| - if (index_def->value().IsSmi()) {
|
| - intptr_t constant_index = Smi::Cast(index_def->value()).Value();
|
| - skip_check = (constant_index < constant_string.Length());
|
| - }
|
| + String::Cast(str->AsConstant()->value());
|
| + const Object& constant_index = index->AsConstant()->value();
|
| + skip_check = constant_index.IsSmi() &&
|
| + (Smi::Cast(constant_index).Value() < constant_string.Length());
|
| }
|
| if (!skip_check) {
|
| // Insert bounds check.
|
| - LoadFieldInstr* length = BuildLoadStringLength(str->Copy());
|
| + LoadFieldInstr* length = BuildLoadStringLength(str);
|
| InsertBefore(call, length, NULL, Definition::kValue);
|
| InsertBefore(call,
|
| new CheckArrayBoundInstr(new Value(length),
|
| - index->Copy(),
|
| + new Value(index),
|
| cid,
|
| call),
|
| call->env(),
|
| Definition::kEffect);
|
| }
|
| - return new LoadIndexedInstr(str,
|
| - index,
|
| + return new LoadIndexedInstr(new Value(str),
|
| + new Value(index),
|
| FlowGraphCompiler::ElementSizeFor(cid),
|
| cid,
|
| Isolate::kNoDeoptId); // Can't deoptimize.
|
| @@ -1349,16 +1299,15 @@ LoadIndexedInstr* FlowGraphOptimizer::BuildStringCharCodeAt(
|
| void FlowGraphOptimizer::ReplaceWithMathCFunction(
|
| InstanceCallInstr* call,
|
| MethodRecognizer::Kind recognized_kind) {
|
| - AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
|
| + AddReceiverCheck(call);
|
| ZoneGrowableArray<Value*>* args =
|
| new ZoneGrowableArray<Value*>(call->ArgumentCount());
|
| for (intptr_t i = 0; i < call->ArgumentCount(); i++) {
|
| - args->Add(call->ArgumentAt(i)->value());
|
| + args->Add(new Value(call->ArgumentAt(i)));
|
| }
|
| InvokeMathCFunctionInstr* invoke =
|
| new InvokeMathCFunctionInstr(args, call, recognized_kind);
|
| - call->ReplaceWith(invoke, current_iterator());
|
| - RemovePushArguments(call);
|
| + ReplaceCall(call, invoke);
|
| }
|
|
|
|
|
| @@ -1420,8 +1369,7 @@ bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
|
| ((class_ids[0] == kOneByteStringCid) ||
|
| (class_ids[0] == kTwoByteStringCid))) {
|
| LoadIndexedInstr* instr = BuildStringCharCodeAt(call, class_ids[0]);
|
| - call->ReplaceWith(instr, current_iterator());
|
| - RemovePushArguments(call);
|
| + ReplaceCall(call, instr);
|
| return true;
|
| }
|
| if ((recognized_kind == MethodRecognizer::kStringBaseCharAt) &&
|
| @@ -1434,8 +1382,7 @@ bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
|
| StringFromCharCodeInstr* char_at =
|
| new StringFromCharCodeInstr(new Value(load_char_code),
|
| kOneByteStringCid);
|
| - call->ReplaceWith(char_at, current_iterator());
|
| - RemovePushArguments(call);
|
| + ReplaceCall(call, char_at);
|
| return true;
|
| }
|
|
|
| @@ -1451,20 +1398,19 @@ bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
|
| if (class_ids[0] == kDoubleCid) {
|
| switch (recognized_kind) {
|
| case MethodRecognizer::kDoubleToInteger: {
|
| - AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
|
| + AddReceiverCheck(call);
|
| ASSERT(call->HasICData());
|
| const ICData& ic_data = *call->ic_data();
|
| + Definition* input = call->ArgumentAt(0);
|
| Definition* d2i_instr = NULL;
|
| if (ic_data.deopt_reason() == kDeoptDoubleToSmi) {
|
| // Do not repeatedly deoptimize because result didn't fit into Smi.
|
| - d2i_instr = new DoubleToIntegerInstr(call->ArgumentAt(0)->value(),
|
| - call);
|
| + d2i_instr = new DoubleToIntegerInstr(new Value(input), call);
|
| } else {
|
| // Optimistically assume result fits into Smi.
|
| - d2i_instr = new DoubleToSmiInstr(call->ArgumentAt(0)->value(), call);
|
| + d2i_instr = new DoubleToSmiInstr(new Value(input), call);
|
| }
|
| - call->ReplaceWith(d2i_instr, current_iterator());
|
| - RemovePushArguments(call);
|
| + ReplaceCall(call, d2i_instr);
|
| return true;
|
| }
|
| case MethodRecognizer::kDoubleMod:
|
| @@ -1478,13 +1424,12 @@ bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
|
| if (!CPUFeatures::double_truncate_round_supported()) {
|
| ReplaceWithMathCFunction(call, recognized_kind);
|
| } else {
|
| - AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
|
| + AddReceiverCheck(call);
|
| DoubleToDoubleInstr* d2d_instr =
|
| - new DoubleToDoubleInstr(call->ArgumentAt(0)->value(),
|
| + new DoubleToDoubleInstr(new Value(call->ArgumentAt(0)),
|
| call,
|
| recognized_kind);
|
| - call->ReplaceWith(d2d_instr, current_iterator());
|
| - RemovePushArguments(call);
|
| + ReplaceCall(call, d2d_instr);
|
| }
|
| return true;
|
| default:
|
| @@ -1526,8 +1471,7 @@ bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
|
| return false;
|
| }
|
| ASSERT(array_op != NULL);
|
| - call->ReplaceWith(array_op, current_iterator());
|
| - RemovePushArguments(call);
|
| + ReplaceCall(call, array_op);
|
| return true;
|
| }
|
| return false;
|
| @@ -1538,50 +1482,50 @@ LoadIndexedInstr* FlowGraphOptimizer::BuildByteArrayViewLoad(
|
| InstanceCallInstr* call,
|
| intptr_t receiver_cid,
|
| intptr_t view_cid) {
|
| - Value* array = call->ArgumentAt(0)->value();
|
| - Value* byte_index = call->ArgumentAt(1)->value();
|
| -
|
| - AddCheckClass(call, array->Copy());
|
| - const bool is_immutable = true;
|
| - LoadFieldInstr* length = new LoadFieldInstr(
|
| - array->Copy(),
|
| - CheckArrayBoundInstr::LengthOffsetFor(receiver_cid),
|
| - Type::ZoneHandle(Type::SmiType()),
|
| - is_immutable);
|
| - length->set_result_cid(kSmiCid);
|
| - length->set_recognized_kind(
|
| - LoadFieldInstr::RecognizedKindFromArrayCid(receiver_cid));
|
| - InsertBefore(call, length, NULL, Definition::kValue);
|
| -
|
| - // len_in_bytes = length * kBytesPerElement(receiver)
|
| - intptr_t element_size = FlowGraphCompiler::ElementSizeFor(receiver_cid);
|
| - ConstantInstr* bytes_per_element =
|
| - new ConstantInstr(Smi::Handle(Smi::New(element_size)));
|
| - InsertBefore(call, bytes_per_element, NULL, Definition::kValue);
|
| - BinarySmiOpInstr* len_in_bytes =
|
| - new BinarySmiOpInstr(Token::kMUL,
|
| - call,
|
| - new Value(length),
|
| - new Value(bytes_per_element));
|
| - InsertBefore(call, len_in_bytes, call->env(), Definition::kValue);
|
| + Definition* array = call->ArgumentAt(0);
|
| + Definition* byte_index = call->ArgumentAt(1);
|
| +
|
| + AddReceiverCheck(call);
|
| + const bool is_immutable = true;
|
| + LoadFieldInstr* length = new LoadFieldInstr(
|
| + new Value(array),
|
| + CheckArrayBoundInstr::LengthOffsetFor(receiver_cid),
|
| + Type::ZoneHandle(Type::SmiType()),
|
| + is_immutable);
|
| + length->set_result_cid(kSmiCid);
|
| + length->set_recognized_kind(
|
| + LoadFieldInstr::RecognizedKindFromArrayCid(receiver_cid));
|
| + InsertBefore(call, length, NULL, Definition::kValue);
|
| +
|
| + // len_in_bytes = length * kBytesPerElement(receiver)
|
| + intptr_t element_size = FlowGraphCompiler::ElementSizeFor(receiver_cid);
|
| + ConstantInstr* bytes_per_element =
|
| + new ConstantInstr(Smi::Handle(Smi::New(element_size)));
|
| + InsertBefore(call, bytes_per_element, NULL, Definition::kValue);
|
| + BinarySmiOpInstr* len_in_bytes =
|
| + new BinarySmiOpInstr(Token::kMUL,
|
| + call,
|
| + new Value(length),
|
| + new Value(bytes_per_element));
|
| + InsertBefore(call, len_in_bytes, call->env(), Definition::kValue);
|
|
|
| // Check byte_index < len_in_bytes.
|
| - InsertBefore(call,
|
| - new CheckArrayBoundInstr(new Value(len_in_bytes),
|
| - byte_index->Copy(),
|
| - receiver_cid,
|
| - call),
|
| - call->env(),
|
| - Definition::kEffect);
|
| + InsertBefore(call,
|
| + new CheckArrayBoundInstr(new Value(len_in_bytes),
|
| + new Value(byte_index),
|
| + receiver_cid,
|
| + call),
|
| + call->env(),
|
| + Definition::kEffect);
|
|
|
| - // TODO(fschneider): Optimistically build smi load for Int32 and Uint32
|
| - // loads on ia32 like we do for normal array loads, and only revert to
|
| - // mint case after deoptimizing here.
|
| - return new LoadIndexedInstr(array,
|
| - byte_index,
|
| - 1, // Index scale.
|
| - view_cid,
|
| - Isolate::kNoDeoptId); // Can't deoptimize.
|
| + // TODO(fschneider): Optimistically build smi load for Int32 and Uint32
|
| + // loads on ia32 like we do for normal array loads, and only revert to
|
| + // mint case after deoptimizing here.
|
| + return new LoadIndexedInstr(new Value(array),
|
| + new Value(byte_index),
|
| + 1, // Index scale.
|
| + view_cid,
|
| + Isolate::kNoDeoptId); // Can't deoptimize.
|
| }
|
|
|
|
|
| @@ -1617,37 +1561,35 @@ RawBool* FlowGraphOptimizer::InstanceOfAsBool(const ICData& ic_data,
|
| // TODO(srdjan): Use ICData to check if always true or false.
|
| void FlowGraphOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) {
|
| ASSERT(Token::IsTypeTestOperator(call->token_kind()));
|
| - Value* left_val = call->ArgumentAt(0)->value();
|
| - Value* instantiator_val = call->ArgumentAt(1)->value();
|
| - Value* type_args_val = call->ArgumentAt(2)->value();
|
| + Definition* left = call->ArgumentAt(0);
|
| + Definition* instantiator = call->ArgumentAt(1);
|
| + Definition* type_args = call->ArgumentAt(2);
|
| const AbstractType& type =
|
| - AbstractType::Cast(call->ArgumentAt(3)->value()->BoundConstant());
|
| + AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value());
|
| const bool negate =
|
| - Bool::Cast(call->ArgumentAt(4)->value()->BoundConstant()).value();
|
| + Bool::Cast(call->ArgumentAt(4)->AsConstant()->value()).value();
|
| const ICData& unary_checks =
|
| ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks());
|
| if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) {
|
| Bool& as_bool = Bool::ZoneHandle(InstanceOfAsBool(unary_checks, type));
|
| if (!as_bool.IsNull()) {
|
| - AddCheckClass(call, left_val->Copy());
|
| + AddReceiverCheck(call);
|
| if (negate) {
|
| - as_bool = as_bool.value() ? Bool::False().raw() : Bool::True().raw();
|
| + as_bool = Bool::Get(!as_bool.value());
|
| }
|
| ConstantInstr* bool_const = new ConstantInstr(as_bool);
|
| - call->ReplaceWith(bool_const, current_iterator());
|
| - RemovePushArguments(call);
|
| + ReplaceCall(call, bool_const);
|
| return;
|
| }
|
| }
|
| InstanceOfInstr* instance_of =
|
| new InstanceOfInstr(call->token_pos(),
|
| - left_val,
|
| - instantiator_val,
|
| - type_args_val,
|
| + new Value(left),
|
| + new Value(instantiator),
|
| + new Value(type_args),
|
| type,
|
| negate);
|
| - call->ReplaceWith(instance_of, current_iterator());
|
| - RemovePushArguments(call);
|
| + ReplaceCall(call, instance_of);
|
| }
|
|
|
|
|
| @@ -1655,7 +1597,6 @@ void FlowGraphOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) {
|
| // (e.g, binary op, field load, ..).
|
| void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
|
| if (!instr->HasICData() || (instr->ic_data()->NumberOfChecks() == 0)) {
|
| - // An instance call without ICData will trigger deoptimization.
|
| return;
|
| }
|
|
|
| @@ -1723,7 +1664,7 @@ void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
|
| bool call_with_checks;
|
| if (has_one_target) {
|
| // Type propagation has not run yet, we cannot eliminate the check.
|
| - AddCheckClass(instr, instr->ArgumentAt(0)->value()->Copy());
|
| + AddReceiverCheck(instr);
|
| // Call can still deoptimize, do not detach environment from instr.
|
| call_with_checks = false;
|
| } else {
|
| @@ -1741,9 +1682,9 @@ void FlowGraphOptimizer::VisitStaticCall(StaticCallInstr* call) {
|
| MethodRecognizer::Kind recognized_kind =
|
| MethodRecognizer::RecognizeKind(call->function());
|
| if (recognized_kind == MethodRecognizer::kMathSqrt) {
|
| - MathSqrtInstr* sqrt = new MathSqrtInstr(call->ArgumentAt(0)->value(), call);
|
| - call->ReplaceWith(sqrt, current_iterator());
|
| - RemovePushArguments(call);
|
| + MathSqrtInstr* sqrt =
|
| + new MathSqrtInstr(new Value(call->ArgumentAt(0)), call);
|
| + ReplaceCall(call, sqrt);
|
| }
|
| }
|
|
|
| @@ -1781,51 +1722,50 @@ bool FlowGraphOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr,
|
| ASSERT(!field.IsNull());
|
|
|
| if (InstanceCallNeedsClassCheck(instr)) {
|
| - AddCheckClass(instr, instr->ArgumentAt(0)->value()->Copy());
|
| + AddReceiverCheck(instr);
|
| }
|
| bool needs_store_barrier = true;
|
| if (ArgIsAlwaysSmi(*instr->ic_data(), 1)) {
|
| InsertBefore(instr,
|
| - new CheckSmiInstr(instr->ArgumentAt(1)->value()->Copy(),
|
| + new CheckSmiInstr(new Value(instr->ArgumentAt(1)),
|
| instr->deopt_id()),
|
| instr->env(),
|
| Definition::kEffect);
|
| needs_store_barrier = false;
|
| }
|
| - // Detach environment from the original instruction because it can't
|
| - // deoptimize.
|
| - instr->set_env(NULL);
|
| StoreInstanceFieldInstr* store = new StoreInstanceFieldInstr(
|
| field,
|
| - instr->ArgumentAt(0)->value(),
|
| - instr->ArgumentAt(1)->value(),
|
| + new Value(instr->ArgumentAt(0)),
|
| + new Value(instr->ArgumentAt(1)),
|
| needs_store_barrier);
|
| - instr->ReplaceWith(store, current_iterator());
|
| - RemovePushArguments(instr);
|
| + // Detach environment from the original instruction because it can't
|
| + // deoptimize.
|
| + for (Environment::DeepIterator it(instr->env()); !it.Done(); it.Advance()) {
|
| + it.CurrentValue()->RemoveFromUseList();
|
| + }
|
| + instr->set_env(NULL);
|
| + ReplaceCall(instr, store);
|
| return true;
|
| }
|
|
|
|
|
| -static void HandleRelationalOp(FlowGraphOptimizer* optimizer,
|
| - RelationalOpInstr* comp,
|
| - Instruction* instr) {
|
| +void FlowGraphOptimizer::HandleRelationalOp(RelationalOpInstr* comp) {
|
| if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) {
|
| return;
|
| }
|
| const ICData& ic_data = *comp->ic_data();
|
| + Instruction* instr = current_iterator()->Current();
|
| if (ic_data.NumberOfChecks() == 1) {
|
| ASSERT(ic_data.HasOneTarget());
|
| if (HasOnlyTwoSmis(ic_data)) {
|
| - optimizer->InsertBefore(
|
| - instr,
|
| - new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()),
|
| - instr->env(),
|
| - Definition::kEffect);
|
| - optimizer->InsertBefore(
|
| - instr,
|
| - new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()),
|
| - instr->env(),
|
| - Definition::kEffect);
|
| + InsertBefore(instr,
|
| + new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()),
|
| + instr->env(),
|
| + Definition::kEffect);
|
| + InsertBefore(instr,
|
| + new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()),
|
| + instr->env(),
|
| + Definition::kEffect);
|
| comp->set_operands_class_id(kSmiCid);
|
| } else if (ShouldSpecializeForDouble(ic_data)) {
|
| comp->set_operands_class_id(kDoubleCid);
|
| @@ -1843,23 +1783,23 @@ static void HandleRelationalOp(FlowGraphOptimizer* optimizer,
|
|
|
|
|
| void FlowGraphOptimizer::VisitRelationalOp(RelationalOpInstr* instr) {
|
| - HandleRelationalOp(this, instr, instr);
|
| + HandleRelationalOp(instr);
|
| }
|
|
|
|
|
| template <typename T>
|
| -static void HandleEqualityCompare(FlowGraphOptimizer* optimizer,
|
| - EqualityCompareInstr* comp,
|
| - T instr,
|
| - ForwardInstructionIterator* iterator) {
|
| +void FlowGraphOptimizer::HandleEqualityCompare(EqualityCompareInstr* comp,
|
| + T current_instruction) {
|
| // If one of the inputs is null, no ICdata will be collected.
|
| if (comp->left()->BindsToConstantNull() ||
|
| comp->right()->BindsToConstantNull()) {
|
| Token::Kind strict_kind = (comp->kind() == Token::kEQ) ?
|
| Token::kEQ_STRICT : Token::kNE_STRICT;
|
| StrictCompareInstr* strict_comp =
|
| - new StrictCompareInstr(strict_kind, comp->left(), comp->right());
|
| - instr->ReplaceWith(strict_comp, iterator);
|
| + new StrictCompareInstr(strict_kind,
|
| + comp->left()->Copy(),
|
| + comp->right()->Copy());
|
| + current_instruction->ReplaceWith(strict_comp, current_iterator());
|
| return;
|
| }
|
| if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) {
|
| @@ -1873,16 +1813,14 @@ static void HandleEqualityCompare(FlowGraphOptimizer* optimizer,
|
| // TODO(srdjan): allow for mixed mode int/double comparison.
|
|
|
| if ((class_ids[0] == kSmiCid) && (class_ids[1] == kSmiCid)) {
|
| - optimizer->InsertBefore(
|
| - instr,
|
| - new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()),
|
| - instr->env(),
|
| - Definition::kEffect);
|
| - optimizer->InsertBefore(
|
| - instr,
|
| - new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()),
|
| - instr->env(),
|
| - Definition::kEffect);
|
| + InsertBefore(current_instruction,
|
| + new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()),
|
| + current_instruction->env(),
|
| + Definition::kEffect);
|
| + InsertBefore(current_instruction,
|
| + new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()),
|
| + current_instruction->env(),
|
| + Definition::kEffect);
|
| comp->set_receiver_class_id(kSmiCid);
|
| } else if ((class_ids[0] == kDoubleCid) && (class_ids[1] == kDoubleCid)) {
|
| comp->set_receiver_class_id(kDoubleCid);
|
| @@ -1909,63 +1847,40 @@ static void HandleEqualityCompare(FlowGraphOptimizer* optimizer,
|
| GrowableArray<intptr_t> smi_or_null(2);
|
| smi_or_null.Add(kSmiCid);
|
| smi_or_null.Add(kNullCid);
|
| - if (ICDataHasOnlyReceiverArgumentClassIds(
|
| - *comp->ic_data(), smi_or_null, smi_or_null)) {
|
| + if (ICDataHasOnlyReceiverArgumentClassIds(*comp->ic_data(),
|
| + smi_or_null,
|
| + smi_or_null)) {
|
| const ICData& unary_checks_0 =
|
| ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks());
|
| - const intptr_t deopt_id = comp->deopt_id();
|
| - if ((unary_checks_0.NumberOfChecks() == 1) &&
|
| - (unary_checks_0.GetReceiverClassIdAt(0) == kSmiCid)) {
|
| - // Smi only.
|
| - optimizer->InsertBefore(
|
| - instr,
|
| - new CheckSmiInstr(comp->left()->Copy(), deopt_id),
|
| - instr->env(),
|
| - Definition::kEffect);
|
| - } else {
|
| - // Smi or NULL.
|
| - optimizer->InsertBefore(
|
| - instr,
|
| - new CheckClassInstr(comp->left()->Copy(), deopt_id, unary_checks_0),
|
| - instr->env(),
|
| - Definition::kEffect);
|
| - }
|
| + AddCheckClass(comp->left()->definition(),
|
| + unary_checks_0,
|
| + comp->deopt_id(),
|
| + current_instruction->env(),
|
| + current_instruction);
|
|
|
| const ICData& unary_checks_1 =
|
| ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecksForArgNr(1));
|
| - if ((unary_checks_1.NumberOfChecks() == 1) &&
|
| - (unary_checks_1.GetReceiverClassIdAt(0) == kSmiCid)) {
|
| - // Smi only.
|
| - optimizer->InsertBefore(
|
| - instr,
|
| - new CheckSmiInstr(comp->right()->Copy(), deopt_id),
|
| - instr->env(),
|
| - Definition::kEffect);
|
| - } else {
|
| - // Smi or NULL.
|
| - optimizer->InsertBefore(
|
| - instr,
|
| - new CheckClassInstr(comp->right()->Copy(), deopt_id, unary_checks_1),
|
| - instr->env(),
|
| - Definition::kEffect);
|
| - }
|
| + AddCheckClass(comp->right()->definition(),
|
| + unary_checks_1,
|
| + comp->deopt_id(),
|
| + current_instruction->env(),
|
| + current_instruction);
|
| comp->set_receiver_class_id(kSmiCid);
|
| }
|
| }
|
|
|
|
|
| void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareInstr* instr) {
|
| - HandleEqualityCompare(this, instr, instr, current_iterator());
|
| + HandleEqualityCompare(instr, instr);
|
| }
|
|
|
|
|
| void FlowGraphOptimizer::VisitBranch(BranchInstr* instr) {
|
| ComparisonInstr* comparison = instr->comparison();
|
| if (comparison->IsRelationalOp()) {
|
| - HandleRelationalOp(this, comparison->AsRelationalOp(), instr);
|
| + HandleRelationalOp(comparison->AsRelationalOp());
|
| } else if (comparison->IsEqualityCompare()) {
|
| - HandleEqualityCompare(this, comparison->AsEqualityCompare(), instr,
|
| - current_iterator());
|
| + HandleEqualityCompare(comparison->AsEqualityCompare(), instr);
|
| } else {
|
| ASSERT(comparison->IsStrictCompare());
|
| // Nothing to do.
|
| @@ -2252,15 +2167,11 @@ ConstraintInstr* RangeAnalysis::InsertConstraintFor(Definition* defn,
|
| // No need to constrain constants.
|
| if (defn->IsConstant()) return NULL;
|
|
|
| - Value* value = new Value(defn);
|
| - ConstraintInstr* constraint = new ConstraintInstr(value, constraint_range);
|
| - constraint->InsertAfter(after);
|
| - constraint->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index());
|
| - RenameDominatedUses(defn, after, constraint);
|
| + ConstraintInstr* constraint =
|
| + new ConstraintInstr(new Value(defn), constraint_range);
|
| + flow_graph_->InsertAfter(after, constraint, NULL, Definition::kValue);
|
| + RenameDominatedUses(defn, constraint, constraint);
|
| constraints_.Add(constraint);
|
| - value->set_instruction(constraint);
|
| - value->set_use_index(0);
|
| - defn->AddInputUse(value);
|
| return constraint;
|
| }
|
|
|
| @@ -4219,7 +4130,7 @@ void ConstantPropagator::Transform() {
|
| defn->ssa_temp_index(),
|
| defn->constant_value().ToCString());
|
| }
|
| - i.ReplaceCurrentWith(new ConstantInstr(defn->constant_value()));
|
| + defn->ReplaceWith(new ConstantInstr(defn->constant_value()), &i);
|
| }
|
| }
|
|
|
|
|