Optimize PropertyMetadataImpl instance creation
Create all property metadatas in <clinit> and save them to a static array $propertyMetadata. Getter/setter of each delegated property will then just obtain the corresponding instance from that array #KT-4232 Fixed
This commit is contained in:
@@ -93,7 +93,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
private final Type returnType;
|
||||
|
||||
private final BindingContext bindingContext;
|
||||
final MethodContext context;
|
||||
private final MethodContext context;
|
||||
private final CodegenStatementVisitor statementVisitor;
|
||||
|
||||
private final Stack<BlockStackElement> blockStackElements = new Stack<BlockStackElement>();
|
||||
@@ -105,8 +105,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
* When we create a temporary variable to hold some value not to compute it many times
|
||||
* we put it into this map to emit access to that variable instead of evaluating the whole expression
|
||||
*/
|
||||
private final Map<JetElement, StackValue.Local> tempVariables = Maps.newHashMap();
|
||||
@NotNull
|
||||
final Map<JetElement, StackValue> tempVariables = Maps.newHashMap();
|
||||
|
||||
private final TailRecursionCodegen tailRecursionCodegen;
|
||||
|
||||
public final CallGenerator defaultCallGenerator;
|
||||
|
||||
@@ -442,6 +442,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
|
||||
@Override
|
||||
protected void generateSyntheticParts() {
|
||||
generateDelegatedPropertyMetadataArray();
|
||||
|
||||
generateFieldForSingleton();
|
||||
|
||||
generateClassObjectBackingFieldCopies();
|
||||
@@ -474,6 +476,12 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
genClosureFields(context.closure, v, state.getTypeMapper());
|
||||
}
|
||||
|
||||
private void generateDelegatedPropertyMetadataArray() {
|
||||
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
|
||||
generatePropertyMetadataArrayFieldIfNeeded(classAsmType, myClass);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isGenericToArrayPresent() {
|
||||
Collection<FunctionDescriptor> functions = descriptor.getDefaultType().getMemberScope().getFunctions(Name.identifier("toArray"));
|
||||
for (FunctionDescriptor function : functions) {
|
||||
|
||||
@@ -31,7 +31,9 @@ import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.jet.lang.resolve.name.SpecialNames;
|
||||
import org.jetbrains.jet.lang.types.ErrorUtils;
|
||||
@@ -40,15 +42,18 @@ import org.jetbrains.jet.storage.LockBasedStorageManager;
|
||||
import org.jetbrains.jet.storage.NotNullLazyValue;
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.jet.codegen.AsmUtil.boxType;
|
||||
import static org.jetbrains.jet.codegen.AsmUtil.isPrimitive;
|
||||
import static org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED;
|
||||
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
|
||||
import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_STATIC;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.VARIABLE;
|
||||
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.*;
|
||||
import static org.jetbrains.org.objectweb.asm.Opcodes.*;
|
||||
|
||||
public abstract class MemberCodegen extends ParentCodegenAwareImpl {
|
||||
protected final FieldOwnerContext context;
|
||||
@@ -193,7 +198,7 @@ public abstract class MemberCodegen extends ParentCodegenAwareImpl {
|
||||
}
|
||||
|
||||
protected void initializeProperty(@NotNull ExpressionCodegen codegen, @NotNull JetProperty property) {
|
||||
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) bindingContext.get(BindingContext.VARIABLE, property);
|
||||
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) bindingContext.get(VARIABLE, property);
|
||||
assert propertyDescriptor != null;
|
||||
|
||||
JetExpression initializer = property.getDelegateExpressionOrInitializer();
|
||||
@@ -220,7 +225,7 @@ public abstract class MemberCodegen extends ParentCodegenAwareImpl {
|
||||
JetExpression initializer = property.getDelegateExpressionOrInitializer();
|
||||
if (initializer == null) return false;
|
||||
|
||||
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) bindingContext.get(BindingContext.VARIABLE, property);
|
||||
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) bindingContext.get(VARIABLE, property);
|
||||
assert propertyDescriptor != null;
|
||||
|
||||
CompileTimeConstant<?> compileTimeValue = propertyDescriptor.getCompileTimeInitializer();
|
||||
@@ -281,4 +286,38 @@ public abstract class MemberCodegen extends ParentCodegenAwareImpl {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void generatePropertyMetadataArrayFieldIfNeeded(@NotNull Type thisAsmType, @NotNull JetDeclarationContainer container) {
|
||||
List<JetProperty> delegatedProperties = new ArrayList<JetProperty>();
|
||||
for (JetDeclaration declaration : container.getDeclarations()) {
|
||||
if (declaration instanceof JetProperty) {
|
||||
JetProperty property = (JetProperty) declaration;
|
||||
if (property.getDelegate() != null) {
|
||||
delegatedProperties.add(property);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (delegatedProperties.isEmpty()) return;
|
||||
|
||||
v.newField(null, ACC_PRIVATE | ACC_STATIC | ACC_FINAL | ACC_SYNTHETIC, JvmAbi.PROPERTY_METADATA_ARRAY_NAME,
|
||||
"[" + PROPERTY_METADATA_TYPE, null, null);
|
||||
|
||||
InstructionAdapter iv = createOrGetClInitCodegen().v;
|
||||
iv.iconst(delegatedProperties.size());
|
||||
iv.newarray(PROPERTY_METADATA_TYPE);
|
||||
|
||||
for (int i = 0, size = delegatedProperties.size(); i < size; i++) {
|
||||
VariableDescriptor property = BindingContextUtils.getNotNull(bindingContext, VARIABLE, delegatedProperties.get(i));
|
||||
|
||||
iv.dup();
|
||||
iv.iconst(i);
|
||||
iv.anew(PROPERTY_METADATA_IMPL_TYPE);
|
||||
iv.dup();
|
||||
iv.visitLdcInsn(property.getName().asString());
|
||||
iv.invokespecial(PROPERTY_METADATA_IMPL_TYPE.getInternalName(), "<init>", "(Ljava/lang/String;)V");
|
||||
iv.astore(PROPERTY_METADATA_IMPL_TYPE);
|
||||
}
|
||||
|
||||
iv.putstatic(thisAsmType.getInternalName(), JvmAbi.PROPERTY_METADATA_ARRAY_NAME, "[" + PROPERTY_METADATA_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +74,8 @@ public class PackagePartCodegen extends MemberCodegen {
|
||||
}
|
||||
});
|
||||
|
||||
generatePropertyMetadataArrayFieldIfNeeded(packagePartType, jetFile);
|
||||
|
||||
if (clInit != null) {
|
||||
clInit.v.visitInsn(RETURN);
|
||||
FunctionCodegen.endVisit(clInit.v, "static initializer for package", jetFile);
|
||||
|
||||
@@ -18,10 +18,10 @@ package org.jetbrains.jet.codegen;
|
||||
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.codegen.context.FieldOwnerContext;
|
||||
import org.jetbrains.jet.codegen.context.PackageFacadeContext;
|
||||
import org.jetbrains.jet.codegen.context.*;
|
||||
import org.jetbrains.jet.codegen.signature.JvmMethodSignature;
|
||||
import org.jetbrains.jet.codegen.state.GenerationState;
|
||||
import org.jetbrains.jet.codegen.state.GenerationStateAware;
|
||||
@@ -49,6 +49,7 @@ import static org.jetbrains.jet.codegen.CodegenUtil.isInterface;
|
||||
import static org.jetbrains.jet.codegen.JvmSerializationBindings.*;
|
||||
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isTrait;
|
||||
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
|
||||
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.PROPERTY_METADATA_TYPE;
|
||||
import static org.jetbrains.org.objectweb.asm.Opcodes.*;
|
||||
|
||||
public class PropertyCodegen extends GenerationStateAware {
|
||||
@@ -291,8 +292,8 @@ public class PropertyCodegen extends GenerationStateAware {
|
||||
|
||||
FunctionGenerationStrategy strategy;
|
||||
if (isDefaultAccessor) {
|
||||
if (p instanceof JetProperty && ((JetProperty) p).getDelegateExpression() != null) {
|
||||
strategy = new DefaultPropertyWithDelegateAccessorStrategy(state, accessorDescriptor);
|
||||
if (p instanceof JetProperty && ((JetProperty) p).getDelegate() != null) {
|
||||
strategy = new DelegatedPropertyAccessorStrategy(state, accessorDescriptor, indexOfDelegatedProperty((JetProperty) p));
|
||||
}
|
||||
else {
|
||||
strategy = new DefaultPropertyAccessorStrategy(state, accessorDescriptor);
|
||||
@@ -306,6 +307,32 @@ public class PropertyCodegen extends GenerationStateAware {
|
||||
functionCodegen.generateMethod(accessor != null ? accessor : p, signature, accessorDescriptor, strategy);
|
||||
}
|
||||
|
||||
private static int indexOfDelegatedProperty(@NotNull JetProperty property) {
|
||||
PsiElement parent = property.getParent();
|
||||
JetDeclarationContainer container;
|
||||
if (parent instanceof JetClassBody) {
|
||||
container = ((JetClassOrObject) parent.getParent());
|
||||
}
|
||||
else if (parent instanceof JetFile) {
|
||||
container = (JetFile) parent;
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("Unknown delegated property container: " + parent);
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
for (JetDeclaration declaration : container.getDeclarations()) {
|
||||
if (declaration instanceof JetProperty && ((JetProperty) declaration).getDelegate() != null) {
|
||||
if (declaration == property) {
|
||||
return index;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Delegated property not found in its parent: " + JetPsiUtil.getElementTextWithContext(property));
|
||||
}
|
||||
|
||||
|
||||
private static class DefaultPropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased<PropertyAccessorDescriptor> {
|
||||
public DefaultPropertyAccessorStrategy(@NotNull GenerationState state, @NotNull PropertyAccessorDescriptor descriptor) {
|
||||
@@ -318,7 +345,7 @@ public class PropertyCodegen extends GenerationStateAware {
|
||||
PropertyDescriptor propertyDescriptor = callableDescriptor.getCorrespondingProperty();
|
||||
|
||||
int paramCode = 0;
|
||||
if (codegen.context.getContextKind() != OwnerKind.PACKAGE) {
|
||||
if (codegen.getContext().getContextKind() != OwnerKind.PACKAGE) {
|
||||
v.load(0, OBJECT_TYPE);
|
||||
paramCode = 1;
|
||||
}
|
||||
@@ -345,9 +372,12 @@ public class PropertyCodegen extends GenerationStateAware {
|
||||
}
|
||||
}
|
||||
|
||||
private static class DefaultPropertyWithDelegateAccessorStrategy extends FunctionGenerationStrategy.CodegenBased<PropertyAccessorDescriptor> {
|
||||
public DefaultPropertyWithDelegateAccessorStrategy(@NotNull GenerationState state, @NotNull PropertyAccessorDescriptor descriptor) {
|
||||
private static class DelegatedPropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased<PropertyAccessorDescriptor> {
|
||||
private final int index;
|
||||
|
||||
public DelegatedPropertyAccessorStrategy(@NotNull GenerationState state, @NotNull PropertyAccessorDescriptor descriptor, int index) {
|
||||
super(state, descriptor);
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -361,13 +391,35 @@ public class PropertyCodegen extends GenerationStateAware {
|
||||
Call call = bindingContext.get(BindingContext.DELEGATED_PROPERTY_CALL, callableDescriptor);
|
||||
assert call != null : "Call should be recorded for delegate call " + signature.toString();
|
||||
|
||||
if (codegen.context.getContextKind() != OwnerKind.PACKAGE) {
|
||||
if (codegen.getContext().getContextKind() != OwnerKind.PACKAGE) {
|
||||
v.load(0, OBJECT_TYPE);
|
||||
}
|
||||
|
||||
PropertyDescriptor propertyDescriptor = callableDescriptor.getCorrespondingProperty();
|
||||
CodegenContext<? extends ClassOrPackageFragmentDescriptor> ownerContext = codegen.getContext().getClassOrPackageParentContext();
|
||||
final Type owner;
|
||||
if (ownerContext instanceof ClassContext) {
|
||||
owner = state.getTypeMapper().mapClass(((ClassContext) ownerContext).getContextDescriptor());
|
||||
}
|
||||
else if (ownerContext instanceof PackageContext) {
|
||||
owner = ((PackageContext) ownerContext).getPackagePartType();
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("Unknown context: " + ownerContext);
|
||||
}
|
||||
|
||||
StackValue delegatedProperty = codegen.intermediateValueForProperty(propertyDescriptor, true, null);
|
||||
codegen.tempVariables.put(
|
||||
call.getValueArguments().get(1).asElement(),
|
||||
new StackValue(PROPERTY_METADATA_TYPE) {
|
||||
@Override
|
||||
public void put(Type type, InstructionAdapter v) {
|
||||
v.getstatic(owner.getInternalName(), JvmAbi.PROPERTY_METADATA_ARRAY_NAME, "[" + PROPERTY_METADATA_TYPE);
|
||||
v.iconst(index);
|
||||
StackValue.arrayElement(PROPERTY_METADATA_TYPE).put(type, v);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
StackValue delegatedProperty = codegen.intermediateValueForProperty(callableDescriptor.getCorrespondingProperty(), true, null);
|
||||
StackValue lastValue = codegen.invokeFunction(call, delegatedProperty, resolvedCall);
|
||||
|
||||
Type asmType = signature.getReturnType();
|
||||
|
||||
@@ -19,7 +19,6 @@ package org.jetbrains.jet.codegen.context;
|
||||
import kotlin.Function0;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
import org.jetbrains.jet.codegen.*;
|
||||
import org.jetbrains.jet.codegen.binding.CodegenBinding;
|
||||
import org.jetbrains.jet.codegen.binding.MutableClosure;
|
||||
@@ -33,17 +32,18 @@ import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.storage.LockBasedStorageManager;
|
||||
import org.jetbrains.jet.storage.NullableLazyValue;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_PRIVATE;
|
||||
import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_PROTECTED;
|
||||
import static org.jetbrains.jet.codegen.AsmUtil.CAPTURED_THIS_FIELD;
|
||||
import static org.jetbrains.jet.codegen.AsmUtil.getVisibilityAccessFlag;
|
||||
import static org.jetbrains.jet.codegen.binding.CodegenBinding.*;
|
||||
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
|
||||
import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_PRIVATE;
|
||||
import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_PROTECTED;
|
||||
|
||||
public abstract class CodegenContext<T extends DeclarationDescriptor> {
|
||||
|
||||
@@ -103,17 +103,15 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ClassOrPackageFragmentDescriptor getClassOrPackageDescriptor() {
|
||||
CodegenContext c = this;
|
||||
@SuppressWarnings("unchecked")
|
||||
public CodegenContext<? extends ClassOrPackageFragmentDescriptor> getClassOrPackageParentContext() {
|
||||
CodegenContext<?> context = this;
|
||||
while (true) {
|
||||
assert c != null;
|
||||
DeclarationDescriptor contextDescriptor = c.getContextDescriptor();
|
||||
if (contextDescriptor instanceof ClassOrPackageFragmentDescriptor) {
|
||||
return (ClassOrPackageFragmentDescriptor) contextDescriptor;
|
||||
}
|
||||
else {
|
||||
c = c.getParentContext();
|
||||
if (context.getContextDescriptor() instanceof ClassOrPackageFragmentDescriptor) {
|
||||
return (CodegenContext) context;
|
||||
}
|
||||
context = context.getParentContext();
|
||||
assert context != null : "Context which is not top-level has no parent: " + this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,7 +411,7 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
|
||||
}
|
||||
|
||||
CodegenContext descriptorContext = null;
|
||||
if (!fromOutsideContext || getClassOrPackageDescriptor() != descriptor.getContainingDeclaration()) {
|
||||
if (!fromOutsideContext || getClassOrPackageParentContext().getContextDescriptor() != descriptor.getContainingDeclaration()) {
|
||||
DeclarationDescriptor enclosed = descriptor.getContainingDeclaration();
|
||||
boolean isClassObjectMember = DescriptorUtils.isClassObject(enclosed);
|
||||
//go upper
|
||||
|
||||
@@ -35,6 +35,8 @@ public class AsmTypeConstants {
|
||||
public static final Type FUNCTION0_TYPE = Type.getObjectType(BUILT_INS_PACKAGE_FQ_NAME + "/Function0");
|
||||
public static final Type FUNCTION1_TYPE = Type.getObjectType(BUILT_INS_PACKAGE_FQ_NAME + "/Function1");
|
||||
public static final Type INT_RANGE_TYPE = Type.getObjectType(BUILT_INS_PACKAGE_FQ_NAME + "/IntRange");
|
||||
public static final Type PROPERTY_METADATA_TYPE = Type.getObjectType(BUILT_INS_PACKAGE_FQ_NAME + "/PropertyMetadata");
|
||||
public static final Type PROPERTY_METADATA_IMPL_TYPE = Type.getObjectType(BUILT_INS_PACKAGE_FQ_NAME + "/PropertyMetadataImpl");
|
||||
|
||||
public static final Type OBJECT_REF_TYPE = Type.getObjectType("kotlin/jvm/internal/Ref$ObjectRef");
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import java.util.IdentityHashMap
|
||||
|
||||
class A {
|
||||
var foo: Int by IntHandler
|
||||
|
||||
class object {
|
||||
var bar: Any? by AnyHandler
|
||||
}
|
||||
}
|
||||
|
||||
val baz: String by StringHandler
|
||||
|
||||
|
||||
|
||||
val metadatas = IdentityHashMap<PropertyMetadata, Unit>()
|
||||
|
||||
fun record(p: PropertyMetadata) = metadatas.put(p, Unit.VALUE)
|
||||
|
||||
object IntHandler {
|
||||
fun get(t: Any?, p: PropertyMetadata): Int { record(p); return 42 }
|
||||
fun set(t: Any?, p: PropertyMetadata, value: Int) { record(p) }
|
||||
}
|
||||
|
||||
object AnyHandler {
|
||||
fun get(t: Any?, p: PropertyMetadata): Any? { record(p); return 3.14 }
|
||||
fun set(t: Any?, p: PropertyMetadata, value: Any?) { record(p) }
|
||||
}
|
||||
|
||||
object StringHandler {
|
||||
fun get(t: Any?, p: PropertyMetadata): String { record(p); return p.name }
|
||||
fun set(t: Any?, p: PropertyMetadata, value: String) { record(p) }
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val a = A()
|
||||
a.foo = 42
|
||||
a.foo = a.foo + baz.length
|
||||
a.foo = 239
|
||||
A.bar = baz + a.foo
|
||||
baz + A.bar
|
||||
|
||||
if (metadatas.keySet().size() != 3)
|
||||
return "Fail: only three instances of PropertyMetadata should have been created\n${metadatas.keySet()}"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -2299,6 +2299,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
doTest("compiler/testData/codegen/box/delegatedProperty/privateVar.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("propertyMetadataShouldBeCached.kt")
|
||||
public void testPropertyMetadataShouldBeCached() throws Exception {
|
||||
doTest("compiler/testData/codegen/box/delegatedProperty/propertyMetadataShouldBeCached.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("setAsExtensionFun.kt")
|
||||
public void testSetAsExtensionFun() throws Exception {
|
||||
doTest("compiler/testData/codegen/box/delegatedProperty/setAsExtensionFun.kt");
|
||||
|
||||
@@ -38,6 +38,7 @@ public final class JvmAbi {
|
||||
public static final String CLASS_OBJECT_SUFFIX = "$" + CLASS_OBJECT_CLASS_NAME;
|
||||
|
||||
public static final String DELEGATED_PROPERTY_NAME_SUFFIX = "$delegate";
|
||||
public static final String PROPERTY_METADATA_ARRAY_NAME = "$propertyMetadata";
|
||||
public static final String ANNOTATED_PROPERTY_METHOD_NAME_SUFFIX = "$annotations";
|
||||
|
||||
public static final String INSTANCE_FIELD = "instance$";
|
||||
|
||||
Reference in New Issue
Block a user