| // 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, ?> builder) { | |
| builder.addDebugLocalWrite(src()); | |
| } | |
| } |