<commit_before>/*
 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package lancet.interpreter


import java.lang.reflect.{Array=>jlrArray,_};

import com.oracle.graal.api._;
import com.oracle.graal.api.meta._;
import com.oracle.graal.hotspot.meta._;
import com.oracle.graal.bytecode._;



trait RuntimeUniverse_Opt extends Core_Opt with RuntimeUniverse_Str {

object static extends HasUnsafe
object unsafe extends Unsafe_Opt


var debugReadWrite = false
var debugNullCheck = false


trait Unsafe_Opt extends Unsafe_Str {

  /*
  def monitorEnter(value: Rep[Object]): Rep[Unit] = 
    reflect("unsafe.monitorEnter("+value+")")
  def monitorExit(value: Rep[Object]): Rep[Unit] = 
    reflect("unsafe.monitorExit("+value+")")
  */

  // TODO: should inspect reflect.Field objects

  def isSafeRead(base: Object, offset: Long, typ: TypeRep[_]): Boolean = {
    if (base == null) {
      println("// base is null, dammit"); false
    } else {
      val unsafePrefixes = "sun.nio."::"java.io."::"java.nio."::Nil
      val safeFields = "java.io.PrintStream.16"::
                       "java.io.PrintStream.40"::
                       "java.io.PrintStream.48"::
                       "java.io.BufferedWriter.32":: /*.40 Int .44 Int */
                       "java.io.BufferedWriter.48"::
                       "java.io.BufferedWriter.56"::
                       "java.io.BufferedWriter.64"::
                       "java.io.OutputStreamWriter.40"::
                       "sun.nio.cs.StreamEncoder.32"::
                       "sun.nio.cs.StreamEncoder.56"::
                       "sun.nio.cs.StreamEncoder.64"::
                       "sun.nio.cs.StreamEncoder.72"::
                       "sun.nio.cs.StreamEncoder.80"::
                       "sun.nio.cs.StreamEncoder.88"::
                       "java.nio.HeapByteBuffer[pos=0 lim=8192 cap=8192].48":: //HACK/FIXME
                       "sun.nio.cs.UTF_8$Encoder.72"::
                       "java.nio.charset.CoderResult$1.16"::
                       Nil
      val str = base.toString
      val lookup = str.replaceAll("@[a-z0-9]+","")+"."+offset
      //println("// " + lookup + "/" + safeFields)
      val r = lookup.startsWith("Class.forName") || safeFields.contains(lookup) || !unsafePrefixes.exists(str startsWith _)
      if (debugReadWrite) {
        val pred = if (r) "safe" else "unsafe"
        println("// " + pred + " read: " + base.toString.replace("\n","\\n") + "." + offset + ":" + typ)
      }
      r
    }
  }


  override def getObject(base: Rep[Object], offset: Rep[Long]): Rep[Object] = (eval(base), eval(offset)) match {
    case (Const(base), Const(offset)) if isSafeRead(base, offset, typeRep[Object]) =>
      unit(static.unsafe.getObject(base,offset))
    case (Partial(fs), Const(offset)) => 
      def default = fs("alloc") match {
        case Static(base1:Object) => 
          if (isSafeRead(base1, offset, typeRep[Object])) unit(static.unsafe.getObject(base1,offset))
          else super.getObject(base, offset)
        case _ => unit(null)
      }
      fs.getOrElse(offset.toString, default).asInstanceOf[Rep[Object]]
    case _ => super.getObject(base,offset)
  }
    
/*
  def getObjectVolatile(base: Rep[Object], offset: Rep[Long]): Rep[Object] = 
    reflect("unsafe.getObjectVolatile("+base+","+offset+")")
*/
  override def getBoolean(base: Rep[Object], offset: Rep[Long]): Rep[Boolean] = (eval(base), eval(offset)) match {
    case (Const(base), Const(offset)) if isSafeRead(base, offset, typeRep[Int]) => 
      unit(static.unsafe.getBoolean(base,offset))
    case (Partial(fs), Const(offset)) => 
      def default = fs("alloc") match {
        case Static(base1:Object) => 
          if (isSafeRead(base1, offset, typeRep[Boolean])) unit(static.unsafe.getBoolean(base1,offset))
          else super.getBoolean(base, offset)
        case _ => unit(false)
      }
      fs.get(offset.toString).
        map(x=>objectAsInstanceOf[Boolean](x.asInstanceOf[Rep[Object]])).
        getOrElse(default) // value stored will be int, not bool
    case _ => super.getBoolean(base, offset)
  }

  override def getBooleanVolatile(base: Rep[Object], offset: Rep[Long]): Rep[Boolean] = {
    // HACK !!
    if (base+","+offset == "Class.forName(\"sun.misc.VM\").asInstanceOf[Object],261.asInstanceOf[Long]") unit(true)
    else super.getBooleanVolatile(base, offset)
  }
/*
  def getByte(base: Rep[Object], offset: Rep[Long]): Rep[Byte] = 
    reflect("unsafe.getByte("+base+","+offset+")")
  def getByteVolatile(base: Rep[Object], offset: Rep[Long]): Rep[Byte] = 
    reflect("unsafe.getByteVolatile("+base+","+offset+")")

  def getChar(base: Rep[Object], offset: Rep[Long]): Rep[Char] = 
    reflect("unsafe.getChar("+base+","+offset+")")
  def getCharVolatile(base: Rep[Object], offset: Rep[Long]): Rep[Char] = 
    reflect("unsafe.getCharVolatile("+base+","+offset+")")

  def getShort(base: Rep[Object], offset: Rep[Long]): Rep[Short] = 
    reflect("unsafe.getShort("+base+","+offset+")")
  def getShortVolatile(base: Rep[Object], offset: Rep[Long]): Rep[Short] = 
    reflect("unsafe.getShortVolatile("+base+","+offset+")")
*/

  override def getInt(base: Rep[Object], offset: Rep[Long]): Rep[Int] = (eval(base), eval(offset)) match {
    case (Const(base), Const(offset)) if isSafeRead(base, offset, typeRep[Int]) => <commit_msg>fix cast in getBoolean<commit_after>/*
 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package lancet.interpreter


import java.lang.reflect.{Array=>jlrArray,_};

import com.oracle.graal.api._;
import com.oracle.graal.api.meta._;
import com.oracle.graal.hotspot.meta._;
import com.oracle.graal.bytecode._;



trait RuntimeUniverse_Opt extends Core_Opt with RuntimeUniverse_Str {

object static extends HasUnsafe
object unsafe extends Unsafe_Opt


var debugReadWrite = false
var debugNullCheck = false


trait Unsafe_Opt extends Unsafe_Str {

  /*
  def monitorEnter(value: Rep[Object]): Rep[Unit] = 
    reflect("unsafe.monitorEnter("+value+")")
  def monitorExit(value: Rep[Object]): Rep[Unit] = 
    reflect("unsafe.monitorExit("+value+")")
  */

  // TODO: should inspect reflect.Field objects

  def isSafeRead(base: Object, offset: Long, typ: TypeRep[_]): Boolean = {
    if (base == null) {
      println("// base is null, dammit"); false
    } else {
      val unsafePrefixes = "sun.nio."::"java.io."::"java.nio."::Nil
      val safeFields = "java.io.PrintStream.16"::
                       "java.io.PrintStream.40"::
                       "java.io.PrintStream.48"::
                       "java.io.BufferedWriter.32":: /*.40 Int .44 Int */
                       "java.io.BufferedWriter.48"::
                       "java.io.BufferedWriter.56"::
                       "java.io.BufferedWriter.64"::
                       "java.io.OutputStreamWriter.40"::
                       "sun.nio.cs.StreamEncoder.32"::
                       "sun.nio.cs.StreamEncoder.56"::
                       "sun.nio.cs.StreamEncoder.64"::
                       "sun.nio.cs.StreamEncoder.72"::
                       "sun.nio.cs.StreamEncoder.80"::
                       "sun.nio.cs.StreamEncoder.88"::
                       "java.nio.HeapByteBuffer[pos=0 lim=8192 cap=8192].48":: //HACK/FIXME
                       "sun.nio.cs.UTF_8$Encoder.72"::
                       "java.nio.charset.CoderResult$1.16"::
                       Nil
      val str = base.toString
      val lookup = str.replaceAll("@[a-z0-9]+","")+"."+offset
      //println("// " + lookup + "/" + safeFields)
      val r = lookup.startsWith("Class.forName") || safeFields.contains(lookup) || !unsafePrefixes.exists(str startsWith _)
      if (debugReadWrite) {
        val pred = if (r) "safe" else "unsafe"
        println("// " + pred + " read: " + base.toString.replace("\n","\\n") + "." + offset + ":" + typ)
      }
      r
    }
  }


  override def getObject(base: Rep[Object], offset: Rep[Long]): Rep[Object] = (eval(base), eval(offset)) match {
    case (Const(base), Const(offset)) if isSafeRead(base, offset, typeRep[Object]) =>
      unit(static.unsafe.getObject(base,offset))
    case (Partial(fs), Const(offset)) => 
      def default = fs("alloc") match {
        case Static(base1:Object) => 
          if (isSafeRead(base1, offset, typeRep[Object])) unit(static.unsafe.getObject(base1,offset))
          else super.getObject(base, offset)
        case _ => unit(null)
      }
      fs.getOrElse(offset.toString, default).asInstanceOf[Rep[Object]]
    case _ => super.getObject(base,offset)
  }
    
/*
  def getObjectVolatile(base: Rep[Object], offset: Rep[Long]): Rep[Object] = 
    reflect("unsafe.getObjectVolatile("+base+","+offset+")")
*/
  override def getBoolean(base: Rep[Object], offset: Rep[Long]): Rep[Boolean] = (eval(base), eval(offset)) match {
    case (Const(base), Const(offset)) if isSafeRead(base, offset, typeRep[Int]) => 
      unit(static.unsafe.getBoolean(base,offset))
    case (Partial(fs), Const(offset)) => 
      def default = fs("alloc") match {
        case Static(base1:Object) => 
          if (isSafeRead(base1, offset, typeRep[Boolean])) unit(static.unsafe.getBoolean(base1,offset))
          else super.getBoolean(base, offset)
        case _ => unit(false)
      }
      fs.get(offset.toString).
        map{x=>if(x.typ==typeRep[Int]) (x.asInstanceOf[Rep[Int]] === 1) else x.asInstanceOf[Rep[Boolean]]}.
        getOrElse(default) // value stored will be int, not bool (not quite sure why exactly)
    case _ => super.getBoolean(base, offset)
  }

  override def getBooleanVolatile(base: Rep[Object], offset: Rep[Long]): Rep[Boolean] = {
    // HACK !!
    if (base+","+offset == "Class.forName(\"sun.misc.VM\").asInstanceOf[Object],261.asInstanceOf[Long]") unit(true)
    else super.getBooleanVolatile(base, offset)
  }
/*
  def getByte(base: Rep[Object], offset: Rep[Long]): Rep[Byte] = 
    reflect("unsafe.getByte("+base+","+offset+")")
  def getByteVolatile(base: Rep[Object], offset: Rep[Long]): Rep[Byte] = 
    reflect("unsafe.getByteVolatile("+base+","+offset+")")

  def getChar(base: Rep[Object], offset: Rep[Long]): Rep[Char] = 
    reflect("unsafe.getChar("+base+","+offset+")")
  def getCharVolatile(base: Rep[Object], offset: Rep[Long]): Rep[Char] = 
    reflect("unsafe.getCharVolatile("+base+","+offset+")")

  def getShort(base: Rep[Object], offset: Rep[Long]): Rep[Short] = 
    reflect("unsafe.getShort("+base+","+offset+")")
  def getShortVolatile(base: Rep[Object], offset: Rep[Long]): Rep[Short] = 
    reflect("unsafe.getShortVolatile("+base+","+offset+")")
*/

  override def getInt(base: Rep[Object], offset: Rep[Long]): Rep[Int] = (eval(base), eval(offset)) match {
    case (Const(base), Const(offset)) if isSafeRead(base, offset, typeRep[Int]) => 
{'fraction_non_alphanumeric': 0.1515413652091853, 'fraction_numerical': 0.01360490720352312, 'mean_word_length': 3.060344827586207, 'pattern_counts': {'":': 42, '<': 3, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '1365463', 'n_tokens_mistral': 4123, 'n_tokens_neox': 3860, 'n_words': 944}