| Index: runtime/vm/flow_graph_compiler_dbc.cc
|
| diff --git a/runtime/vm/flow_graph_compiler_dbc.cc b/runtime/vm/flow_graph_compiler_dbc.cc
|
| index 92ba799b2a277e1b4d20667c0e2e711498c03315..86352cc491b03df24cef4cc6c6dc978111bb8f21 100644
|
| --- a/runtime/vm/flow_graph_compiler_dbc.cc
|
| +++ b/runtime/vm/flow_graph_compiler_dbc.cc
|
| @@ -90,8 +90,120 @@ void FlowGraphCompiler::ExitIntrinsicMode() {
|
| RawTypedData* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
|
| DeoptInfoBuilder* builder,
|
| const Array& deopt_table) {
|
| - UNIMPLEMENTED();
|
| - return TypedData::null();
|
| + if (deopt_env_ == NULL) {
|
| + ++builder->current_info_number_;
|
| + return TypedData::null();
|
| + }
|
| +
|
| + intptr_t stack_height = compiler->StackSize();
|
| + AllocateIncomingParametersRecursive(deopt_env_, &stack_height);
|
| +
|
| + intptr_t slot_ix = 0;
|
| + Environment* current = deopt_env_;
|
| +
|
| + // Emit all kMaterializeObject instructions describing objects to be
|
| + // materialized on the deoptimization as a prefix to the deoptimization info.
|
| + EmitMaterializations(deopt_env_, builder);
|
| +
|
| + // The real frame starts here.
|
| + builder->MarkFrameStart();
|
| +
|
| + Zone* zone = compiler->zone();
|
| +
|
| + builder->AddCallerFp(slot_ix++);
|
| + builder->AddReturnAddress(current->function(), deopt_id(), slot_ix++);
|
| + builder->AddPcMarker(Function::ZoneHandle(zone), slot_ix++);
|
| + builder->AddConstant(Function::ZoneHandle(zone), slot_ix++);
|
| +
|
| + // Emit all values that are needed for materialization as a part of the
|
| + // expression stack for the bottom-most frame. This guarantees that GC
|
| + // will be able to find them during materialization.
|
| + slot_ix = builder->EmitMaterializationArguments(slot_ix);
|
| +
|
| + // For the innermost environment, set outgoing arguments and the locals.
|
| + for (intptr_t i = current->Length() - 1;
|
| + i >= current->fixed_parameter_count();
|
| + i--) {
|
| + builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++);
|
| + }
|
| +
|
| + builder->AddCallerFp(slot_ix++);
|
| +
|
| + Environment* previous = current;
|
| + current = current->outer();
|
| + while (current != NULL) {
|
| + // For any outer environment the deopt id is that of the call instruction
|
| + // which is recorded in the outer environment.
|
| + builder->AddReturnAddress(
|
| + current->function(),
|
| + Thread::ToDeoptAfter(current->deopt_id()),
|
| + slot_ix++);
|
| +
|
| + builder->AddPcMarker(previous->function(), slot_ix++);
|
| + builder->AddConstant(previous->function(), slot_ix++);
|
| +
|
| + // The values of outgoing arguments can be changed from the inlined call so
|
| + // we must read them from the previous environment.
|
| + for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) {
|
| + builder->AddCopy(previous->ValueAt(i),
|
| + previous->LocationAt(i),
|
| + slot_ix++);
|
| + }
|
| +
|
| + // Set the locals, note that outgoing arguments are not in the environment.
|
| + for (intptr_t i = current->Length() - 1;
|
| + i >= current->fixed_parameter_count();
|
| + i--) {
|
| + builder->AddCopy(current->ValueAt(i),
|
| + current->LocationAt(i),
|
| + slot_ix++);
|
| + }
|
| +
|
| + builder->AddCallerFp(slot_ix++);
|
| +
|
| + // Iterate on the outer environment.
|
| + previous = current;
|
| + current = current->outer();
|
| + }
|
| + // The previous pointer is now the outermost environment.
|
| + ASSERT(previous != NULL);
|
| +
|
| + // For the outermost environment, set caller PC.
|
| + builder->AddCallerPc(slot_ix++);
|
| +
|
| + builder->AddPcMarker(previous->function(), slot_ix++);
|
| + builder->AddConstant(previous->function(), slot_ix++);
|
| +
|
| +
|
| + // For the outermost environment, set the incoming arguments.
|
| + for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) {
|
| + builder->AddCopy(previous->ValueAt(i), previous->LocationAt(i), slot_ix++);
|
| + }
|
| +
|
| + return builder->CreateDeoptInfo(deopt_table);
|
| +}
|
| +
|
| +
|
| +void FlowGraphCompiler::RecordAfterCall(Instruction* instr) {
|
| + RecordSafepoint(instr->locs());
|
| + // Marks either the continuation point in unoptimized code or the
|
| + // deoptimization point in optimized code, after call.
|
| + const intptr_t deopt_id_after = Thread::ToDeoptAfter(instr->deopt_id());
|
| + if (is_optimizing()) {
|
| + // Return/ReturnTOS instruction drops incoming arguments so
|
| + // we have to drop outgoing arguments from the innermost environment.
|
| + // On all other architectures caller drops outgoing arguments itself
|
| + // hence the difference.
|
| + pending_deoptimization_env_->DropArguments(instr->ArgumentCount());
|
| + AddDeoptIndexAtCall(deopt_id_after, instr->token_pos());
|
| + } else {
|
| + // Add deoptimization continuation point after the call and before the
|
| + // arguments are removed.
|
| + // In optimized code this descriptor is needed for exception handling.
|
| + AddCurrentDescriptor(RawPcDescriptors::kDeopt,
|
| + deopt_id_after,
|
| + instr->token_pos());
|
| + }
|
| }
|
|
|
|
|
| @@ -109,16 +221,28 @@ void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos,
|
| const AbstractType& dst_type,
|
| const String& dst_name,
|
| LocationSummary* locs) {
|
| - ASSERT(!is_optimizing());
|
| SubtypeTestCache& test_cache = SubtypeTestCache::Handle();
|
| if (!dst_type.IsVoidType() && dst_type.IsInstantiated()) {
|
| test_cache = SubtypeTestCache::New();
|
| }
|
|
|
| + if (is_optimizing()) {
|
| + __ Push(locs->in(0).reg());
|
| + __ Push(locs->in(1).reg());
|
| + }
|
| __ PushConstant(dst_type);
|
| __ PushConstant(dst_name);
|
| __ AssertAssignable(__ AddConstant(test_cache));
|
| + RecordSafepoint(locs);
|
| AddCurrentDescriptor(RawPcDescriptors::kOther, deopt_id, token_pos);
|
| + if (is_optimizing()) {
|
| + // Assert assignable keeps the instance on the stack as the result,
|
| + // all other arguments are popped.
|
| + // In optimized code we need to drop it because optimized code
|
| + // expects the result in the register and it is already there
|
| + // because locs()->in(0).reg() == locs()->out(0).reg().
|
| + __ Drop1();
|
| + }
|
| }
|
|
|
|
|
| @@ -168,10 +292,21 @@ void FlowGraphCompiler::EmitFrameEntry() {
|
| const intptr_t context_index =
|
| -parsed_function().current_context_var()->index() - 1;
|
|
|
| + if (CanOptimizeFunction() &&
|
| + function.IsOptimizable() &&
|
| + (!is_optimizing() || may_reoptimize())) {
|
| + __ HotCheck(!is_optimizing(), GetOptimizationThreshold());
|
| + }
|
| +
|
| if (has_optional_params) {
|
| - __ EntryOpt(num_fixed_params, num_opt_pos_params, num_opt_named_params);
|
| - } else {
|
| + __ EntryOptional(num_fixed_params,
|
| + num_opt_pos_params,
|
| + num_opt_named_params);
|
| + } else if (!is_optimizing()) {
|
| __ Entry(num_fixed_params, num_locals, context_index);
|
| + } else {
|
| + __ EntryOptimized(num_fixed_params,
|
| + flow_graph_.graph_entry()->spill_slot_count());
|
| }
|
|
|
| if (num_opt_named_params != 0) {
|
| @@ -212,14 +347,20 @@ void FlowGraphCompiler::EmitFrameEntry() {
|
| }
|
|
|
|
|
| - ASSERT(num_locals > 0); // There is always at least context_var.
|
| if (has_optional_params) {
|
| - ASSERT(!is_optimizing());
|
| - __ Frame(num_locals); // Reserve space for locals.
|
| + if (!is_optimizing()) {
|
| + ASSERT(num_locals > 0); // There is always at least context_var.
|
| + __ Frame(num_locals); // Reserve space for locals.
|
| + } else if (flow_graph_.graph_entry()->spill_slot_count() >
|
| + flow_graph_.num_copied_params()) {
|
| + __ Frame(flow_graph_.graph_entry()->spill_slot_count() -
|
| + flow_graph_.num_copied_params());
|
| + }
|
| }
|
|
|
| if (function.IsClosureFunction()) {
|
| - Register reg = context_index;
|
| + Register reg = is_optimizing() ? flow_graph_.num_copied_params()
|
| + : context_index;
|
| Register closure_reg = reg;
|
| LocalScope* scope = parsed_function().node_sequence()->scope();
|
| LocalVariable* local = scope->VariableAt(0);
|
| @@ -229,7 +370,7 @@ void FlowGraphCompiler::EmitFrameEntry() {
|
| closure_reg = -local->index() - 1;
|
| }
|
| __ LoadField(reg, closure_reg, Closure::context_offset() / kWordSize);
|
| - } else if (has_optional_params) {
|
| + } else if (has_optional_params && !is_optimizing()) {
|
| __ LoadConstant(context_index,
|
| Object::Handle(isolate()->object_store()->empty_context()));
|
| }
|
| @@ -254,12 +395,48 @@ void FlowGraphCompiler::CompileGraph() {
|
|
|
|
|
| void ParallelMoveResolver::EmitMove(int index) {
|
| - UNIMPLEMENTED();
|
| + MoveOperands* move = moves_[index];
|
| + const Location source = move->src();
|
| + const Location destination = move->dest();
|
| + if (source.IsStackSlot() && destination.IsRegister()) {
|
| + // Only allow access to the arguments.
|
| + ASSERT(source.base_reg() == FPREG);
|
| + ASSERT(source.stack_index() < 0);
|
| + __ Move(destination.reg(), -kParamEndSlotFromFp + source.stack_index());
|
| + } else if (source.IsRegister() && destination.IsRegister()) {
|
| + __ Move(destination.reg(), source.reg());
|
| + } else if (source.IsConstant() && destination.IsRegister()) {
|
| + __ LoadConstant(destination.reg(), source.constant());
|
| + } else {
|
| + compiler_->Bailout("Unsupported move");
|
| + }
|
| +
|
| + move->Eliminate();
|
| }
|
|
|
|
|
| void ParallelMoveResolver::EmitSwap(int index) {
|
| - UNIMPLEMENTED();
|
| + MoveOperands* move = moves_[index];
|
| + const Location source = move->src();
|
| + const Location destination = move->dest();
|
| + ASSERT(source.IsRegister() && destination.IsRegister());
|
| + __ Swap(destination.reg(), source.reg());
|
| +
|
| + // The swap of source and destination has executed a move from source to
|
| + // destination.
|
| + move->Eliminate();
|
| +
|
| + // Any unperformed (including pending) move with a source of either
|
| + // this move's source or destination needs to have their source
|
| + // changed to reflect the state of affairs after the swap.
|
| + for (int i = 0; i < moves_.length(); ++i) {
|
| + const MoveOperands& other_move = *moves_[i];
|
| + if (other_move.Blocks(source)) {
|
| + moves_[i]->set_src(destination);
|
| + } else if (other_move.Blocks(destination)) {
|
| + moves_[i]->set_src(source);
|
| + }
|
| + }
|
| }
|
|
|
|
|
|
|