| Index: runtime/vm/flow_graph_inliner.cc
|
| diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
|
| index 9a68b00919ec0323c4c90f7b7e165b9fe890ea2d..1601565197a82c56f0e799e6b9edc79f7e9a5056 100644
|
| --- a/runtime/vm/flow_graph_inliner.cc
|
| +++ b/runtime/vm/flow_graph_inliner.cc
|
| @@ -2352,6 +2352,9 @@ static bool InlineDoubleOp(FlowGraph* flow_graph,
|
| Instruction* call,
|
| TargetEntryInstr** entry,
|
| Definition** last) {
|
| + if (!CanUnboxDouble()) {
|
| + return false;
|
| + }
|
| Definition* left = call->ArgumentAt(0);
|
| Definition* right = call->ArgumentAt(1);
|
|
|
| @@ -2421,7 +2424,7 @@ static bool InlineGrowableArraySetter(FlowGraph* flow_graph,
|
| }
|
|
|
|
|
| -static intptr_t PrepareInlineByteArrayBaseOp(
|
| +static void PrepareInlineByteArrayBaseOp(
|
| FlowGraph* flow_graph,
|
| Instruction* call,
|
| intptr_t array_cid,
|
| @@ -2499,7 +2502,6 @@ static intptr_t PrepareInlineByteArrayBaseOp(
|
| FlowGraph::kValue);
|
| *array = elements;
|
| }
|
| - return array_cid;
|
| }
|
|
|
|
|
| @@ -2518,13 +2520,13 @@ static bool InlineByteArrayBaseLoad(FlowGraph* flow_graph,
|
| (*entry)->InheritDeoptTarget(Z, call);
|
| Instruction* cursor = *entry;
|
|
|
| - array_cid = PrepareInlineByteArrayBaseOp(flow_graph,
|
| - call,
|
| - array_cid,
|
| - view_cid,
|
| - &array,
|
| - index,
|
| - &cursor);
|
| + PrepareInlineByteArrayBaseOp(flow_graph,
|
| + call,
|
| + array_cid,
|
| + view_cid,
|
| + &array,
|
| + index,
|
| + &cursor);
|
|
|
| intptr_t deopt_id = Thread::kNoDeoptId;
|
| if ((array_cid == kTypedDataInt32ArrayCid) ||
|
| @@ -2572,13 +2574,13 @@ static bool InlineByteArrayBaseStore(FlowGraph* flow_graph,
|
| (*entry)->InheritDeoptTarget(Z, call);
|
| Instruction* cursor = *entry;
|
|
|
| - array_cid = PrepareInlineByteArrayBaseOp(flow_graph,
|
| - call,
|
| - array_cid,
|
| - view_cid,
|
| - &array,
|
| - index,
|
| - &cursor);
|
| + PrepareInlineByteArrayBaseOp(flow_graph,
|
| + call,
|
| + array_cid,
|
| + view_cid,
|
| + &array,
|
| + index,
|
| + &cursor);
|
|
|
| // Extract the instance call so we can use the function_name in the stored
|
| // value check ICData.
|
| @@ -2874,12 +2876,18 @@ bool FlowGraphInliner::TryReplaceInstanceCallWithInline(
|
| push->RemoveFromGraph();
|
| }
|
| // Replace all uses of this definition with the result.
|
| - call->ReplaceUsesWith(last);
|
| + if (call->HasUses()) {
|
| + call->ReplaceUsesWith(last);
|
| + }
|
| // Finally insert the sequence other definition in place of this one in the
|
| // graph.
|
| - call->previous()->LinkTo(entry->next());
|
| + if (entry->next() != NULL) {
|
| + call->previous()->LinkTo(entry->next());
|
| + }
|
| entry->UnuseAllInputs(); // Entry block is not in the graph.
|
| - last->LinkTo(call);
|
| + if (last != NULL) {
|
| + last->LinkTo(call);
|
| + }
|
| // Remove through the iterator.
|
| ASSERT(iterator->Current() == call);
|
| iterator->RemoveCurrentFromGraph();
|
| @@ -2912,12 +2920,18 @@ bool FlowGraphInliner::TryReplaceStaticCallWithInline(
|
| push->RemoveFromGraph();
|
| }
|
| // Replace all uses of this definition with the result.
|
| - call->ReplaceUsesWith(last);
|
| + if (call->HasUses()) {
|
| + call->ReplaceUsesWith(last);
|
| + }
|
| // Finally insert the sequence other definition in place of this one in the
|
| // graph.
|
| - call->previous()->LinkTo(entry->next());
|
| + if (entry->next() != NULL) {
|
| + call->previous()->LinkTo(entry->next());
|
| + }
|
| entry->UnuseAllInputs(); // Entry block is not in the graph.
|
| - last->LinkTo(call);
|
| + if (last != NULL) {
|
| + last->LinkTo(call);
|
| + }
|
| // Remove through the iterator.
|
| ASSERT(iterator->Current() == call);
|
| iterator->RemoveCurrentFromGraph();
|
| @@ -3327,10 +3341,51 @@ static bool InlineSimdConstructor(FlowGraph* flow_graph,
|
| }
|
|
|
|
|
| +static bool InlineMathCFunction(FlowGraph* flow_graph,
|
| + Instruction* call,
|
| + MethodRecognizer::Kind kind,
|
| + TargetEntryInstr** entry,
|
| + Definition** last) {
|
| + if (!CanUnboxDouble()) {
|
| + return false;
|
| + }
|
| + *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(),
|
| + call->GetBlock()->try_index());
|
| + (*entry)->InheritDeoptTarget(Z, call);
|
| + Instruction* cursor = *entry;
|
| +
|
| + switch (kind) {
|
| + case MethodRecognizer::kMathSqrt: {
|
| + *last = new(Z) MathUnaryInstr(MathUnaryInstr::kSqrt,
|
| + new(Z) Value(call->ArgumentAt(0)),
|
| + call->deopt_id());
|
| + break;
|
| + }
|
| + default: {
|
| + ZoneGrowableArray<Value*>* args =
|
| + new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount());
|
| + for (intptr_t i = 0; i < call->ArgumentCount(); i++) {
|
| + args->Add(new(Z) Value(call->ArgumentAt(i)));
|
| + }
|
| + *last = new(Z) InvokeMathCFunctionInstr(args,
|
| + call->deopt_id(),
|
| + kind,
|
| + call->token_pos());
|
| + break;
|
| + }
|
| + }
|
| + flow_graph->AppendTo(cursor, *last,
|
| + call->deopt_id() != Thread::kNoDeoptId ?
|
| + call->env() : NULL,
|
| + FlowGraph::kValue);
|
| + return true;
|
| +}
|
| +
|
| +
|
| bool FlowGraphInliner::TryInlineRecognizedMethod(FlowGraph* flow_graph,
|
| intptr_t receiver_cid,
|
| const Function& target,
|
| - Instruction* call,
|
| + Definition* call,
|
| Definition* receiver,
|
| TokenPosition token_pos,
|
| const ICData& ic_data,
|
| @@ -3653,6 +3708,75 @@ bool FlowGraphInliner::TryInlineRecognizedMethod(FlowGraph* flow_graph,
|
| case MethodRecognizer::kInt32x4FromFloat32x4Bits:
|
| return InlineSimdConstructor(flow_graph, call, kind, entry, last);
|
|
|
| + case MethodRecognizer::kMathSqrt:
|
| + case MethodRecognizer::kMathDoublePow:
|
| + case MethodRecognizer::kMathSin:
|
| + case MethodRecognizer::kMathCos:
|
| + case MethodRecognizer::kMathTan:
|
| + case MethodRecognizer::kMathAsin:
|
| + case MethodRecognizer::kMathAcos:
|
| + case MethodRecognizer::kMathAtan:
|
| + case MethodRecognizer::kMathAtan2:
|
| + return InlineMathCFunction(flow_graph, call, kind, entry, last);
|
| +
|
| + case MethodRecognizer::kObjectConstructor: {
|
| + *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(),
|
| + call->GetBlock()->try_index());
|
| + (*entry)->InheritDeoptTarget(Z, call);
|
| + ASSERT(!call->HasUses());
|
| + *last = NULL; // Empty body.
|
| + return true;
|
| + }
|
| +
|
| + case MethodRecognizer::kObjectArrayAllocate: {
|
| + Value* num_elements = new(Z) Value(call->ArgumentAt(1));
|
| + if (num_elements->BindsToConstant() &&
|
| + num_elements->BoundConstant().IsSmi()) {
|
| + intptr_t length =
|
| + Smi::Cast(num_elements->BoundConstant()).Value();
|
| + if (length >= 0 && length <= Array::kMaxElements) {
|
| + Value* type = new(Z) Value(call->ArgumentAt(0));
|
| + *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(),
|
| + call->GetBlock()->try_index());
|
| + (*entry)->InheritDeoptTarget(Z, call);
|
| + *last =
|
| + new(Z) CreateArrayInstr(call->token_pos(), type, num_elements);
|
| + flow_graph->AppendTo(*entry, *last,
|
| + call->deopt_id() != Thread::kNoDeoptId ?
|
| + call->env() : NULL,
|
| + FlowGraph::kValue);
|
| + return true;
|
| + }
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + case MethodRecognizer::kOneByteStringSetAt: {
|
| + // This is an internal method, no need to check argument types nor
|
| + // range.
|
| + *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(),
|
| + call->GetBlock()->try_index());
|
| + (*entry)->InheritDeoptTarget(Z, call);
|
| + Definition* str = call->ArgumentAt(0);
|
| + Definition* index = call->ArgumentAt(1);
|
| + Definition* value = call->ArgumentAt(2);
|
| + *last = new(Z) StoreIndexedInstr(
|
| + new(Z) Value(str),
|
| + new(Z) Value(index),
|
| + new(Z) Value(value),
|
| + kNoStoreBarrier,
|
| + 1, // Index scale
|
| + kOneByteStringCid,
|
| + call->deopt_id(),
|
| + call->token_pos());
|
| + flow_graph->AppendTo(*entry,
|
| + *last,
|
| + call->deopt_id() != Thread::kNoDeoptId ?
|
| + call->env() : NULL,
|
| + FlowGraph::kEffect);
|
| + return true;
|
| + }
|
| +
|
| default:
|
| return false;
|
| }
|
|
|