private Object convertToObject(TruffleObject truffleObject, Object languageContext) { Object primitiveValue = primitive.unbox(truffleObject); if (primitiveValue != null) { return primitiveValue; } else if (languageContext == null) { // for legacy support return truffleObject; } else if (primitive.hasKeys(truffleObject)) { return asJavaObject(truffleObject, Map.class, null, languageContext); } else if (primitive.hasSize(truffleObject)) { return asJavaObject(truffleObject, List.class, null, languageContext); } else if (isExecutable(truffleObject) || isInstantiable(truffleObject)) { return asJavaObject(truffleObject, Function.class, null, languageContext); } else { return JavaInterop.toHostValue(truffleObject, languageContext); } }
@ExplodeLoop public boolean test(Object value, ToJavaNode toJavaNode) { for (Class<?> otherType : otherTypes) { if (toJavaNode.canConvertStrict(value, otherType)) { return false; } } return toJavaNode.canConvertStrict(value, targetType); } }
@Specialization(guards = "operand != null", replaces = "doCached") @TruffleBoundary protected Object doGeneric(Object operand, Class<?> targetType, Type genericType, Object languageContext) { return convertImpl(operand, targetType, genericType, languageContext); }
obj = JavaObject.valueOf(truffleObject); } else if (targetType == Object.class) { obj = convertToObject(truffleObject, languageContext); } else if (languageContext == null && targetType.isInstance(truffleObject)) { } else if (targetType == List.class) { if (primitive.hasSize(truffleObject)) { boolean implementsFunction = shouldImplementFunction(truffleObject); TypeAndClass<?> elementType = getGenericParameterType(genericType, 0); obj = TruffleList.create(languageContext, truffleObject, implementsFunction, elementType.clazz, elementType.type); } else { Class<?> keyClazz = getGenericParameterType(genericType, 0).clazz; TypeAndClass<?> valueType = getGenericParameterType(genericType, 1); if (!isSupportedMapKeyType(keyClazz)) { throw newInvalidKeyTypeException(keyClazz); boolean implementsFunction = shouldImplementFunction(truffleObject); obj = TruffleMap.create(languageContext, truffleObject, implementsFunction, keyClazz, valueType.clazz, valueType.type); } else { TypeAndClass<?> returnType = getGenericParameterType(genericType, 1); if (isExecutable(truffleObject) || isInstantiable(truffleObject)) { obj = TruffleFunction.create(languageContext, truffleObject, returnType.clazz, returnType.type); } else if (!TruffleOptions.AOT && ForeignAccess.sendHasKeys(hasKeysNode, truffleObject)) { obj = truffleObjectToArray(truffleObject, targetType, genericType, languageContext); } else { throw JavaInteropErrors.cannotConvert(languageContext, truffleObject, targetType, "Value must have array elements.");
@Override public Object toJava(Node javaNode, Class<?> rawType, Type genericType, Object value, Object polyglotContext) { ToJavaNode toJavaNode = (ToJavaNode) javaNode; return toJavaNode.execute(value, rawType, genericType, polyglotContext); }
@SuppressWarnings("unused") boolean canConvert(Object value, Class<?> targetType, Type genericType, Object languageContext, boolean strict) { if (canConvertStrict(value, targetType)) { return true; return primitive.hasKeys(tValue); } else if (targetType == Function.class) { return isExecutable(tValue) || isInstantiable(tValue) || (TruffleOptions.AOT && ForeignAccess.sendHasKeys(hasKeysNode, tValue)); } else if (targetType.isArray()) { return primitive.hasKeys(tValue); } else { if (TruffleOptions.AOT) { if (JavaInterop.isJavaFunctionInterface(targetType) && (isExecutable(tValue) || isInstantiable(tValue))) { return true; } else if (targetType.isInterface() && ForeignAccess.sendHasKeys(hasKeysNode, tValue)) { return isExecutable(tValue) || isInstantiable(tValue); } else { return false;
private Object convertImpl(Object value, Class<?> targetType, Type genericType, Object languageContext) { Object convertedValue; if (isAssignableFromTrufflePrimitiveType(targetType)) { convertedValue = primitive.toPrimitive(value, targetType); if (convertedValue != null) { convertedValue = value instanceof Value ? value : JavaInterop.toHostValue(value, languageContext); } else if (value instanceof TruffleObject) { convertedValue = asJavaObject((TruffleObject) value, targetType, genericType, languageContext); } else if (targetType.isAssignableFrom(value.getClass())) { convertedValue = value; CompilerDirectives.transferToInterpreter(); String reason; if (isAssignableFromTrufflePrimitiveType(targetType)) { reason = "Invalid or lossy primitive coercion."; } else {
private Object newArray(JavaObject receiver, Object[] args) { if (args.length != 1) { throw ArityException.raise(1, args.length); } if (toJava == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); toJava = insert(ToJavaNode.create()); } int length; try { length = (int) toJava.execute(args[0], int.class, null, receiver.languageContext); } catch (ClassCastException | NullPointerException e) { // conversion failed by ToJavaNode throw UnsupportedTypeException.raise(e, args); } Object array = Array.newInstance(receiver.asClass().getComponentType(), length); return JavaObject.forObject(array, receiver.languageContext); }
if (arg == null) { argType = null; } else if (multiple && ToJavaNode.isAssignableFromTrufflePrimitiveType(targetType)) { Class<?> currentTargetType = targetType; continue; if ((ToJavaNode.isAssignableFromTrufflePrimitiveType(paramType) || ToJavaNode.isAssignableFromTrufflePrimitiveType(targetType)) && isAssignableFrom(targetType, paramType)) { otherPossibleTypes.add(paramType); assert checkArgTypes(args, cachedArgTypes, ToJavaNode.create(), false) : Arrays.toString(cachedArgTypes);
static ToJavaNode[] createToJava(int argsLength) { ToJavaNode[] toJava = new ToJavaNode[argsLength]; for (int i = 0; i < argsLength; i++) { toJava[i] = ToJavaNode.create(); } return toJava; }
private static Object truffleObjectToArray(TruffleObject foreignObject, Class<?> arrayType, Type genericArrayType, Object languageContext) { Class<?> componentType = arrayType.getComponentType(); List<?> list = TruffleList.create(languageContext, foreignObject, false, componentType, getGenericArrayComponentType(genericArrayType)); Object array = Array.newInstance(componentType, list.size()); for (int i = 0; i < list.size(); i++) { Array.set(array, i, list.get(i)); } return array; }
boolean canConvertStrict(Object value, Class<?> targetType) { if (isAssignableFromTrufflePrimitiveType(targetType)) { Object convertedValue = primitive.toPrimitive(value, targetType); if (convertedValue != null) { return true; } } if (JavaObject.isJavaInstance(targetType, value)) { return true; } return false; }
boolean applicable = true; for (int i = 0; i < paramCount; i++) { if (!isSubtypeOf(args[i], parameterTypes[i]) && !toJavaNode.canConvert(args[i], parameterTypes[i], genericParameterTypes[i], languageContext, strict)) { applicable = false; break; boolean applicable = true; for (int i = 0; i < parameterCount - 1; i++) { if (!isSubtypeOf(args[i], parameterTypes[i]) && !toJavaNode.canConvert(args[i], parameterTypes[i], genericParameterTypes[i], languageContext, strict)) { applicable = false; break; if (!isSubtypeOf(args[i], varArgsComponentType) && !toJavaNode.canConvert(args[i], varArgsComponentType, varArgsGenericComponentType, languageContext, strict)) { applicable = false; break;
@Override public Object execute(VirtualFrame frame) { return node.execute(value, type, null, currentPolyglotContext()); } }
@Override public Node createToJavaNode() { return ToJavaNode.create(); }
private Object doArrayAccess(JavaObject receiver, int index, Object value) { Object obj = receiver.obj; assert receiver.isArray(); final Object javaValue = toJavaNode.execute(value, obj.getClass().getComponentType(), null, receiver.languageContext); try { Array.set(obj, index, javaValue); } catch (ArrayIndexOutOfBoundsException outOfBounds) { CompilerDirectives.transferToInterpreter(); throw UnknownIdentifierException.raise(String.valueOf(index)); } return JavaObject.NULL; }
/** * Takes executable object from a {@link TruffleLanguage} and converts it into an instance of a * <b>Java</b> <em>functional interface</em>. If the <code>functionalType</code> method is using * {@link java.lang.reflect.Method#isVarArgs() variable arguments}, then the arguments are * unwrapped and passed into the <code>function</code> as indivual arguments. * * @param <T> requested and returned type * @param functionalType interface with a single defined method - so called <em>functional * interface</em> * @param function <em>Truffle</em> that responds to {@link Message#IS_EXECUTABLE} and can be * invoked * @return instance of interface that wraps the provided <code>function</code> * @since 0.9 */ public static <T> T asJavaFunction(Class<T> functionalType, TruffleObject function) { RootNode root = new TemporaryConvertRoot(ToJavaNode.create(), function, functionalType); return functionalType.cast(Truffle.getRuntime().createCallTarget(root).call()); }
@SuppressWarnings("unused") @Specialization(guards = {"operand != null", "operand.getClass() == cachedOperandType", "targetType == cachedTargetType"}, limit = "LIMIT") protected Object doCached(Object operand, Class<?> targetType, Type genericType, Object languageContext, @Cached("operand.getClass()") Class<?> cachedOperandType, @Cached("targetType") Class<?> cachedTargetType) { return convertImpl(cachedOperandType.cast(operand), cachedTargetType, genericType, languageContext); }
@SuppressWarnings("unchecked") @TruffleBoundary @Specialization(guards = {"isList(receiver)"}) protected Object doListIntIndex(JavaObject receiver, int index, Object value) { final Object javaValue = toJavaNode.execute(value, Object.class, null, receiver.languageContext); try { List<Object> list = ((List<Object>) receiver.obj); if (index == list.size()) { list.add(javaValue); } else { list.set(index, javaValue); } return value; } catch (IndexOutOfBoundsException e) { CompilerDirectives.transferToInterpreter(); throw UnknownIdentifierException.raise(String.valueOf(index)); } }
@CompilerDirectives.TruffleBoundary @SuppressWarnings("unchecked") private static <T> T convertToJavaObject(Class<T> type, TruffleObject foreignObject) { RootNode root = new TemporaryConvertRoot(ToJavaNode.create(), foreignObject, type); Object convertedValue = Truffle.getRuntime().createCallTarget(root).call(); return (T) convertedValue; }