<commit_before>/*
 * Scala (https://www.scala-lang.org)
 *
 * Copyright EPFL and Lightbend, Inc.
 *
 * Licensed under Apache License 2.0
 * (http://www.apache.org/licenses/LICENSE-2.0).
 *
 * See the NOTICE file distributed with this work for
 * additional information regarding copyright ownership.
 */

package scala.tools.nsc
package backend.jvm

import scala.reflect.internal.Flags.{DEFERRED, SYNTHESIZE_IMPL_IN_SUBCLASS}
import scala.tools.asm
import scala.tools.nsc.backend.jvm.BTypes._
import scala.tools.nsc.backend.jvm.BackendReporting._

/**
 * This class mainly contains the method classBTypeFromSymbol, which extracts the necessary
 * information from a symbol and its type to create the corresponding ClassBType. It requires
 * access to the compiler (global parameter).
 */
abstract class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
  val frontendAccess: PostProcessorFrontendAccess

  import global._
  import definitions._
  import genBCode._
  import codeGen.CodeGenImpl._
  import postProcessor.{bTypesFromClassfile, byteCodeRepository}

  val coreBTypes = new CoreBTypesFromSymbols[G] {
    val bTypes: BTypesFromSymbols.this.type = BTypesFromSymbols.this
  }
  import coreBTypes._

  final def initialize(): Unit = {
    coreBTypes.initialize()
  }

  // helpers that need access to global.
  // TODO @lry create a separate component, they don't belong to BTypesFromSymbols

  final val strMODULE_INSTANCE_FIELD = nme.MODULE_INSTANCE_FIELD.toString

  private val primitiveCompilationUnits = Set(
    "Unit.scala",
    "Boolean.scala",
    "Char.scala",
    "Byte.scala",
    "Short.scala",
    "Int.scala",
    "Float.scala",
    "Long.scala",
    "Double.scala"
  )

  /**
   * True if the current compilation unit is of a primitive class (scala.Boolean et al).
   * Used only in assertions.
   */
  def isCompilingPrimitive = {
    primitiveCompilationUnits(currentUnit.source.file.name)
  }

  def isCompilingArray = {
    currentUnit.source.file.name == "Array.scala"
  }

  // end helpers

  /**
   * The ClassBType for a class symbol `classSym`.
   *
   * The class symbol scala.Nothing is mapped to the class scala.runtime.Nothing$. Similarly,
   * scala.Null is mapped to scala.runtime.Null$. This is because there exist no class files
   * for the Nothing / Null. If used for example as a parameter type, we use the runtime classes
   * in the classfile method signature.
   */
  final def classBTypeFromSymbol(sym: Symbol): ClassBType = {
    // For each java class, the scala compiler creates a class and a module (thus a module class).
    // If the `sym` is a java module class, we use the java class instead. This ensures that the
    // ClassBType is created from the main class (instead of the module class).
    // The two symbols have the same name, so the resulting internalName is the same.
    // Phase travel (exitingPickler) required for scala/bug#6613 - linkedCoC is only reliable in early phases (nesting)
    val classSym = if (sym.isJavaDefined && sym.isModuleClass) exitingPickler(sym.linkedClassOfClass) else sym

    assert(classSym != NoSymbol, "Cannot create ClassBType from NoSymbol")
    assert(classSym.isClass, s"Cannot create ClassBType from non-class symbol $classSym")
    if (global.settings.debug) {
      // OPT these assertions have too much performance overhead to run unconditionally
      assertClassNotArrayNotPrimitive(classSym)
      assert(!primitiveTypeToBType.contains(classSym) || isCompilingPrimitive, s"Cannot create ClassBType for primitive class symbol $classSym")
    }

    if (classSym == NothingClass) srNothingRef
    else if (classSym == NullClass) srNullRef
    else {
      val internalName = classSym.javaBinaryNameString
      // The new ClassBType is added to the map via its apply, before we set its info. This
      // allows initializing cyclic dependencies, see the comment on variable ClassBType._info.
      ClassBType(internalName, fromSymbol = true) { res:ClassBType =>
        if (completeSilentlyAndCheckErroneous(classSym))
          Left(NoClassBTypeInfoClassSymbolInfoFailedSI9111(classSym.fullName))
        else computeClassInfo(classSym, res)
      }
    }
  }

  /**
   * Builds a [[MethodBType]] for a method symbol.
   */
  final def methodBTypeFromSymbol(methodSymbol: Symbol): MethodBType = {
    assert(methodSymbol.isMethod, s"not a method-symbol: $methodSymbol")
    methodBTypeFromMethodType(methodSymbol.info, methodSymbol.isClassConstructor || methodSymbol.isConstructor)
  }

  /**
   * Builds a [[MethodBType]] for a method type.
   */
  final def methodBTypeFromMethodType(tpe: Type, isConstructor: Boolean): MethodBType = {
    val resultType: BType =
      if (isConstructor) UNIT
      else typeToBType(tpe.resultType)
    MethodBType(tpe.paramTypes map typeToBType, resultType)
  }

  def bootstrapMethodArg(t: Constant, pos: Position): AnyRef = t match {
    case Constant(mt: Type) => methodBTypeFromMethodType(transformedType(mt), isConstructor = false).toASMType
    case c @ Constant(sym: Symbol) => staticHandleFromSymbol(sym)
    case c @ Constant(value: String) => value
    case c @ Constant(value) if c.isNonUnitAnyVal => c.value.asInstanceOf[AnyRef]
    case _ => reporter.error(pos, "Unable to convert static argument of ApplyDynamic into a classfile constant: " + t); null
  }

  def staticHandleFromSymbol(sym: Symbol): asm.Handle = {
    val owner = if (sym.owner.isModuleClass) sym.owner.linkedClassOfClass else sym.owner
    val descriptor = methodBTypeFromMethodType(sym.info, isConstructor = false).descriptor
    val ownerBType = classBTypeFromSymbol(owner)
    new asm.Handle(asm.Opcodes.H_INVOKESTATIC, ownerBType.internalName, sym.name.encoded, descriptor, /* itf = */ ownerBType.isInterface.get)
  }

  /**
   * This method returns the BType for a type reference, for example a parameter type.
   */
  final def typeToBType(t: Type): BType = {
    import definitions.ArrayClass

    /**
     * Primitive types are represented as TypeRefs to the class symbol of, for example, scala.Int.
     * The `primitiveTypeMap` maps those class symbols to the corresponding PrimitiveBType.
     */<commit_msg>Thread the needle of static handle ownership<commit_after>/*
 * Scala (https://www.scala-lang.org)
 *
 * Copyright EPFL and Lightbend, Inc.
 *
 * Licensed under Apache License 2.0
 * (http://www.apache.org/licenses/LICENSE-2.0).
 *
 * See the NOTICE file distributed with this work for
 * additional information regarding copyright ownership.
 */

package scala.tools.nsc
package backend.jvm

import scala.reflect.internal.Flags.{DEFERRED, SYNTHESIZE_IMPL_IN_SUBCLASS}
import scala.tools.asm
import scala.tools.nsc.backend.jvm.BTypes._
import scala.tools.nsc.backend.jvm.BackendReporting._

/**
 * This class mainly contains the method classBTypeFromSymbol, which extracts the necessary
 * information from a symbol and its type to create the corresponding ClassBType. It requires
 * access to the compiler (global parameter).
 */
abstract class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
  val frontendAccess: PostProcessorFrontendAccess

  import global._
  import definitions._
  import genBCode._
  import codeGen.CodeGenImpl._
  import postProcessor.{bTypesFromClassfile, byteCodeRepository}

  val coreBTypes = new CoreBTypesFromSymbols[G] {
    val bTypes: BTypesFromSymbols.this.type = BTypesFromSymbols.this
  }
  import coreBTypes._

  final def initialize(): Unit = {
    coreBTypes.initialize()
  }

  // helpers that need access to global.
  // TODO @lry create a separate component, they don't belong to BTypesFromSymbols

  final val strMODULE_INSTANCE_FIELD = nme.MODULE_INSTANCE_FIELD.toString

  private val primitiveCompilationUnits = Set(
    "Unit.scala",
    "Boolean.scala",
    "Char.scala",
    "Byte.scala",
    "Short.scala",
    "Int.scala",
    "Float.scala",
    "Long.scala",
    "Double.scala"
  )

  /**
   * True if the current compilation unit is of a primitive class (scala.Boolean et al).
   * Used only in assertions.
   */
  def isCompilingPrimitive = {
    primitiveCompilationUnits(currentUnit.source.file.name)
  }

  def isCompilingArray = {
    currentUnit.source.file.name == "Array.scala"
  }

  // end helpers

  /**
   * The ClassBType for a class symbol `classSym`.
   *
   * The class symbol scala.Nothing is mapped to the class scala.runtime.Nothing$. Similarly,
   * scala.Null is mapped to scala.runtime.Null$. This is because there exist no class files
   * for the Nothing / Null. If used for example as a parameter type, we use the runtime classes
   * in the classfile method signature.
   */
  final def classBTypeFromSymbol(sym: Symbol): ClassBType = {
    // For each java class, the scala compiler creates a class and a module (thus a module class).
    // If the `sym` is a java module class, we use the java class instead. This ensures that the
    // ClassBType is created from the main class (instead of the module class).
    // The two symbols have the same name, so the resulting internalName is the same.
    // Phase travel (exitingPickler) required for scala/bug#6613 - linkedCoC is only reliable in early phases (nesting)
    val classSym = if (sym.isJavaDefined && sym.isModuleClass) exitingPickler(sym.linkedClassOfClass) else sym

    assert(classSym != NoSymbol, "Cannot create ClassBType from NoSymbol")
    assert(classSym.isClass, s"Cannot create ClassBType from non-class symbol $classSym")
    if (global.settings.debug) {
      // OPT these assertions have too much performance overhead to run unconditionally
      assertClassNotArrayNotPrimitive(classSym)
      assert(!primitiveTypeToBType.contains(classSym) || isCompilingPrimitive, s"Cannot create ClassBType for primitive class symbol $classSym")
    }

    if (classSym == NothingClass) srNothingRef
    else if (classSym == NullClass) srNullRef
    else {
      val internalName = classSym.javaBinaryNameString
      // The new ClassBType is added to the map via its apply, before we set its info. This
      // allows initializing cyclic dependencies, see the comment on variable ClassBType._info.
      ClassBType(internalName, fromSymbol = true) { res:ClassBType =>
        if (completeSilentlyAndCheckErroneous(classSym))
          Left(NoClassBTypeInfoClassSymbolInfoFailedSI9111(classSym.fullName))
        else computeClassInfo(classSym, res)
      }
    }
  }

  /**
   * Builds a [[MethodBType]] for a method symbol.
   */
  final def methodBTypeFromSymbol(methodSymbol: Symbol): MethodBType = {
    assert(methodSymbol.isMethod, s"not a method-symbol: $methodSymbol")
    methodBTypeFromMethodType(methodSymbol.info, methodSymbol.isClassConstructor || methodSymbol.isConstructor)
  }

  /**
   * Builds a [[MethodBType]] for a method type.
   */
  final def methodBTypeFromMethodType(tpe: Type, isConstructor: Boolean): MethodBType = {
    val resultType: BType =
      if (isConstructor) UNIT
      else typeToBType(tpe.resultType)
    MethodBType(tpe.paramTypes map typeToBType, resultType)
  }

  def bootstrapMethodArg(t: Constant, pos: Position): AnyRef = t match {
    case Constant(mt: Type) => methodBTypeFromMethodType(transformedType(mt), isConstructor = false).toASMType
    case c @ Constant(sym: Symbol) => staticHandleFromSymbol(sym)
    case c @ Constant(value: String) => value
    case c @ Constant(value) if c.isNonUnitAnyVal => c.value.asInstanceOf[AnyRef]
    case _ => reporter.error(pos, "Unable to convert static argument of ApplyDynamic into a classfile constant: " + t); null
  }

  def staticHandleFromSymbol(sym: Symbol): asm.Handle = {
    val descriptor = methodBTypeFromMethodType(sym.info, isConstructor = false).descriptor
    val ownerBType = classBTypeFromSymbol(sym.owner)
    val rawInternalName = ownerBType.internalName
    // object Qux { def foo = 1 } --> we want the handle to be to (static) Qux.foo, not (member) Qux$.foo
    val mustUseMirrorClass = !sym.isJava && sym.owner.isModuleClass && !sym.isStaticMember
    // ... but we don't know that the mirror class exists! (if there's no companion, the class is synthesized in jvm without a symbol)
    val ownerInternalName = if (mustUseMirrorClass) rawInternalName stripSuffix nme.MODULE_SUFFIX_STRING else rawInternalName
    val isInterface = sym.owner.linkedClassOfClass.isTraitOrInterface
    new asm.Handle(asm.Opcodes.H_INVOKESTATIC, ownerInternalName, sym.name.encoded, descriptor, isInterface)
  }

  /**
   * This method returns the BType for a type reference, for example a parameter type.
   */
  final def typeToBType(t: Type): BType = {
    import definitions.ArrayClass

    /**
     * Primitive types are represented as TypeRefs to the class symbol of, for example, scala.Int.
     * The `primitiveTypeMap` maps those class symbols to the corresponding PrimitiveBType.
     */
{'fraction_non_alphanumeric': 0.08808613560115472, 'fraction_numerical': 0.001950534446438324, 'mean_word_length': 3.782835820895522, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 16, 'https://': 2, 'lorem ipsum': 0, 'www.': 4, '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': '6271786', 'n_tokens_mistral': 3779, 'n_tokens_neox': 3699, 'n_words': 1183}