<commit_before>package gololang.compiler;

import gololang.compiler.ir.*;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;

import java.util.Set;
import java.util.Stack;

import static gololang.compiler.ir.GoloFunction.Visibility.PUBLIC;
import static org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;
import static org.objectweb.asm.ClassWriter.COMPUTE_MAXS;
import static org.objectweb.asm.Opcodes.*;

class JavaBytecodeGenerationGoloIrVisitor implements GoloIrVisitor {

  private static final String JOBJECT = "java/lang/Object";
  private static final String TOBJECT = "Ljava/lang/Object;";
  private static final Handle FUNCTION_INVOCATION_HANDLE;

  static {
    String bootstrapOwner = "gololang/runtime/InvokeDynamicSupport";
    String bootstraper = "bootstrapFunctionInvocation";
    String description = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;";
    FUNCTION_INVOCATION_HANDLE = new Handle(H_INVOKESTATIC, bootstrapOwner, bootstraper, description);
  }

  private ClassWriter classWriter;
  private MethodVisitor methodVisitor;
  private String sourceFilename;
  private Context context;

  private static class Context {
    private Stack<ReferenceTable> referenceTableStack = new Stack<>();
    private Stack<Integer> methodArityStack = new Stack<>();
  }

  public byte[] toBytecode(GoloModule module, String sourceFilename) {
    this.sourceFilename = sourceFilename;
    this.classWriter = new ClassWriter(COMPUTE_FRAMES | COMPUTE_MAXS);
    this.context = new Context();
    module.accept(this);
    return classWriter.toByteArray();
  }

  @Override
  public void visitModule(GoloModule module) {
    classWriter.visit(V1_7, ACC_PUBLIC, module.getPackageAndClass().toJVMType(), null, JOBJECT, null);
    classWriter.visitSource(sourceFilename, null);
    writeImportMetaData(module.getImports());
    for (GoloFunction function : module.getFunctions().values()) {
      function.accept(this);
    }
    classWriter.visitEnd();
  }

  private void writeImportMetaData(Set<ModuleImport> imports) {
    ModuleImport[] importsArray = imports.toArray(new ModuleImport[imports.size()]);
    methodVisitor = classWriter.visitMethod(
        ACC_PUBLIC | ACC_STATIC,
        "$imports",
        "()[Ljava/lang/String;",
        null, null);
    methodVisitor.visitCode();
    methodVisitor.visitLdcInsn(importsArray.length);
    methodVisitor.visitTypeInsn(ANEWARRAY, "java/lang/String");
    for (int i = 0; i < importsArray.length; i++) {
      methodVisitor.visitInsn(DUP);
      methodVisitor.visitLdcInsn(i);
      methodVisitor.visitLdcInsn(importsArray[i].getPackageAndClass().toString());
      methodVisitor.visitInsn(AASTORE);
    }
    methodVisitor.visitInsn(ARETURN);
    methodVisitor.visitMaxs(0, 0);
    methodVisitor.visitEnd();
  }

  @Override
  public void visitFunction(GoloFunction function) {
    int visibility = (function.getVisibility() == PUBLIC) ? ACC_PUBLIC : ACC_PRIVATE;
    context.methodArityStack.push(function.getArity());
    methodVisitor = classWriter.visitMethod(
        visibility | ACC_STATIC,
        function.getName(),
        goloFunctionSignature(function.getArity()),
        null, null);
    methodVisitor.visitCode();
    function.getBlock().accept(this);
    methodVisitor.visitMaxs(0, 0);
    methodVisitor.visitEnd();
    context.methodArityStack.pop();
  }

  private String goloFunctionSignature(int arity) {
    StringBuilder descriptorBuilder = new StringBuilder("(");
    for (int i = 0; i < arity; i++) {
      descriptorBuilder.append(TOBJECT);
    }
    descriptorBuilder.append(")").append(TOBJECT);
    return descriptorBuilder.toString();
  }

  @Override
  public void visitBlock(Block block) {
    ReferenceTable referenceTable = block.getReferenceTable();
    context.referenceTableStack.push(referenceTable);
    Label blockStart = new Label();
    Label blockEnd = new Label();
    methodVisitor.visitLabel(blockStart);
    final int lastParameterIndex = context.methodArityStack.peek() - 1;
    for (LocalReference localReference : referenceTable.ownedReferences()) {
      if (localReference.getIndex() > lastParameterIndex) {
        methodVisitor.visitLocalVariable(localReference.getName(), TOBJECT, null,
            blockStart, blockEnd, localReference.getIndex());
      }
    }
    for (GoloStatement statement : block.getStatements()) {<commit_msg>Move the block labels allocation to the caller.<commit_after>package gololang.compiler;

import gololang.compiler.ir.*;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;

import java.util.Set;
import java.util.Stack;

import static gololang.compiler.ir.GoloFunction.Visibility.PUBLIC;
import static org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;
import static org.objectweb.asm.ClassWriter.COMPUTE_MAXS;
import static org.objectweb.asm.Opcodes.*;

class JavaBytecodeGenerationGoloIrVisitor implements GoloIrVisitor {

  private static final String JOBJECT = "java/lang/Object";
  private static final String TOBJECT = "Ljava/lang/Object;";
  private static final Handle FUNCTION_INVOCATION_HANDLE;

  static {
    String bootstrapOwner = "gololang/runtime/InvokeDynamicSupport";
    String bootstraper = "bootstrapFunctionInvocation";
    String description = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;";
    FUNCTION_INVOCATION_HANDLE = new Handle(H_INVOKESTATIC, bootstrapOwner, bootstraper, description);
  }

  private ClassWriter classWriter;
  private MethodVisitor methodVisitor;
  private String sourceFilename;
  private Context context;

  private static class Context {
    private Stack<ReferenceTable> referenceTableStack = new Stack<>();
    private Stack<Integer> methodArityStack = new Stack<>();
    private Label nextBlockStart;
    private Label nextBlockEnd;
  }

  public byte[] toBytecode(GoloModule module, String sourceFilename) {
    this.sourceFilename = sourceFilename;
    this.classWriter = new ClassWriter(COMPUTE_FRAMES | COMPUTE_MAXS);
    this.context = new Context();
    module.accept(this);
    return classWriter.toByteArray();
  }

  @Override
  public void visitModule(GoloModule module) {
    classWriter.visit(V1_7, ACC_PUBLIC, module.getPackageAndClass().toJVMType(), null, JOBJECT, null);
    classWriter.visitSource(sourceFilename, null);
    writeImportMetaData(module.getImports());
    for (GoloFunction function : module.getFunctions().values()) {
      function.accept(this);
    }
    classWriter.visitEnd();
  }

  private void writeImportMetaData(Set<ModuleImport> imports) {
    ModuleImport[] importsArray = imports.toArray(new ModuleImport[imports.size()]);
    methodVisitor = classWriter.visitMethod(
        ACC_PUBLIC | ACC_STATIC,
        "$imports",
        "()[Ljava/lang/String;",
        null, null);
    methodVisitor.visitCode();
    methodVisitor.visitLdcInsn(importsArray.length);
    methodVisitor.visitTypeInsn(ANEWARRAY, "java/lang/String");
    for (int i = 0; i < importsArray.length; i++) {
      methodVisitor.visitInsn(DUP);
      methodVisitor.visitLdcInsn(i);
      methodVisitor.visitLdcInsn(importsArray[i].getPackageAndClass().toString());
      methodVisitor.visitInsn(AASTORE);
    }
    methodVisitor.visitInsn(ARETURN);
    methodVisitor.visitMaxs(0, 0);
    methodVisitor.visitEnd();
  }

  @Override
  public void visitFunction(GoloFunction function) {
    int visibility = (function.getVisibility() == PUBLIC) ? ACC_PUBLIC : ACC_PRIVATE;
    context.methodArityStack.push(function.getArity());
    methodVisitor = classWriter.visitMethod(
        visibility | ACC_STATIC,
        function.getName(),
        goloFunctionSignature(function.getArity()),
        null, null);
    methodVisitor.visitCode();
    context.nextBlockStart = new Label();
    context.nextBlockEnd = new Label();
    function.getBlock().accept(this);
    methodVisitor.visitMaxs(0, 0);
    methodVisitor.visitEnd();
    context.methodArityStack.pop();
  }

  private String goloFunctionSignature(int arity) {
    StringBuilder descriptorBuilder = new StringBuilder("(");
    for (int i = 0; i < arity; i++) {
      descriptorBuilder.append(TOBJECT);
    }
    descriptorBuilder.append(")").append(TOBJECT);
    return descriptorBuilder.toString();
  }

  @Override
  public void visitBlock(Block block) {
    ReferenceTable referenceTable = block.getReferenceTable();
    context.referenceTableStack.push(referenceTable);
    Label blockStart = context.nextBlockStart;
    Label blockEnd = context.nextBlockEnd;
    methodVisitor.visitLabel(blockStart);
    final int lastParameterIndex = context.methodArityStack.peek() - 1;
    for (LocalReference localReference : referenceTable.ownedReferences()) {
      if (localReference.getIndex() > lastParameterIndex) {
        methodVisitor.visitLocalVariable(localReference.getName(), TOBJECT, null,
            blockStart, blockEnd, localReference.getIndex());
      }
    }
    for (GoloStatement statement : block.getStatements()) {
{'fraction_non_alphanumeric': 0.10822839774207556, 'fraction_numerical': 0.0019539730785931393, 'mean_word_length': 4.467655786350148, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 15, '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': '3635207', 'n_tokens_mistral': 2690, 'n_tokens_neox': 2633, 'n_words': 515}