2 * Copyright (C) 2014, United States Government, as represented by the
3 * Administrator of the National Aeronautics and Space Administration.
6 * The Java Pathfinder core (jpf-core) platform is licensed under the
7 * Apache License, Version 2.0 (the "License"); you may not use this file except
8 * in compliance with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0.
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 package gov.nasa.jpf.jvm;
21 import gov.nasa.jpf.Config;
22 import gov.nasa.jpf.util.Misc;
23 import gov.nasa.jpf.util.StringSetMatcher;
24 import gov.nasa.jpf.vm.*;
26 import java.lang.reflect.Modifier;
27 import java.util.HashMap;
28 import java.util.LinkedHashMap;
31 * a ClassInfo that was created from a Java classfile
33 public class JVMClassInfo extends ClassInfo {
36 * this is the inner class that does the actual ClassInfo initialization from ClassFile. It is an inner class so that
37 * (a) it can set ClassInfo fields, (b) it can extend ClassFileReaderAdapter, and (c) we don't clutter JVMClassInfo with
38 * fields that are only temporarily used during parsing
40 class Initializer extends ClassFileReaderAdapter {
41 protected ClassFile cf;
42 protected JVMCodeBuilder cb;
44 public Initializer (ClassFile cf, JVMCodeBuilder cb) throws ClassParseException {
52 public void setClass (ClassFile cf, String clsName, String superClsName, int flags, int cpCount) throws ClassParseException {
53 JVMClassInfo.this.setClass(clsName, superClsName, flags, cpCount);
57 public void setClassAttribute (ClassFile cf, int attrIndex, String name, int attrLength) {
58 if (name == ClassFile.SOURCE_FILE_ATTR) {
59 cf.parseSourceFileAttr(this, null);
61 } else if (name == ClassFile.SIGNATURE_ATTR) {
62 cf.parseSignatureAttr(this, JVMClassInfo.this);
64 } else if (name == ClassFile.RUNTIME_VISIBLE_ANNOTATIONS_ATTR) {
65 cf.parseAnnotationsAttr(this, JVMClassInfo.this);
67 } else if (name == ClassFile.RUNTIME_INVISIBLE_ANNOTATIONS_ATTR) {
68 //cf.parseAnnotationsAttr(this, ClassInfo.this);
70 } else if (name == ClassFile.RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR) {
71 cf.parseTypeAnnotationsAttr(this, JVMClassInfo.this);
73 } else if (name == ClassFile.INNER_CLASSES_ATTR) {
74 cf.parseInnerClassesAttr(this, JVMClassInfo.this);
76 } else if (name == ClassFile.ENCLOSING_METHOD_ATTR) {
77 cf.parseEnclosingMethodAttr(this, JVMClassInfo.this);
79 } else if (name == ClassFile.BOOTSTRAP_METHOD_ATTR) {
80 cf.parseBootstrapMethodAttr(this, JVMClassInfo.this);
86 public void setBootstrapMethodCount (ClassFile cf, Object tag, int count) {
87 bootstrapMethods = new BootstrapMethodInfo[count];
91 public void setBootstrapMethod (ClassFile cf, Object tag, int idx, int refKind, String cls, String mth, String descriptor, int[] cpArgs) {
93 int lambdaRefKind = cf.mhRefTypeAt(cpArgs[1]);
95 int mrefIdx = cf.mhMethodRefIndexAt(cpArgs[1]);
96 String clsName = cf.methodClassNameAt(mrefIdx).replace('/', '.');
97 ClassInfo eclosingLambdaCls;
99 if(!clsName.equals(JVMClassInfo.this.getName())) {
100 eclosingLambdaCls = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName);
102 eclosingLambdaCls = JVMClassInfo.this;
105 assert (eclosingLambdaCls!=null);
107 String mthName = cf.methodNameAt(mrefIdx);
108 String signature = cf.methodDescriptorAt(mrefIdx);
110 MethodInfo lambdaBody = eclosingLambdaCls.getMethod(mthName + signature, false);
112 String samDescriptor = cf.methodTypeDescriptorAt(cpArgs[2]);
114 if(lambdaBody!=null) {
115 bootstrapMethods[idx] = new BootstrapMethodInfo(lambdaRefKind, JVMClassInfo.this, lambdaBody, samDescriptor);
119 //--- inner/enclosing classes
121 public void setInnerClassCount (ClassFile cf, Object tag, int classCount) {
122 innerClassNames = new String[classCount];
126 public void setInnerClass (ClassFile cf, Object tag, int innerClsIndex,
127 String outerName, String innerName, String innerSimpleName, int accessFlags) {
128 // Ok, this is a total mess - some names are in dot notation, others use '/'
129 // and to make it even more confusing, some InnerClass attributes refer NOT
130 // to the currently parsed class, so we have to check if we are the outerName,
131 // but then 'outerName' can also be null instead of our own name.
132 // Oh, and there are also InnerClass attributes that have their own name as inner names
133 // (see java/lang/String$CaseInsensitiveComparator or ...System and java/lang/System$1 for instance)
134 if (outerName != null) {
135 outerName = Types.getClassNameFromTypeName(outerName);
138 innerName = Types.getClassNameFromTypeName(innerName);
139 if (!innerName.equals(name)) {
140 innerClassNames[innerClsIndex] = innerName;
143 // this refers to ourself, and can be a force fight with setEnclosingMethod
144 if (outerName != null) { // only set if this is a direct member, otherwise taken from setEnclosingMethod
145 setEnclosingClass(outerName);
151 public void setEnclosingMethod (ClassFile cf, Object tag, String enclosingClassName, String enclosingMethodName, String descriptor) {
152 setEnclosingClass(enclosingClassName);
154 if (enclosingMethodName != null) {
155 JVMClassInfo.this.setEnclosingMethod(enclosingMethodName + descriptor);
160 public void setInnerClassesDone (ClassFile cf, Object tag) {
161 // we have to check if we allocated too many - see the mess above
162 for (int i = 0; i < innerClassNames.length; i++) {
163 innerClassNames = Misc.stripNullElements(innerClassNames);
169 public void setSourceFile (ClassFile cf, Object tag, String fileName) {
170 JVMClassInfo.this.setSourceFile(fileName);
175 public void setInterfaceCount (ClassFile cf, int ifcCount) {
176 interfaceNames = new String[ifcCount];
180 public void setInterface (ClassFile cf, int ifcIndex, String ifcName) {
181 interfaceNames[ifcIndex] = Types.getClassNameFromTypeName(ifcName);
185 // unfortunately they are stored together in the ClassFile, i.e. we
186 // have to split them up once we are done
188 protected FieldInfo[] fields;
189 protected FieldInfo curFi; // need to cache for attributes
192 public void setFieldCount (ClassFile cf, int fieldCount) {
194 fields = new FieldInfo[fieldCount];
201 public void setField (ClassFile cf, int fieldIndex, int accessFlags, String name, String descriptor) {
202 FieldInfo fi = FieldInfo.create(name, descriptor, accessFlags);
203 fields[fieldIndex] = fi;
204 curFi = fi; // for attributes
208 public void setFieldAttribute (ClassFile cf, int fieldIndex, int attrIndex, String name, int attrLength) {
209 if (name == ClassFile.SIGNATURE_ATTR) {
210 cf.parseSignatureAttr(this, curFi);
212 } else if (name == ClassFile.CONST_VALUE_ATTR) {
213 cf.parseConstValueAttr(this, curFi);
215 } else if (name == ClassFile.RUNTIME_VISIBLE_ANNOTATIONS_ATTR) {
216 cf.parseAnnotationsAttr(this, curFi);
218 } else if (name == ClassFile.RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR) {
219 cf.parseTypeAnnotationsAttr(this, curFi);
221 } else if (name == ClassFile.RUNTIME_INVISIBLE_ANNOTATIONS_ATTR) {
222 //cf.parseAnnotationsAttr(this, curFi);
227 public void setConstantValue (ClassFile cf, Object tag, Object constVal) {
228 curFi.setConstantValue(constVal);
232 public void setFieldsDone (ClassFile cf) {
236 //--- declaredMethods
237 protected MethodInfo curMi;
240 public void setMethodCount (ClassFile cf, int methodCount) {
241 methods = new LinkedHashMap<String, MethodInfo>();
245 public void setMethod (ClassFile cf, int methodIndex, int accessFlags, String name, String signature) {
246 MethodInfo mi = MethodInfo.create(name, signature, accessFlags);
251 public void setMethodDone (ClassFile cf, int methodIndex){
252 curMi.setLocalVarAnnotations();
254 JVMClassInfo.this.setMethod(curMi);
258 public void setMethodAttribute (ClassFile cf, int methodIndex, int attrIndex, String name, int attrLength) {
259 if (name == ClassFile.CODE_ATTR) {
260 cf.parseCodeAttr(this, curMi);
262 } else if (name == ClassFile.SIGNATURE_ATTR) {
263 cf.parseSignatureAttr(this, curMi);
265 } else if (name == ClassFile.EXCEPTIONS_ATTR) {
266 cf.parseExceptionAttr(this, curMi);
268 } else if (name == ClassFile.RUNTIME_VISIBLE_ANNOTATIONS_ATTR) {
269 cf.parseAnnotationsAttr(this, curMi);
271 } else if (name == ClassFile.RUNTIME_INVISIBLE_ANNOTATIONS_ATTR) {
272 //cf.parseAnnotationsAttr(this, curMi);
273 } else if (name == ClassFile.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS_ATTR) {
274 cf.parseParameterAnnotationsAttr(this, curMi);
276 } else if (name == ClassFile.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS_ATTR) {
277 //cf.parseParameterAnnotationsAttr(this, curMi);
279 } else if (name == ClassFile.RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR) {
280 cf.parseTypeAnnotationsAttr(this, curMi);
285 //--- current methods throws list
286 protected String[] exceptions;
289 public void setExceptionCount (ClassFile cf, Object tag, int exceptionCount) {
290 exceptions = new String[exceptionCount];
294 public void setException (ClassFile cf, Object tag, int exceptionIndex, String exceptionType) {
295 exceptions[exceptionIndex] = Types.getClassNameFromTypeName(exceptionType);
299 public void setExceptionsDone (ClassFile cf, Object tag) {
300 curMi.setThrownExceptions(exceptions);
303 //--- current method exception handlers
304 protected ExceptionHandler[] handlers;
307 public void setExceptionHandlerTableCount (ClassFile cf, Object tag, int exceptionTableCount) {
308 handlers = new ExceptionHandler[exceptionTableCount];
312 public void setExceptionHandler (ClassFile cf, Object tag, int handlerIndex,
313 int startPc, int endPc, int handlerPc, String catchType) {
314 ExceptionHandler xh = new ExceptionHandler(catchType, startPc, endPc, handlerPc);
315 handlers[handlerIndex] = xh;
319 public void setExceptionHandlerTableDone (ClassFile cf, Object tag) {
320 curMi.setExceptionHandlers(handlers);
323 //--- current method code
325 public void setCode (ClassFile cf, Object tag, int maxStack, int maxLocals, int codeLength) {
326 curMi.setMaxLocals(maxLocals);
327 curMi.setMaxStack(maxStack);
331 cf.parseBytecode(cb, tag, codeLength);
336 public void setCodeAttribute (ClassFile cf, Object tag, int attrIndex, String name, int attrLength) {
337 if (name == ClassFile.LINE_NUMBER_TABLE_ATTR) {
338 cf.parseLineNumberTableAttr(this, tag);
340 } else if (name == ClassFile.LOCAL_VAR_TABLE_ATTR) {
341 cf.parseLocalVarTableAttr(this, tag);
343 } else if (name == ClassFile.RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR){
344 cf.parseTypeAnnotationsAttr(this, tag);
348 //--- current method line numbers
349 protected int[] lines, startPcs;
352 public void setLineNumberTableCount (ClassFile cf, Object tag, int lineNumberCount) {
353 lines = new int[lineNumberCount];
354 startPcs = new int[lineNumberCount];
358 public void setLineNumber (ClassFile cf, Object tag, int lineIndex, int lineNumber, int startPc) {
359 lines[lineIndex] = lineNumber;
360 startPcs[lineIndex] = startPc;
364 public void setLineNumberTableDone (ClassFile cf, Object tag) {
365 curMi.setLineNumbers(lines, startPcs);
368 //--- current method local variables
369 protected LocalVarInfo[] localVars;
372 public void setLocalVarTableCount (ClassFile cf, Object tag, int localVarCount) {
373 localVars = new LocalVarInfo[localVarCount];
377 public void setLocalVar (ClassFile cf, Object tag, int localVarIndex,
378 String varName, String descriptor, int scopeStartPc, int scopeEndPc, int slotIndex) {
379 LocalVarInfo lvi = new LocalVarInfo(varName, descriptor, "", scopeStartPc, scopeEndPc, slotIndex);
380 localVars[localVarIndex] = lvi;
384 public void setLocalVarTableDone (ClassFile cf, Object tag) {
385 curMi.setLocalVarTable(localVars);
389 protected AnnotationInfo[] annotations;
390 protected AnnotationInfo curAi;
391 protected AnnotationInfo[][] parameterAnnotations;
392 protected Object[] values;
394 //--- declaration annotations
397 public void setAnnotationCount (ClassFile cf, Object tag, int annotationCount) {
398 annotations = new AnnotationInfo[annotationCount];
402 public void setAnnotation (ClassFile cf, Object tag, int annotationIndex, String annotationType) {
403 if (tag instanceof InfoObject) {
404 curAi = getResolvedAnnotationInfo(Types.getClassNameFromTypeName(annotationType));
405 annotations[annotationIndex] = curAi;
410 public void setAnnotationsDone (ClassFile cf, Object tag) {
411 if (tag instanceof InfoObject) {
412 ((InfoObject) tag).addAnnotations(annotations);
417 public void setParameterCount (ClassFile cf, Object tag, int parameterCount) {
418 parameterAnnotations = new AnnotationInfo[parameterCount][];
422 public void setParameterAnnotationCount (ClassFile cf, Object tag, int paramIndex, int annotationCount) {
423 annotations = new AnnotationInfo[annotationCount];
424 parameterAnnotations[paramIndex] = annotations;
428 public void setParameterAnnotation (ClassFile cf, Object tag, int annotationIndex, String annotationType) {
429 curAi = getResolvedAnnotationInfo(Types.getClassNameFromTypeName(annotationType));
430 annotations[annotationIndex] = curAi;
434 public void setParametersDone (ClassFile cf, Object tag) {
435 curMi.setParameterAnnotations(parameterAnnotations);
438 //--- Java 8 type annotations
441 public void setTypeAnnotationCount(ClassFile cf, Object tag, int annotationCount){
442 annotations = new AnnotationInfo[annotationCount];
446 public void setTypeParameterAnnotation(ClassFile cf, Object tag, int annotationIndex, int targetType,
447 int typeIndex, short[] typePath, String annotationType){
448 AnnotationInfo base = getResolvedAnnotationInfo(Types.getClassNameFromTypeName(annotationType));
449 curAi = new TypeParameterAnnotationInfo(base, targetType, typePath, typeIndex);
450 annotations[annotationIndex] = curAi;
453 public void setSuperTypeAnnotation(ClassFile cf, Object tag, int annotationIndex, int targetType,
454 int superTypeIdx, short[] typePath, String annotationType){
455 AnnotationInfo base = getResolvedAnnotationInfo(Types.getClassNameFromTypeName(annotationType));
456 curAi = new SuperTypeAnnotationInfo(base, targetType, typePath, superTypeIdx);
457 annotations[annotationIndex] = curAi;
460 public void setTypeParameterBoundAnnotation(ClassFile cf, Object tag, int annotationIndex, int targetType,
461 int typeIndex, int boundIndex, short[] typePath, String annotationType){
462 AnnotationInfo base = getResolvedAnnotationInfo(Types.getClassNameFromTypeName(annotationType));
463 curAi = new TypeParameterBoundAnnotationInfo(base, targetType, typePath, typeIndex, boundIndex);
464 annotations[annotationIndex] = curAi;
467 public void setTypeAnnotation(ClassFile cf, Object tag, int annotationIndex, int targetType,
468 short[] typePath, String annotationType){
469 AnnotationInfo base = getResolvedAnnotationInfo(Types.getClassNameFromTypeName(annotationType));
470 curAi = new TypeAnnotationInfo(base, targetType, typePath);
471 annotations[annotationIndex] = curAi;
474 public void setFormalParameterAnnotation(ClassFile cf, Object tag, int annotationIndex, int targetType,
475 int paramIndex, short[] typePath, String annotationType){
476 AnnotationInfo base = getResolvedAnnotationInfo(Types.getClassNameFromTypeName(annotationType));
477 curAi = new FormalParameterAnnotationInfo(base, targetType, typePath, paramIndex);
478 annotations[annotationIndex] = curAi;
481 public void setThrowsAnnotation(ClassFile cf, Object tag, int annotationIndex, int targetType,
482 int throwsTypeIdx, short[] typePath, String annotationType){
483 AnnotationInfo base = getResolvedAnnotationInfo(Types.getClassNameFromTypeName(annotationType));
484 curAi = new ThrowsAnnotationInfo(base, targetType, typePath, throwsTypeIdx);
485 annotations[annotationIndex] = curAi;
488 public void setVariableAnnotation(ClassFile cf, Object tag, int annotationIndex, int targetType,
489 long[] scopeEntries, short[] typePath, String annotationType){
490 AnnotationInfo base = getResolvedAnnotationInfo(Types.getClassNameFromTypeName(annotationType));
491 VariableAnnotationInfo vai = new VariableAnnotationInfo(base, targetType, typePath, scopeEntries);
493 annotations[annotationIndex] = curAi;
496 public void setExceptionParameterAnnotation(ClassFile cf, Object tag, int annotationIndex, int targetType,
497 int exceptionIndex, short[] typePath, String annotationType){
498 AnnotationInfo base = getResolvedAnnotationInfo(Types.getClassNameFromTypeName(annotationType));
499 curAi= new ExceptionParameterAnnotationInfo(base, targetType, typePath, exceptionIndex);
500 annotations[annotationIndex] = curAi;
503 public void setBytecodeAnnotation(ClassFile cf, Object tag, int annotationIndex, int targetType,
504 int offset, short[] typePath, String annotationType){
505 AnnotationInfo base = getResolvedAnnotationInfo(Types.getClassNameFromTypeName(annotationType));
506 curAi = new BytecodeAnnotationInfo(base, targetType, typePath, offset);
507 annotations[annotationIndex] = curAi;
510 public void setBytecodeTypeParameterAnnotation(ClassFile cf, Object tag, int annotationIndex, int targetType,
511 int offset, int typeArgIdx, short[] typePath, String annotationType){
512 AnnotationInfo base = getResolvedAnnotationInfo(Types.getClassNameFromTypeName(annotationType));
513 curAi = new BytecodeTypeParameterAnnotationInfo(base, targetType, typePath, offset, typeArgIdx);
514 annotations[annotationIndex] = curAi;
518 public void setTypeAnnotationsDone(ClassFile cf, Object tag) {
519 if (tag instanceof InfoObject) {
520 int len = annotations.length;
521 AbstractTypeAnnotationInfo[] tais = new AbstractTypeAnnotationInfo[annotations.length];
522 for (int i=0; i<len; i++){
523 tais[i] = (AbstractTypeAnnotationInfo)annotations[i];
526 // we can get them in batches (e.g. VariableTypeAnnos from code attrs and ReturnTypeAnnos from method attrs
527 ((InfoObject) tag).addTypeAnnotations( tais);
531 //--- AnnotationInfo values entries
533 public void setAnnotationValueCount (ClassFile cf, Object tag, int annotationIndex, int nValuePairs) {
534 // if we have values, we need to clone the defined annotation so that we can overwrite entries
535 curAi = curAi.cloneForOverriddenValues();
536 annotations[annotationIndex] = curAi;
540 public void setPrimitiveAnnotationValue (ClassFile cf, Object tag, int annotationIndex, int valueIndex,
541 String elementName, int arrayIndex, Object val) {
542 if (arrayIndex >= 0) {
543 values[arrayIndex] = val;
545 curAi.setClonedEntryValue(elementName, val);
550 public void setStringAnnotationValue (ClassFile cf, Object tag, int annotationIndex, int valueIndex,
551 String elementName, int arrayIndex, String val) {
552 if (arrayIndex >= 0) {
553 values[arrayIndex] = val;
555 curAi.setClonedEntryValue(elementName, val);
560 public void setClassAnnotationValue (ClassFile cf, Object tag, int annotationIndex, int valueIndex, String elementName,
561 int arrayIndex, String typeName) {
562 Object val = AnnotationInfo.getClassValue(typeName);
563 if (arrayIndex >= 0) {
564 values[arrayIndex] = val;
566 curAi.setClonedEntryValue(elementName, val);
571 public void setEnumAnnotationValue (ClassFile cf, Object tag, int annotationIndex, int valueIndex,
572 String elementName, int arrayIndex, String enumType, String enumValue) {
573 Object val = AnnotationInfo.getEnumValue(enumType, enumValue);
574 if (arrayIndex >= 0) {
575 values[arrayIndex] = val;
577 curAi.setClonedEntryValue(elementName, val);
582 public void setAnnotationValueElementCount (ClassFile cf, Object tag, int annotationIndex, int valueIndex,
583 String elementName, int elementCount) {
584 values = new Object[elementCount];
588 public void setAnnotationValueElementsDone (ClassFile cf, Object tag, int annotationIndex, int valueIndex, String elementName) {
589 curAi.setClonedEntryValue(elementName, values);
594 public void setSignature (ClassFile cf, Object tag, String signature) {
595 if (tag instanceof GenericSignatureHolder) {
596 ((GenericSignatureHolder) tag).setGenericSignature(signature);
601 // since nested class init locking can explode the state space, we make it optional and controllable
602 protected static boolean nestedInit;
603 protected static StringSetMatcher includeNestedInit;
604 protected static StringSetMatcher excludeNestedInit;
606 protected static boolean init (Config config){
607 nestedInit = config.getBoolean("jvm.nested_init", false);
609 includeNestedInit = StringSetMatcher.getNonEmpty(config.getStringArray("jvm.nested_init.include"));
610 excludeNestedInit = StringSetMatcher.getNonEmpty(config.getStringArray("jvm.nested_init.exclude"));
616 JVMClassInfo (String name, ClassLoaderInfo cli, ClassFile cf, String srcUrl, JVMCodeBuilder cb) throws ClassParseException {
617 super( name, cli, srcUrl);
619 new Initializer( cf, cb); // we just need the ctor
625 //--- for annotation classinfos
627 // called on the annotation classinfo
629 protected ClassInfo createAnnotationProxy (String proxyName){
630 return new JVMClassInfo (this, proxyName, classLoader, null);
633 // concrete proxy ctor
634 protected JVMClassInfo (ClassInfo ciAnnotation, String proxyName, ClassLoaderInfo cli, String url) {
635 super( ciAnnotation, proxyName, cli, url);
639 * This is called on the functional interface type. It creates a synthetic type which
640 * implements the functional interface and contains a method capturing the behavior
641 * of the lambda expression.
644 protected ClassInfo createFuncObjClassInfo (BootstrapMethodInfo bootstrapMethod, String name, String samUniqueName, String[] fieldTypesName) {
645 return new JVMClassInfo(this, bootstrapMethod, name, samUniqueName, fieldTypesName);
648 protected JVMClassInfo (ClassInfo funcInterface, BootstrapMethodInfo bootstrapMethod, String name, String samUniqueName, String[] fieldTypesName) {
649 super(funcInterface, bootstrapMethod, name, fieldTypesName);
651 // creating a method corresponding to the single abstract method of the functional interface
652 methods = new HashMap<String, MethodInfo>();
654 MethodInfo fiMethod = funcInterface.getInterfaceAbstractMethod();
655 int modifiers = fiMethod.getModifiers() & (~Modifier.ABSTRACT);
656 int nLocals = fiMethod.getArgumentsSize();
657 int nOperands = this.nInstanceFields + nLocals;
659 MethodInfo mi = new MethodInfo(fiMethod.getName(), fiMethod.getSignature(), modifiers, nLocals, nOperands);
660 mi.linkToClass(this);
662 methods.put(mi.getUniqueName(), mi);
664 setLambdaDirectCallCode(mi, bootstrapMethod);
668 } catch (ClassParseException e) {
669 // we do not even get here - this a synthetic class, and at this point
670 // the interfaces are already loaded.
675 * perform initialization of this class and its not-yet-initialized superclasses (top down),
676 * which includes calling clinit() methods
678 * This is overridden here to model a questionable yet consequential behavior of hotspot, which
679 * is holding derived class locks when initializing base classes. The generic implementation in
680 * ClassInfo uses non-nested locks (i.e. A.clinit() only synchronizes on A.class) and hence cannot
681 * produce the same static init deadlocks as hotspot. In order to catch such defects we implement
682 * nested locking here.
684 * The main difference is that the generic implementation only pushes DCSFs for required clinits
685 * and otherwise doesn't lock anything. Here, we create one static init specific DCSF which wraps
686 * all clinits in nested monitorenter/exits. We create this even if there is no clinit so that we
687 * mimic hotspot locking.
689 * Note this scheme also enables us to get rid of the automatic clinit sync (they don't have
690 * a 0x20 sync modifier in classfiles)
692 * @return true if client needs to re-execute because we pushed DirectCallStackFrames
695 public boolean initializeClass(ThreadInfo ti) {
696 if (needsInitialization(ti)) {
697 if (nestedInit && StringSetMatcher.isMatch(name, includeNestedInit, excludeNestedInit)) {
698 registerClass(ti); // this is recursively upwards
699 int nOps = 2 * (getNumberOfSuperClasses() + 1); // this is just an upper bound for the number of operands we need
701 MethodInfo miInitialize = new MethodInfo("[initializeClass]", "()V", Modifier.STATIC, 0, nOps);
702 JVMDirectCallStackFrame frame = new JVMDirectCallStackFrame(miInitialize, null);
703 JVMCodeBuilder cb = getSystemCodeBuilder(null, miInitialize);
705 addClassInit(ti, frame, cb); // this is recursively upwards until we hit a initialized superclass
706 cb.directcallreturn();
709 // this is normally initialized in the ctor, but at that point we don't have the code yet
710 frame.setPC(miInitialize.getFirstInsn());
713 return true; // client has to re-execute, we pushed a stackframe
716 } else { // use generic initialization without nested locks (directly calling clinits)
717 return super.initializeClass(ti);
721 return false; // nothing to do
725 protected void addClassInit (ThreadInfo ti, JVMDirectCallStackFrame frame, JVMCodeBuilder cb){
726 int clsObjRef = getClassObjectRef();
728 frame.pushRef(clsObjRef);
731 if (superClass != null && superClass.needsInitialization(ti)) {
732 ((JVMClassInfo) superClass).addClassInit(ti, frame, cb); // go recursive
735 if (getMethod("<clinit>()V", false) != null) { // do we have a clinit
736 cb.invokeclinit(this);
738 cb.finishclinit(this);
739 // we can't just do call ci.setInitialized() since that has to be deferred
742 frame.pushRef(clsObjRef);
746 //--- call processing
748 protected JVMCodeBuilder getSystemCodeBuilder (ClassFile cf, MethodInfo mi){
749 JVMSystemClassLoaderInfo sysCl = (JVMSystemClassLoaderInfo) ClassLoaderInfo.getCurrentSystemClassLoader();
750 JVMCodeBuilder cb = sysCl.getSystemCodeBuilder(cf, mi);
756 * to be called from super proxy ctor
757 * this needs to be in the VM specific ClassInfo because we need to create code
760 protected void setAnnotationValueGetterCode (MethodInfo pmi, FieldInfo fi){
761 JVMCodeBuilder cb = getSystemCodeBuilder(null, pmi);
764 cb.getfield( pmi.getName(), name, pmi.getReturnType());
765 if (fi.isReference()) {
768 if (fi.getStorageSize() == 1) {
779 protected void setDirectCallCode (MethodInfo miDirectCall, MethodInfo miCallee){
780 JVMCodeBuilder cb = getSystemCodeBuilder(null, miDirectCall);
782 String calleeName = miCallee.getName();
783 String calleeSig = miCallee.getSignature();
785 if (miCallee.isStatic()){
786 if (miCallee.isClinit()) {
787 cb.invokeclinit(this);
789 cb.invokestatic( name, calleeName, calleeSig);
791 } else if (name.equals("<init>") || miCallee.isPrivate()){
792 cb.invokespecial( name, calleeName, calleeSig);
794 cb.invokevirtual( name, calleeName, calleeSig);
797 cb.directcallreturn();
803 protected void setNativeCallCode (NativeMethodInfo miNative){
804 JVMCodeBuilder cb = getSystemCodeBuilder(null, miNative);
806 cb.executenative(miNative);
813 protected void setRunStartCode (MethodInfo miStub, MethodInfo miRun){
814 JVMCodeBuilder cb = getSystemCodeBuilder(null, miStub);
816 cb.runStart( miStub);
817 cb.invokevirtual( name, miRun.getName(), miRun.getSignature());
818 cb.directcallreturn();
824 * This method creates the body of the function object method that captures the
828 protected void setLambdaDirectCallCode (MethodInfo miDirectCall, BootstrapMethodInfo bootstrapMethod) {
830 MethodInfo miCallee = bootstrapMethod.getLambdaBody();
831 String samSignature = bootstrapMethod.getSamDescriptor();
832 JVMCodeBuilder cb = getSystemCodeBuilder(null, miDirectCall);
834 String calleeName = miCallee.getName();
835 String calleeSig = miCallee.getSignature();
837 ClassInfo callerCi = miDirectCall.getClassInfo();
839 // loading free variables, which are used in the body of the lambda
840 // expression and captured by the lexical scope. These variables
841 // are stored by the fields of the synthetic function object class
842 int n = callerCi.getNumberOfInstanceFields();
843 for(int i=0; i<n; i++) {
845 FieldInfo fi = callerCi.getInstanceField(i);
847 cb.getfield(fi.getName(), callerCi.getName(), Types.getTypeSignature(fi.getSignature(), false));
850 // adding bytecode instructions to load input parameters of the lambda expression
851 n = miDirectCall.getArgumentsSize();
852 for(int i=1; i<n; i++) {
856 String calleeClass = miCallee.getClassName();
858 // adding the bytecode instruction to invoke lambda method
859 switch (bootstrapMethod.getLambdaRefKind()) {
860 case ClassFile.REF_INVOKESTATIC:
861 cb.invokestatic(calleeClass, calleeName, calleeSig);
863 case ClassFile.REF_INVOKEINTERFACE:
864 cb.invokeinterface(calleeClass, calleeName, calleeSig);
866 case ClassFile.REF_INVOKEVIRTUAL:
867 cb.invokevirtual(calleeClass, calleeName, calleeSig);
869 case ClassFile.REF_NEW_INVOKESPECIAL:
870 cb.new_(calleeClass);
871 cb.invokespecial(calleeClass, calleeName, calleeSig);
873 case ClassFile.REF_INVOKESPECIAL:
874 cb.invokespecial(calleeClass, calleeName, calleeSig);
878 String returnType = Types.getReturnTypeSignature(samSignature);
879 int len = returnType.length();
880 char c = returnType.charAt(0);
882 // adding a return statement for function object method
912 // create a stack frame that has properly initialized arguments
914 public StackFrame createStackFrame (ThreadInfo ti, MethodInfo callee){
917 NativeMethodInfo nativeCallee = (NativeMethodInfo) callee;
918 JVMNativeStackFrame calleeFrame = new JVMNativeStackFrame( nativeCallee);
919 calleeFrame.setArguments( ti);
923 JVMStackFrame calleeFrame = new JVMStackFrame( callee);
924 calleeFrame.setCallArguments( ti);
930 public DirectCallStackFrame createDirectCallStackFrame (ThreadInfo ti, MethodInfo miCallee, int nLocals){
931 int nOperands = miCallee.getNumberOfCallerStackSlots();
933 MethodInfo miDirect = new MethodInfo(miCallee, nLocals, nOperands);
934 setDirectCallCode( miDirect, miCallee);
936 return new JVMDirectCallStackFrame( miDirect, miCallee);
940 * while this is a normal DirectCallStackFrame, it has different code which has to be created here
943 public DirectCallStackFrame createRunStartStackFrame (ThreadInfo ti, MethodInfo miRun){
944 MethodInfo miDirect = new MethodInfo( miRun, 0, 1);
945 setRunStartCode( miDirect, miRun);
947 return new JVMDirectCallStackFrame( miDirect, miRun);