<commit_before>/* This library handles message serialization for communicating between
 * tools */
package org.ucombinator.jaam.messaging

import java.io.InputStream
import java.io.OutputStream
import scala.collection.mutable.ArrayBuffer
import de.javakaffee.kryoserializers._
import com.esotericsoftware.minlog.Log
import com.esotericsoftware.kryo._
import com.esotericsoftware.kryo.io._
import com.twitter.chill.ScalaKryoInstantiator
import soot.{Unit => _, _}
import soot.jimple.{Stmt => SootStmt}


////////////////////////////////////////
// Methods and types for reading and writing message
////////////////////////////////////////

object Message {
  // Types for reading and writing messages
  // These extend from Kryo instead of a type alias to keep Java happy
  class Input(in : InputStream) extends com.esotericsoftware.kryo.io.Input(in) {
    var isRead : Boolean = false
    var ms : Array[Message] = Array.empty[Message]
    var index : Int = 0
    def pop() : Message = {
      if (index <= ms.size) {
        val m = ms(index)
        index += 1
        return m
      }
      Done()
    }
  }

  class Output(out : OutputStream) extends com.esotericsoftware.kryo.io.Output(out) {
    val buf: ArrayBuffer[Message] = ArrayBuffer.empty[Message]
    def append(m : Message): Unit = {
      buf += m
    }
    override def close() : Unit = {
      //println("size of buf: " + buf.size)
      append(Done())
      kryo.writeClassAndObject(this, buf.toArray)
      super.close()
    }
  }

  // Lift an InputStream to Message.Input
  def openInput(in : InputStream) : Input =
    new Input(in)

  // Lift an OutputStream to Message.Output
  def openOutput(out : OutputStream) : Output =
    new Output(out)

  // Reads a 'Message' from 'in'
  // TODO: check for exceptions
  def read(in : Input) : Message = {
    if (in.isRead) in.pop
    else {
      kryo.readClassAndObject(in) match {
        case ms : Array[Message] => 
          in.ms = ms
          in.isRead = true
        case _ => throw new Exception("TODO: Message.read failed")
      }
      read(in)
    }
  }

  // Writes the 'Message' 'm' to 'out'
  def write(out : Output, m : Message) : Unit = {
    out.append(m)
  }

  // Initialize Kryo
  val instantiator = new ScalaKryoInstantiator
  val kryo = instantiator.newKryo()
  kryo.addDefaultSerializer(classOf[soot.util.Chain[java.lang.Object]], classOf[com.esotericsoftware.kryo.serializers.FieldSerializer[java.lang.Object]])
  UnmodifiableCollectionsSerializer.registerSerializers(kryo)
}


////////////////////////////////////////
// Message types
////////////////////////////////////////

// The super type of all messages
abstract class Message {}

// Signals that all messages are done
// TODO: check if "object" is okay here
case class Done() extends Message {}

// Declare a transition edge between two 'State' nodes
case class Edge(id : Id[Edge], src : Id[AbstractState], dst : Id[AbstractState]) extends Message {}

// Declare 'AbstractState' nodes
abstract class AbstractState(id : Id[AbstractState]) extends Message {}
case class ErrorState(id : Id[AbstractState]) extends AbstractState(id) {}
case class State(id : Id[AbstractState], stmt : Stmt, framePointer : String, kontStack : String) extends AbstractState(id) {}


////////////////////////////////////////
// Types inside messages
////////////////////////////////////////

// Identifiers qualified by a namespace
case class Id[Namespace](id : Int) {
  // val namespace = classOf[Namespace]
}

// Type for statements (needed because 'SootStmt' doesn't specify the
// 'SootMethod' that it is in)
case class Stmt(stmt : SootStmt, method : SootMethod) {}


/*


AbstractState
  ErrorState
  State(Stmt, FramePointer, KontStack)

Stmt(SootStmt, SootMethod)


FramePointer
  InvariantFramePointer
  ZeroCFAFramePointer(SootMethod)
  OneCFAFramePointer(SootMethod, Stmt)
  InitialFramePointer

From
  FromNative
  FromJava

BasePointer
  OneCFABasePointer(Stmt, FramePointer, From)
  InitialBasePointer
  StringBasePointer(String)
  ClassBasePointer(String)

Value
  AtomicValue
    AnyAtomicValue<commit_msg>Added index to messaging Stmt<commit_after>/* This library handles message serialization for communicating between
 * tools */
package org.ucombinator.jaam.messaging

import java.io.InputStream
import java.io.OutputStream
import scala.collection.mutable.ArrayBuffer
import de.javakaffee.kryoserializers._
import com.esotericsoftware.minlog.Log
import com.esotericsoftware.kryo._
import com.esotericsoftware.kryo.io._
import com.twitter.chill.ScalaKryoInstantiator
import soot.{Unit => _, _}
import soot.jimple.{Stmt => SootStmt}


////////////////////////////////////////
// Methods and types for reading and writing message
////////////////////////////////////////

object Message {
  // Types for reading and writing messages
  // These extend from Kryo instead of a type alias to keep Java happy
  class Input(in : InputStream) extends com.esotericsoftware.kryo.io.Input(in) {
    var isRead : Boolean = false
    var ms : Array[Message] = Array.empty[Message]
    var index : Int = 0
    def pop() : Message = {
      if (index <= ms.size) {
        val m = ms(index)
        index += 1
        return m
      }
      Done()
    }
  }

  class Output(out : OutputStream) extends com.esotericsoftware.kryo.io.Output(out) {
    val buf: ArrayBuffer[Message] = ArrayBuffer.empty[Message]
    def append(m : Message): Unit = {
      buf += m
    }
    override def close() : Unit = {
      //println("size of buf: " + buf.size)
      append(Done())
      kryo.writeClassAndObject(this, buf.toArray)
      super.close()
    }
  }

  // Lift an InputStream to Message.Input
  def openInput(in : InputStream) : Input =
    new Input(in)

  // Lift an OutputStream to Message.Output
  def openOutput(out : OutputStream) : Output =
    new Output(out)

  // Reads a 'Message' from 'in'
  // TODO: check for exceptions
  def read(in : Input) : Message = {
    if (in.isRead) in.pop
    else {
      kryo.readClassAndObject(in) match {
        case ms : Array[Message] => 
          in.ms = ms
          in.isRead = true
        case _ => throw new Exception("TODO: Message.read failed")
      }
      read(in)
    }
  }

  // Writes the 'Message' 'm' to 'out'
  def write(out : Output, m : Message) : Unit = {
    out.append(m)
  }

  // Initialize Kryo
  val instantiator = new ScalaKryoInstantiator
  val kryo = instantiator.newKryo()
  kryo.addDefaultSerializer(classOf[soot.util.Chain[java.lang.Object]], classOf[com.esotericsoftware.kryo.serializers.FieldSerializer[java.lang.Object]])
  UnmodifiableCollectionsSerializer.registerSerializers(kryo)
}


////////////////////////////////////////
// Message types
////////////////////////////////////////

// The super type of all messages
abstract class Message {}

// Signals that all messages are done
// TODO: check if "object" is okay here
case class Done() extends Message {}

// Declare a transition edge between two 'State' nodes
case class Edge(id : Id[Edge], src : Id[AbstractState], dst : Id[AbstractState]) extends Message {}

// Declare 'AbstractState' nodes
abstract class AbstractState(id : Id[AbstractState]) extends Message {}
case class ErrorState(id : Id[AbstractState]) extends AbstractState(id) {}
case class State(id : Id[AbstractState], stmt : Stmt, framePointer : String, kontStack : String) extends AbstractState(id) {}


////////////////////////////////////////
// Types inside messages
////////////////////////////////////////

// Identifiers qualified by a namespace
case class Id[Namespace](id : Int) {
  // val namespace = classOf[Namespace]
}

// Type for statements (needed because 'SootStmt' doesn't specify the
// 'SootMethod' that it is in)
case class Stmt(method : SootMethod, index : Int, stmt : SootStmt) {}


/*


AbstractState
  ErrorState
  State(Stmt, FramePointer, KontStack)

Stmt(SootStmt, SootMethod)


FramePointer
  InvariantFramePointer
  ZeroCFAFramePointer(SootMethod)
  OneCFAFramePointer(SootMethod, Stmt)
  InitialFramePointer

From
  FromNative
  FromJava

BasePointer
  OneCFABasePointer(Stmt, FramePointer, From)
  InitialBasePointer
  StringBasePointer(String)
  ClassBasePointer(String)

Value
  AtomicValue
    AnyAtomicValue
{'fraction_non_alphanumeric': 0.15453772324140444, 'fraction_numerical': 0.0004859676831490706, 'mean_word_length': 2.721518987341772, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1221664', 'n_tokens_mistral': 2476, 'n_tokens_neox': 2424, 'n_words': 675}