// // Copyright (C) 2006 United States Government as represented by the // Administrator of the National Aeronautics and Space Administration // (NASA). All Rights Reserved. // // This software is distributed under the NASA Open Source Agreement // (NOSA), version 1.3. The NOSA has been approved by the Open Source // Initiative. See the file NOSA-1.3-JPF at the top of the distribution // directory tree for the complete NOSA document. // // THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY // KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT // LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO // SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR // A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT // THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT // DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. // package gov.nasa.jpf.jvm.bytecode; import java.util.function.BiFunction; import cmu.conditional.ChoiceFactory; import cmu.conditional.Conditional; import cmu.conditional.One; import de.fosd.typechef.featureexpr.FeatureExpr; import de.fosd.typechef.featureexpr.FeatureExprFactory; import gov.nasa.jpf.vm.ArrayIndexOutOfBoundsExecutiveException; import gov.nasa.jpf.vm.ElementInfo; import gov.nasa.jpf.vm.Instruction; import gov.nasa.jpf.vm.MJIEnv; import gov.nasa.jpf.vm.StackFrame; import gov.nasa.jpf.vm.ThreadInfo; /** * abstraction for all array load instructions * * ..., array, index => ..., value */ public abstract class ArrayLoadInstruction extends ArrayElementInstruction { private Conditional<?> pushValue = One.valueOf(0); private FeatureExpr pushCtx; @Override public Conditional<Instruction> execute(FeatureExpr ctx, final ThreadInfo ti) { pushValue = One.valueOf(0); final StackFrame frame = ti.getModifiableTopFrame(); final Instruction thisInstruction = this; // we need to get the object first, to check if it is shared Conditional<Integer> aref = frame.peek(ctx, 1); // ..,arrayRef,idx final ArrayLoadInstruction instruction = this; pushCtx = ctx; Conditional<Instruction> next = aref.mapf(ctx, new BiFunction<FeatureExpr, Integer, Conditional<Instruction>>() { @Override public Conditional<Instruction> apply(FeatureExpr ctx, Integer aref) { if (aref == MJIEnv.NULL) { pushCtx = pushCtx.andNot(ctx); return new One<>(new EXCEPTION("java.lang.NullPointerException", "")); } final ElementInfo e = ti.getElementInfoWithUpdatedSharedness(aref); if (isNewPorBoundary(e, ti)) { if (createAndSetArrayCG(e, ti, aref, peekIndex(ctx, ti), true)) { pushCtx = pushCtx.andNot(ctx); return new One<Instruction>(instruction); } } return new One<Instruction>(null); } }); if (Conditional.isContradiction(pushCtx)) { return next; } index = frame.pop(ctx); // we should not set 'arrayRef' before the CG check // (this would kill the CG loop optimization) arrayRef = frame.pop(ctx).simplify(pushCtx); next = ChoiceFactory.create(pushCtx, arrayRef.mapf(FeatureExprFactory.True(), new BiFunction<FeatureExpr, Integer, Conditional<Instruction>>() { @Override public Conditional<Instruction> apply(FeatureExpr ctx, Integer aref) { final ElementInfo e = ti.getElementInfoWithUpdatedSharedness(aref); return index.mapf(ctx, new BiFunction<FeatureExpr, Integer, Conditional<Instruction>>() { @Override public Conditional<Instruction> apply(FeatureExpr ctx, Integer index) { try { final Conditional push = getPushValue(ctx, frame, e, index); pushValue = ChoiceFactory.create(ctx, push, pushValue); return getNext(ctx, ti); } catch (ArrayIndexOutOfBoundsException ex) { pushCtx = pushCtx.andNot(ctx); return new One<Instruction>(new EXCEPTION(thisInstruction, java.lang.ArrayIndexOutOfBoundsException.class.getName(), Integer.toString(index))); } } }); } }), next); frame.push(pushCtx, pushValue, isReference()); if (index.isOne() && aref.isOne()) { // TODO final ElementInfo e = ti.getElementInfoWithUpdatedSharedness(aref.getValue()); Object attr = e.getElementAttr(index.getValue()); if (attr != null) { if (getElementSize() == 1) { frame.setOperandAttr(attr); } else { frame.setLongOperandAttr(attr); } } } return next; } protected boolean isReference() { return false; } /** * only makes sense pre-exec */ @Override public Conditional<Integer> peekArrayRef(FeatureExpr ctx, ThreadInfo ti) { return ti.getTopFrame().peek(ctx, 1); } // wouldn't really be required for loads, but this is a general // ArrayInstruction API @Override public Conditional<Integer> peekIndex(FeatureExpr ctx, ThreadInfo ti) { return ti.getTopFrame().peek(ctx); } protected abstract Conditional<?> getPushValue(FeatureExpr ctx, StackFrame frame, ElementInfo e, int index) throws ArrayIndexOutOfBoundsExecutiveException; @Override public boolean isRead() { return true; } @Override public void accept(InstructionVisitor insVisitor) { insVisitor.visit(this); } }