/* BSD 2-Clause License - see OPAL/LICENSE for details. */ package org.opalj package ai package domain import org.opalj.br.Code import org.opalj.br.instructions.NEW import org.opalj.br.instructions.INVOKESPECIAL import org.opalj.ai.collectPCWithOperands /** * Commonly useful methods. * * @author Michael Eichberg */ package object l1 { /** * @note At the bytecode level, the allocation of memory and the call of the * constructor are not atomic and it is possible to associate one "new" * instruction with multiple constructor calls (INVOKESPECIAL(...,"",...)); * however, such code is not generated by any known compiler so far (Dec. 2014). */ def constructorCallForNewReferenceValueWithOrigin( code: Code, receiverOriginPC: Int, domain: l1.ReferenceValues )( operandsArray: domain.OperandsArray ): Seq[Int /*PC*/ ] = { // IMPROVE Ues Int based datastructure val instructions = code.instructions assert( receiverOriginPC >= 0 && receiverOriginPC < instructions.length, s"the origin $receiverOriginPC is outside the scope of the method " ) assert( instructions(receiverOriginPC).opcode == NEW.opcode, s"${instructions(receiverOriginPC)} is not a NEW instruction" ) assert( operandsArray(receiverOriginPC) ne null, s"the (new) instruction with pc=$receiverOriginPC was never executed" ) // as usual in OPAL, we assume that the bytecode is valid; i.e., there will // be one constructor call collectPCWithOperands(domain)(code, operandsArray) { case (pc, INVOKESPECIAL(_, _, "", md), operands) if operands.size >= md.parametersCount && domain.asObjectValue(operands(md.parametersCount)).origin == receiverOriginPC => pc } } }