com.oracle.truffle.api.interop.java.TruffleMap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of truffle-api Show documentation
Show all versions of truffle-api Show documentation
Truffle is a multi-language framework for executing dynamic languages
that achieves high performance when combined with Graal.
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.truffle.api.interop.java;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.ForeignAccess;
import com.oracle.truffle.api.interop.InteropException;
import com.oracle.truffle.api.interop.Message;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.interop.UnknownIdentifierException;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.RootNode;
final class TruffleMap extends AbstractMap {
private final TypeAndClass keyType;
private final TypeAndClass valueType;
private final TruffleObject obj;
private final CallTarget callKeyInfo;
private final CallTarget callKeys;
private final CallTarget callHasSize;
private final CallTarget callGetSize;
private final CallTarget callRead;
private final CallTarget callWrite;
private boolean includeInternal = false;
private TruffleMap(TypeAndClass keyType, TypeAndClass valueType, TruffleObject obj) {
this.keyType = keyType;
this.valueType = valueType;
this.obj = obj;
this.callKeyInfo = initializeMapCall(obj, Message.KEY_INFO);
this.callKeys = initializeMapCall(obj, Message.KEYS);
this.callHasSize = initializeMapCall(obj, Message.HAS_SIZE);
this.callGetSize = initializeMapCall(obj, Message.GET_SIZE);
this.callRead = initializeMapCall(obj, Message.READ);
this.callWrite = initializeMapCall(obj, Message.WRITE);
}
private TruffleMap(TruffleMap map, boolean includeInternal) {
this.keyType = map.keyType;
this.valueType = map.valueType;
this.obj = map.obj;
this.callKeyInfo = map.callKeyInfo;
this.callKeys = map.callKeys;
this.callHasSize = map.callHasSize;
this.callGetSize = map.callGetSize;
this.callRead = map.callRead;
this.callWrite = map.callWrite;
this.includeInternal = includeInternal;
}
static Map create(TypeAndClass keyType, TypeAndClass valueType, TruffleObject foreignObject) {
return new TruffleMap<>(keyType, valueType, foreignObject);
}
TruffleMap cloneInternal(boolean includeInternalKeys) {
return new TruffleMap<>(this, includeInternalKeys);
}
@Override
public boolean containsKey(Object key) {
return ((Integer) callKeyInfo.call(null, obj, key)) != 0;
}
@Override
public Set> entrySet() {
Object props = callKeys.call(null, obj, includeInternal);
if (Boolean.TRUE.equals(callHasSize.call(null, props))) {
Number size = (Number) callGetSize.call(null, props);
return new LazyEntries(props, size.intValue());
}
return Collections.emptySet();
}
@Override
public V get(Object key) {
keyType.cast(key);
final Object item = callRead.call(valueType, obj, key);
return valueType.cast(item);
}
@Override
public V put(K key, V value) {
keyType.cast(key);
valueType.cast(value);
V previous = get(key);
callWrite.call(valueType, obj, key, value);
return previous;
}
private static CallTarget initializeMapCall(TruffleObject obj, Message msg) {
CallTarget res = JavaInterop.ACCESSOR.engine().lookupOrRegisterComputation(obj, null, TruffleMap.class, msg);
if (res == null) {
res = JavaInterop.ACCESSOR.engine().lookupOrRegisterComputation(obj, new MapNode(msg), TruffleMap.class, msg);
}
return res;
}
private final class LazyEntries extends AbstractSet> {
private final Object props;
private final int size;
LazyEntries(Object props, int size) {
this.props = props;
this.size = size;
}
@Override
public Iterator> iterator() {
return new LazyIterator();
}
@Override
public int size() {
return size;
}
@Override
public boolean contains(Object o) {
return containsKey(o);
}
private final class LazyIterator implements Iterator> {
private int index;
LazyIterator() {
index = 0;
}
@Override
public boolean hasNext() {
return index < size;
}
@Override
public Entry next() {
Object key = callRead.call(keyType, props, index++);
return new TruffleEntry(keyType.cast(key));
}
@Override
public void remove() {
throw new UnsupportedOperationException("remove not supported.");
}
}
}
private final class TruffleEntry implements Entry {
private final K key;
TruffleEntry(K key) {
this.key = key;
}
@Override
public K getKey() {
return key;
}
@Override
public V getValue() {
final Object value = callRead.call(valueType, obj, key);
return valueType.cast(value);
}
@Override
public V setValue(V value) {
V prev = getValue();
callWrite.call(null, obj, key, value);
return prev;
}
}
private static final class MapNode extends RootNode {
private final Message msg;
@Child private Node node;
@Child private ToJavaNode toJavaNode;
MapNode(Message msg) {
super(null);
this.msg = msg;
this.node = msg.createNode();
this.toJavaNode = ToJavaNodeGen.create();
}
@Override
public Object execute(VirtualFrame frame) {
final Object[] args = frame.getArguments();
TypeAndClass> type = (TypeAndClass>) args[0];
TruffleObject receiver = (TruffleObject) args[1];
Object ret;
try {
if (msg == Message.HAS_SIZE) {
ret = ForeignAccess.sendHasSize(node, receiver);
} else if (msg == Message.GET_SIZE) {
ret = ForeignAccess.sendGetSize(node, receiver);
} else if (msg == Message.READ) {
try {
ret = ForeignAccess.sendRead(node, receiver, args[2]);
} catch (UnknownIdentifierException uiex) {
return null; // key not present in the map
}
} else if (msg == Message.WRITE) {
ret = ForeignAccess.sendWrite(node, receiver, args[2], JavaInterop.asTruffleValue(args[3]));
} else if (msg == Message.KEY_INFO) {
ret = ForeignAccess.sendKeyInfo(node, receiver, args[2]);
} else if (msg == Message.KEYS) {
ret = ForeignAccess.sendKeys(node, receiver, (boolean) args[2]);
} else {
CompilerDirectives.transferToInterpreter();
throw UnsupportedMessageException.raise(msg);
}
} catch (InteropException ex) {
CompilerDirectives.transferToInterpreter();
throw ex.raise();
}
if (type != null) {
return toJavaNode.execute(ret, type);
} else {
return ret;
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy