| // Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| package com.android.tools.r8.ir.code; |
| |
| import com.android.tools.r8.cf.LoadStoreHelper; |
| import com.android.tools.r8.cf.TypeVerificationHelper; |
| import com.android.tools.r8.cf.code.CfStore; |
| import com.android.tools.r8.graph.AppView; |
| import com.android.tools.r8.graph.DexType; |
| import com.android.tools.r8.ir.analysis.VerifyTypesHelper; |
| import com.android.tools.r8.ir.conversion.CfBuilder; |
| import com.android.tools.r8.lightir.LirBuilder; |
| |
| /** |
| * Instruction introducing an SSA value with attached local information. |
| * |
| * <p>All instructions may have attached local information (defined as the local information of |
| * their outgoing value). This instruction is needed to mark a transition of an existing value (with |
| * a possible local attached) to a new value that has a local (possibly the same one). Even if the |
| * debug info of the ingoing value is equal to that of the outgoing value, the write may still be |
| * needed since an explicit end may have ended the visibility range of the local which now becomes |
| * visible again. |
| * |
| * <p>For valid debug info, this instruction should have at least one debug user, denoting the end |
| * of its range, and thus it should be live. |
| */ |
| public class DebugLocalWrite extends Move { |
| |
| public DebugLocalWrite(Value dest, Value src) { |
| super(dest, src); |
| assert dest.hasLocalInfo(); |
| } |
| |
| @Override |
| public <T> T accept(InstructionVisitor<T> visitor) { |
| return visitor.visit(this); |
| } |
| |
| @Override |
| public boolean isDebugLocalWrite() { |
| return true; |
| } |
| |
| @Override |
| public DebugLocalWrite asDebugLocalWrite() { |
| return this; |
| } |
| |
| @Override |
| public boolean isOutConstant() { |
| return false; |
| } |
| |
| @Override |
| public boolean identicalNonValueNonPositionParts(Instruction other) { |
| return other.isDebugLocalWrite(); |
| } |
| |
| @Override |
| public DexType computeVerificationType(AppView<?> appView, TypeVerificationHelper helper) { |
| return helper.getDexType(src()); |
| } |
| |
| @Override |
| public void insertLoadAndStores(InstructionListIterator it, LoadStoreHelper helper) { |
| helper.loadInValues(this, it); |
| // A local-write does not have an outgoing stack value, but in writes directly to the local. |
| assert !instructionTypeCanThrow(); |
| if (getBlock().hasCatchHandlers()) { |
| helper.splitAfterStoredOutValue(it); |
| } |
| } |
| |
| @Override |
| public void buildCf(CfBuilder builder) { |
| builder.add(new CfStore(outType(), builder.getLocalRegister(outValue())), this); |
| } |
| |
| @Override |
| public boolean isAllowedAfterThrowingInstruction() { |
| return true; |
| } |
| |
| @Override |
| public boolean verifyTypes(AppView<?> appView, VerifyTypesHelper verifyTypesHelper) { |
| super.verifyTypes(appView, verifyTypesHelper); |
| assert verifyTypesHelper.isAssignable(src().getType(), getOutType()); |
| return true; |
| } |
| |
| @Override |
| public void buildLir(LirBuilder<Value, BasicBlock> builder) { |
| builder.addDebugLocalWrite(src()); |
| } |
| } |