<commit_before>package som.interpreter.nodes.dispatch;

import som.compiler.ClassDefinition;
import som.interpreter.Invokable;
import som.interpreter.objectstorage.FieldAccessorNode.AbstractReadFieldNode;
import som.interpreter.objectstorage.FieldAccessorNode.AbstractWriteFieldNode;
import som.vm.constants.Nil;
import som.vmobjects.SClass;
import som.vmobjects.SObject;

import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.DirectCallNode;


public class CachedClassSlotAccessNode extends AbstractDispatchNode {

  @Child protected AbstractDispatchNode nextInCache;
  private final SClass rcvrClass;

  private final ClassDefinition classDefinition;
  @Child protected DirectCallNode classObjectInstantiation;

  @Child protected AbstractReadFieldNode  read;
  @Child protected AbstractWriteFieldNode write;

  public CachedClassSlotAccessNode(final ClassDefinition classDefinition,
      final SClass rcvrClass, final AbstractReadFieldNode read,
      final AbstractWriteFieldNode write, final AbstractDispatchNode next) {
    this.rcvrClass = rcvrClass;
    this.read = read;
    this.write = write;
    this.nextInCache = next;
    this.classDefinition = classDefinition;
  }

  @Override
  public Object executeDispatch(final VirtualFrame frame, final Object[] arguments) {
    assert arguments[0] instanceof SObject;
    SObject rcvr = (SObject) arguments[0];

    if (rcvr.getSOMClass() == rcvrClass) {
      return getClassObject(frame, rcvr);
    } else {
      return nextInCache.executeDispatch(frame, arguments);
    }
  }

  private SClass getClassObject(final VirtualFrame frame, final SObject rcvr) {
    Object cacheValue = read.read(rcvr);

    // check whether cache is initialized with class object
    if (cacheValue == Nil.nilObject) {
      SClass classObject = instantiateClassObject(frame, rcvr);
      write.write(rcvr, classObject);
      return classObject;
    } else {
      assert cacheValue instanceof SClass;
      return (SClass) cacheValue;
    }
  }

  private SClass instantiateClassObject(final VirtualFrame frame,
      final SObject rcvr) {
    if (classObjectInstantiation == null) {
      Invokable invokable = classDefinition.getClassObjectInstantiationInvokable();
      classObjectInstantiation = Truffle.getRuntime().createDirectCallNode(
          invokable.getCallTarget());
    }

    SClass superClass = (SClass) classObjectInstantiation.call(frame,
        new Object[] {rcvr});
    SClass classObject = classDefinition.instantiateClass(rcvr, superClass);
    return classObject;
  }

  @Override
  public final int lengthOfDispatchChain() {
    return 1 + nextInCache.lengthOfDispatchChain();
  }
 }
<commit_msg>Need to use createCallTarget, not sure whether that should be guarded or not to avoid repreated creations?<commit_after>package som.interpreter.nodes.dispatch;

import som.compiler.ClassDefinition;
import som.interpreter.Invokable;
import som.interpreter.objectstorage.FieldAccessorNode.AbstractReadFieldNode;
import som.interpreter.objectstorage.FieldAccessorNode.AbstractWriteFieldNode;
import som.vm.constants.Nil;
import som.vmobjects.SClass;
import som.vmobjects.SObject;

import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.DirectCallNode;


public class CachedClassSlotAccessNode extends AbstractDispatchNode {

  @Child protected AbstractDispatchNode nextInCache;
  private final SClass rcvrClass;

  private final ClassDefinition classDefinition;
  @Child protected DirectCallNode classObjectInstantiation;

  @Child protected AbstractReadFieldNode  read;
  @Child protected AbstractWriteFieldNode write;

  public CachedClassSlotAccessNode(final ClassDefinition classDefinition,
      final SClass rcvrClass, final AbstractReadFieldNode read,
      final AbstractWriteFieldNode write, final AbstractDispatchNode next) {
    this.rcvrClass = rcvrClass;
    this.read = read;
    this.write = write;
    this.nextInCache = next;
    this.classDefinition = classDefinition;
  }

  @Override
  public Object executeDispatch(final VirtualFrame frame, final Object[] arguments) {
    assert arguments[0] instanceof SObject;
    SObject rcvr = (SObject) arguments[0];

    if (rcvr.getSOMClass() == rcvrClass) {
      return getClassObject(frame, rcvr);
    } else {
      return nextInCache.executeDispatch(frame, arguments);
    }
  }

  private SClass getClassObject(final VirtualFrame frame, final SObject rcvr) {
    Object cacheValue = read.read(rcvr);

    // check whether cache is initialized with class object
    if (cacheValue == Nil.nilObject) {
      SClass classObject = instantiateClassObject(frame, rcvr);
      write.write(rcvr, classObject);
      return classObject;
    } else {
      assert cacheValue instanceof SClass;
      return (SClass) cacheValue;
    }
  }

  private SClass instantiateClassObject(final VirtualFrame frame,
      final SObject rcvr) {
    if (classObjectInstantiation == null) {
      Invokable invokable = classDefinition.getClassObjectInstantiationInvokable();
      classObjectInstantiation = Truffle.getRuntime().createDirectCallNode(
          invokable.createCallTarget());
    }

    SClass superClass = (SClass) classObjectInstantiation.call(frame,
        new Object[] {rcvr});
    SClass classObject = classDefinition.instantiateClass(rcvr, superClass);
    return classObject;
  }

  @Override
  public final int lengthOfDispatchChain() {
    return 1 + nextInCache.lengthOfDispatchChain();
  }
 }

{'fraction_non_alphanumeric': 0.07722701149425287, 'fraction_numerical': 0.0010775862068965517, 'mean_word_length': 4.465161923454367, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, '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': '7321010', 'n_tokens_mistral': 1564, 'n_tokens_neox': 1555, 'n_words': 376}