@Override
 @AvailMethod
 int o_PrimitiveNumber(final AvailObject object) {
   // Answer the primitive number I should try before falling back on
   // the Avail code.  Zero indicates not-a-primitive.
   return object.slot(PRIMITIVE);
 }
 @Override
 @AvailMethod
 boolean o_EqualsCompiledCode(final AvailObject object, final A_RawFunction aCompiledCode) {
   // Compiled code now (2012.06.14) compares by identity because it may
   // have to track references to the source code.
   return object.sameAddressAs(aCompiledCode);
 }
 /** Answer the starting line number for this block of code. */
 @Override
 @AvailMethod
 int o_StartingLineNumber(final AvailObject object) {
   final A_Atom properties = object.mutableSlot(PROPERTY_ATOM);
   final A_Number lineInteger = properties.getAtomProperty(lineNumberKeyAtom());
   return lineInteger.equalsNil() ? 0 : lineInteger.extractInt();
 }
 @Override
 @AvailMethod
 void o_SetStartingChunkAndReoptimizationCountdown(
     final AvailObject object, final L2Chunk chunk, final long countdown) {
   final AtomicLong atomicCounter = getInvocationStatistic(object).countdownToReoptimize;
   if (isShared()) {
     synchronized (object) {
       object.setSlot(STARTING_CHUNK, chunk.chunkPojo);
     }
     // Must be outside the synchronized section to ensure the write of
     // the new chunk is committed before the counter reset is visible.
     atomicCounter.set(countdown);
   } else {
     object.setSlot(STARTING_CHUNK, chunk.chunkPojo);
     atomicCounter.set(countdown);
   }
 }
 @Override
 @AvailMethod
 void o_SetMethodName(final AvailObject object, final A_String methodName) {
   assert methodName.isString();
   methodName.makeImmutable();
   final A_Atom propertyAtom = object.mutableSlot(PROPERTY_ATOM);
   propertyAtom.setAtomProperty(methodNameKeyAtom(), methodName);
   // Now scan all sub-blocks. Some literals will be functions and some
   // will be compiled code objects.
   int counter = 1;
   for (int i = 1, limit = object.numLiterals(); i <= limit; i++) {
     final AvailObject literal = object.literalAt(i);
     final A_RawFunction subCode;
     if (literal.isFunction()) {
       subCode = literal.code();
     } else if (literal.isInstanceOf(CompiledCodeTypeDescriptor.mostGeneralType())) {
       subCode = literal;
     } else {
       subCode = null;
     }
     if (subCode != null) {
       final String suffix = String.format("[%d]", counter);
       counter++;
       final A_Tuple newName = methodName.concatenateWith(StringDescriptor.from(suffix), true);
       subCode.setMethodName((A_String) newName);
     }
   }
 }
 /**
  * {@inheritDoc}
  *
  * <p>Show the types of local variables and outer variables.
  */
 @Override
 AvailObjectFieldHelper[] o_DescribeForDebugger(final AvailObject object) {
   final List<AvailObjectFieldHelper> fields = new ArrayList<>();
   fields.addAll(Arrays.asList(super.o_DescribeForDebugger(object)));
   for (int i = 1, end = object.numOuters(); i <= end; i++) {
     fields.add(
         new AvailObjectFieldHelper(object, FakeSlots.OUTER_TYPE_, i, object.outerTypeAt(i)));
   }
   for (int i = 1, end = object.numLocals(); i <= end; i++) {
     fields.add(
         new AvailObjectFieldHelper(object, FakeSlots.LOCAL_TYPE_, i, object.localTypeAt(i)));
   }
   final StringBuilder disassembled = new StringBuilder();
   object.printOnAvoidingIndent(disassembled, new IdentityHashMap<A_BasicObject, Void>(), 0);
   final String[] content = disassembled.toString().split("\n");
   fields.add(new AvailObjectFieldHelper(object, FakeSlots.L1_DISASSEMBLY, -1, content));
   final List<AvailObject> allLiterals = new ArrayList<>();
   for (int i = 1; i <= object.numLiterals(); i++) {
     allLiterals.add(object.literalAt(i));
   }
   fields.add(
       new AvailObjectFieldHelper(
           object, FakeSlots.ALL_LITERALS, -1, TupleDescriptor.fromList(allLiterals)));
   return fields.toArray(new AvailObjectFieldHelper[fields.size()]);
 }
 @Override
 @AvailMethod
 A_String o_MethodName(final AvailObject object) {
   final A_Atom propertyAtom = object.mutableSlot(PROPERTY_ATOM);
   final A_String methodName = propertyAtom.getAtomProperty(methodNameKeyAtom());
   if (methodName.equalsNil()) {
     return StringDescriptor.from("Unknown function");
   }
   return methodName;
 }
 @Override
 @AvailMethod
 int o_NumArgs(final AvailObject object) {
   return object.slot(NUM_ARGS);
 }
 /** Answer the module in which this code occurs. */
 @Override
 @AvailMethod
 A_Module o_Module(final AvailObject object) {
   final A_Atom properties = object.mutableSlot(PROPERTY_ATOM);
   return properties.issuingModule();
 }
 @Override
 @AvailMethod
 AvailObject o_LiteralAt(final AvailObject object, final int subscript) {
   return object.slot(LITERAL_AT_, subscript);
 }
 @Override
 @AvailMethod
 L2Chunk o_StartingChunk(final AvailObject object) {
   final AvailObject pojo = object.mutableSlot(STARTING_CHUNK);
   return (L2Chunk) pojo.javaObject();
 }
 @Override
 @AvailMethod
 A_Type o_FunctionType(final AvailObject object) {
   return object.slot(FUNCTION_TYPE);
 }
 @Override
 @AvailMethod
 @Nullable
 Primitive o_Primitive(final AvailObject object) {
   return Primitive.byNumber(object.slot(PRIMITIVE));
 }
 @Override
 @AvailMethod
 int o_NumOuters(final AvailObject object) {
   return object.slot(NUM_OUTERS);
 }
 @Override
 @AvailMethod
 int o_NumLocals(final AvailObject object) {
   return object.slot(NUM_LOCALS);
 }
 /**
  * Answer the {@link InvocationStatistic} associated with the specified {@link
  * CompiledCodeDescriptor raw function}.
  *
  * @param object The {@link A_RawFunction} from which to extract the invocation statistics helper.
  * @return The code's invocation statistics.
  */
 static InvocationStatistic getInvocationStatistic(final AvailObject object) {
   final AvailObject pojo = object.slot(INVOCATION_STATISTIC);
   return (InvocationStatistic) pojo.javaObject();
 }
 @Override
 void o_WriteSummaryTo(final AvailObject object, final JSONWriter writer) {
   writer.startObject();
   writer.write("kind");
   writer.write("function implementation");
   writer.write("outers");
   writer.write(object.slot(NUM_OUTERS));
   writer.write("arguments");
   writer.write(object.slot(NUM_ARGS));
   writer.write("locals");
   writer.write(object.slot(NUM_LOCALS));
   writer.write("maximum stack depth");
   writer.write(object.slot(FRAME_SLOTS));
   writer.write("nybbles");
   object.slot(NYBBLES).writeTo(writer);
   writer.write("function type");
   object.slot(FUNCTION_TYPE).writeSummaryTo(writer);
   writer.write("method");
   object.methodName().writeTo(writer);
   writer.write("module");
   object.module().moduleName().writeTo(writer);
   writer.write("starting line number");
   writer.write(object.startingLineNumber());
   writer.write("literals");
   writer.startArray();
   for (int i = 1, limit = object.variableObjectSlotsCount(); i <= limit; i++) {
     A_BasicObject literal = object.slot(LITERAL_AT_, i);
     if (literal.equalsNil()) {
       literal = IntegerDescriptor.zero();
     }
     literal.writeSummaryTo(writer);
   }
   writer.endArray();
   writer.endObject();
 }
 @Override
 @AvailMethod
 int o_MaxStackDepth(final AvailObject object) {
   return object.numArgsAndLocalsAndStack() - object.numArgs() - object.numLocals();
 }
 @Override
 @AvailMethod
 int o_Hash(final AvailObject object) {
   return object.slot(HASH);
 }
 @Override
 @AvailMethod
 A_Type o_OuterTypeAt(final AvailObject object, final int index) {
   assert 1 <= index && index <= object.numOuters();
   return object.literalAt(object.numLiterals() - object.numLocals() - object.numOuters() + index);
 }
 @Override
 @AvailMethod
 A_Type o_Kind(final AvailObject object) {
   return CompiledCodeTypeDescriptor.forFunctionType(object.functionType());
 }
 @Override
 @AvailMethod
 A_Tuple o_Nybbles(final AvailObject object) {
   return object.slot(NYBBLES);
 }
 @Override
 String o_NameForDebugger(final AvailObject object) {
   return super.o_NameForDebugger(object) + ": " + object.methodName();
 }
 /**
  * {@inheritDoc}
  *
  * <p>Answer the number of arguments + locals + stack slots to reserve in my continuations.
  */
 @Override
 @AvailMethod
 int o_NumArgsAndLocalsAndStack(final AvailObject object) {
   return object.slot(FRAME_SLOTS);
 }
  /**
   * Create a new compiled code object with the given properties.
   *
   * @param nybbles The nybblecodes.
   * @param locals The number of local variables.
   * @param stack The maximum stack depth.
   * @param functionType The type that the code's functions will have.
   * @param primitive Which primitive to invoke, or zero.
   * @param literals A tuple of literals.
   * @param localTypes A tuple of types of local variables.
   * @param outerTypes A tuple of types of outer (captured) variables.
   * @param module The module in which the code, or nil.
   * @param lineNumber The module line number on which this code starts.
   * @return The new compiled code object.
   */
  public static AvailObject create(
      final A_Tuple nybbles,
      final int locals,
      final int stack,
      final A_Type functionType,
      final @Nullable Primitive primitive,
      final A_Tuple literals,
      final A_Tuple localTypes,
      final A_Tuple outerTypes,
      final A_Module module,
      final int lineNumber) {
    if (primitive != null) {
      // Sanity check for primitive blocks.  Use this to hunt incorrectly
      // specified primitive signatures.
      final boolean canHaveCode = primitive.canHaveNybblecodes();
      assert canHaveCode == (nybbles.tupleSize() > 0);
      final A_Type restrictionSignature = primitive.blockTypeRestriction();
      assert restrictionSignature.isSubtypeOf(functionType);
    } else {
      assert nybbles.tupleSize() > 0;
    }

    assert localTypes.tupleSize() == locals;
    final A_Type argCounts = functionType.argsTupleType().sizeRange();
    final int numArgs = argCounts.lowerBound().extractInt();
    assert argCounts.upperBound().extractInt() == numArgs;
    final int literalsSize = literals.tupleSize();
    final int outersSize = outerTypes.tupleSize();

    assert 0 <= numArgs && numArgs <= 0xFFFF;
    assert 0 <= locals && locals <= 0xFFFF;
    final int slotCount = numArgs + locals + stack;
    assert 0 <= slotCount && slotCount <= 0xFFFF;
    assert 0 <= outersSize && outersSize <= 0xFFFF;

    assert module.equalsNil() || module.isInstanceOf(MODULE.o());
    assert lineNumber >= 0;

    final AvailObject code = mutable.create(literalsSize + outersSize + locals);

    final InvocationStatistic statistic = new InvocationStatistic();
    statistic.countdownToReoptimize.set(L2Chunk.countdownForNewCode());
    final AvailObject statisticPojo = RawPojoDescriptor.identityWrap(statistic);

    code.setSlot(NUM_LOCALS, locals);
    code.setSlot(NUM_ARGS, numArgs);
    code.setSlot(FRAME_SLOTS, slotCount);
    code.setSlot(NUM_OUTERS, outersSize);
    code.setSlot(PRIMITIVE, primitive == null ? 0 : primitive.primitiveNumber);
    code.setSlot(NYBBLES, nybbles.makeShared());
    code.setSlot(FUNCTION_TYPE, functionType.makeShared());
    code.setSlot(PROPERTY_ATOM, NilDescriptor.nil());
    code.setSlot(STARTING_CHUNK, L2Chunk.unoptimizedChunk().chunkPojo);
    code.setSlot(INVOCATION_STATISTIC, statisticPojo);

    // Fill in the literals.
    int dest;
    for (dest = 1; dest <= literalsSize; dest++) {
      code.setSlot(LITERAL_AT_, dest, literals.tupleAt(dest).makeShared());
    }
    for (int i = 1; i <= outersSize; i++) {
      code.setSlot(LITERAL_AT_, dest++, outerTypes.tupleAt(i).makeShared());
    }
    for (int i = 1; i <= locals; i++) {
      code.setSlot(LITERAL_AT_, dest++, localTypes.tupleAt(i).makeShared());
    }
    assert dest == literalsSize + outersSize + locals + 1;

    final A_Atom propertyAtom =
        AtomWithPropertiesDescriptor.create(TupleDescriptor.empty(), module);
    propertyAtom.setAtomProperty(lineNumberKeyAtom(), IntegerDescriptor.fromInt(lineNumber));
    code.setSlot(PROPERTY_ATOM, propertyAtom.makeShared());
    final int hash = propertyAtom.hash() ^ -0x3087B215;
    code.setSlot(HASH, hash);
    code.makeShared();

    // Add the newborn raw function to the weak set being used for code
    // coverage tracking.
    activeRawFunctions.add(code);

    return code;
  }
 @Override
 @AvailMethod
 int o_NumLiterals(final AvailObject object) {
   return object.variableObjectSlotsCount();
 }