blob: 8853e8bbbf1067f9b46410cda0a7ca524129e0d3 [file] [log] [blame]
// Copyright (c) 2021, 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.desugar.constantdynamic;
import com.android.tools.r8.cf.code.CfConstDynamic;
import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringCollection;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.FreshLocalProvider;
import com.android.tools.r8.ir.desugar.LocalStackAllocator;
import com.android.tools.r8.utils.Box;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class ConstantDynamicInstructionDesugaring implements CfInstructionDesugaring {
private final AppView<?> appView;
private final Map<DexType, Map<ConstantDynamicReference, ConstantDynamicClass>>
dynamicConstantSyntheticsPerClass = new ConcurrentHashMap<>();
public ConstantDynamicInstructionDesugaring(AppView<?> appView) {
this.appView = appView;
}
@Override
public boolean needsDesugaring(CfInstruction instruction, ProgramMethod context) {
return instruction.isConstDynamic();
}
@Override
public Collection<CfInstruction> desugarInstruction(
CfInstruction instruction,
FreshLocalProvider freshLocalProvider,
LocalStackAllocator localStackAllocator,
CfInstructionDesugaringEventConsumer eventConsumer,
ProgramMethod context,
MethodProcessingContext methodProcessingContext,
CfInstructionDesugaringCollection desugaringCollection,
DexItemFactory dexItemFactory) {
if (instruction.isConstDynamic()) {
return desugarConstDynamicInstruction(
instruction.asConstDynamic(),
freshLocalProvider,
localStackAllocator,
eventConsumer,
context,
methodProcessingContext);
}
return null;
}
private Collection<CfInstruction> desugarConstDynamicInstruction(
CfConstDynamic invoke,
FreshLocalProvider freshLocalProvider,
LocalStackAllocator localStackAllocator,
ConstantDynamicDesugaringEventConsumer eventConsumer,
ProgramMethod context,
MethodProcessingContext methodProcessingContext) {
ConstantDynamicClass constantDynamicClass =
ensureConstantDynamicClass(invoke, context, methodProcessingContext, eventConsumer);
return constantDynamicClass.desugarConstDynamicInstruction(
invoke,
freshLocalProvider,
localStackAllocator,
eventConsumer,
context,
methodProcessingContext);
}
// Creates a class corresponding to the constant dynamic symbolic reference and context.
// TODO(b/178172809): Move this ensure handling to the synthetic items handling and move to
// one class for dynamic constants for each class using dynamic constants.
private ConstantDynamicClass ensureConstantDynamicClass(
CfConstDynamic constantDynamic,
ProgramMethod context,
MethodProcessingContext methodProcessingContext,
ConstantDynamicDesugaringEventConsumer eventConsumer) {
Map<ConstantDynamicReference, ConstantDynamicClass> dynamicConstantSyntheticsForClass =
dynamicConstantSyntheticsPerClass.computeIfAbsent(
context.getHolderType(), (ignore) -> new HashMap<>());
ConstantDynamicClass result =
dynamicConstantSyntheticsForClass.get(constantDynamic.getReference());
if (result == null) {
synchronized (dynamicConstantSyntheticsForClass) {
result = dynamicConstantSyntheticsForClass.get(constantDynamic.getReference());
if (result == null) {
result =
createConstantDynamicClass(
constantDynamic, context, methodProcessingContext, eventConsumer);
dynamicConstantSyntheticsForClass.put(constantDynamic.getReference(), result);
}
}
}
return result;
}
// TODO(b/178172809): Change to use ensureFixedClass.
private ConstantDynamicClass createConstantDynamicClass(
CfConstDynamic constantDynamic,
ProgramMethod context,
MethodProcessingContext methodProcessingContext,
ConstantDynamicDesugaringEventConsumer eventConsumer) {
Box<ConstantDynamicClass> box = new Box<>();
DexProgramClass clazz =
appView
.getSyntheticItems()
.createClass(
kinds -> kinds.CONST_DYNAMIC,
methodProcessingContext.createUniqueContext(),
appView,
builder ->
box.set(
new ConstantDynamicClass(
builder, appView, this, context, constantDynamic)));
// Immediately set the actual program class on the constant dynamic.
ConstantDynamicClass constantDynamicClass = box.get();
constantDynamicClass.setClass(clazz);
eventConsumer.acceptConstantDynamicClass(constantDynamicClass, context);
return constantDynamicClass;
}
}