@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); }
@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); }
/** 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); } }
/** * {@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 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); } } }
@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; }
/** * 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 @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); }
@Override @AvailMethod int o_NumLiterals(final AvailObject object) { return object.variableObjectSlotsCount(); }
@Override @AvailMethod int o_Hash(final AvailObject object) { return object.slot(HASH); }
/** 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 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 AvailObject o_LiteralAt(final AvailObject object, final int subscript) { return object.slot(LITERAL_AT_, subscript); }
@Override @AvailMethod A_Tuple o_Nybbles(final AvailObject object) { return object.slot(NYBBLES); }
@Override @AvailMethod L2Chunk o_StartingChunk(final AvailObject object) { final AvailObject pojo = object.mutableSlot(STARTING_CHUNK); return (L2Chunk) 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 A_Type o_FunctionType(final AvailObject object) { return object.slot(FUNCTION_TYPE); }
@Override @AvailMethod int o_MaxStackDepth(final AvailObject object) { return object.numArgsAndLocalsAndStack() - object.numArgs() - object.numLocals(); }
@Override @AvailMethod int o_NumArgs(final AvailObject object) { return object.slot(NUM_ARGS); }
@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 public Result attempt( final List<AvailObject> args, final Interpreter interpreter, final boolean skipReturnCheck) { assert args.size() == 2; final AvailObject handle = args.get(0); final AvailObject options = args.get(1); final AvailObject pojo = handle.getAtomProperty(AtomDescriptor.socketKey()); if (pojo.equalsNil()) { return interpreter.primitiveFailure( handle.isAtomSpecial() ? E_SPECIAL_ATOM : E_INVALID_HANDLE); } final AsynchronousSocketChannel socket = (AsynchronousSocketChannel) pojo.javaObjectNotNull(); try { for (final MapDescriptor.Entry entry : options.mapIterable()) { final AvailObject key = entry.key(); final AvailObject entryValue = entry.value(); assert key != null; @SuppressWarnings("rawtypes") final SocketOption option = socketOptions[key.extractInt()]; final Class<?> type = option.type(); if (type.equals(Boolean.class) && entryValue.isBoolean()) { final SocketOption<Boolean> booleanOption = option; socket.setOption(booleanOption, entryValue.extractBoolean()); } else if (type.equals(Integer.class) && entryValue.isInt()) { final Integer value = entryValue.extractInt(); socket.<Integer>setOption(option, value); } else { return interpreter.primitiveFailure(E_INCORRECT_ARGUMENT_TYPE); } } return interpreter.primitiveSuccess(NilDescriptor.nil()); } catch (final IllegalArgumentException e) { return interpreter.primitiveFailure(E_INCORRECT_ARGUMENT_TYPE); } catch (final IOException e) { return interpreter.primitiveFailure(E_IO_ERROR); } }