/* * Copyright (c) 2017, 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.debug; import java.util.AbstractList; import java.util.AbstractMap; import java.util.AbstractSet; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import com.oracle.truffle.api.interop.ForeignAccess; 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.interop.UnsupportedTypeException; import com.oracle.truffle.api.nodes.Node; final class ObjectStructures { static Map<Object, Object> asMap(MessageNodes nodes, TruffleObject object) { TruffleObject keys; try { keys = ForeignAccess.sendKeys(nodes.keys, object, true); boolean hasSize = ForeignAccess.sendHasSize(nodes.hasSize, keys); if (!hasSize) { return null; } } catch (UnsupportedMessageException ex) { return null; } return new ObjectMap(nodes, object, keys); } static boolean isArray(MessageNodes nodes, TruffleObject object) { return ForeignAccess.sendHasSize(nodes.hasSize, object); } static List<Object> asList(MessageNodes nodes, TruffleObject object) { if (!ForeignAccess.sendHasSize(nodes.hasSize, object)) { return null; } return new ObjectList(nodes, object); } private static class ObjectMap extends AbstractMap<Object, Object> { private final MessageNodes nodes; private final TruffleObject object; private final TruffleObject keys; ObjectMap(MessageNodes nodes, TruffleObject object, TruffleObject keys) { this.nodes = nodes; this.object = object; this.keys = keys; } @Override public Set<Entry<Object, Object>> entrySet() { try { Number size = (Number) ForeignAccess.sendGetSize(nodes.getSize, keys); return new LazyEntries(keys, size.intValue()); } catch (UnsupportedMessageException ex) { return Collections.emptySet(); } } @Override public Object get(Object key) { try { return ForeignAccess.sendRead(nodes.read, object, key); } catch (UnknownIdentifierException ex) { return null; // key not present in the map } catch (UnsupportedMessageException ex) { throw ex.raise(); } } @Override public Object put(Object key, Object value) { Object prev = get(key); try { ForeignAccess.sendWrite(nodes.write, object, key, value); } catch (UnknownIdentifierException | UnsupportedTypeException | UnsupportedMessageException ex) { throw ex.raise(); } return prev; } private final class LazyEntries extends AbstractSet<Entry<Object, Object>> { private final TruffleObject props; private final int size; LazyEntries(TruffleObject props, int size) { this.props = props; this.size = size; } @Override public Iterator<Entry<Object, Object>> iterator() { return new LazyIterator(); } @Override public int size() { return size; } private final class LazyIterator implements Iterator<Entry<Object, Object>> { private int index; LazyIterator() { index = 0; } @Override public boolean hasNext() { return index < size; } @Override public Entry<Object, Object> next() { Object key; try { key = ForeignAccess.sendRead(nodes.read, props, index++); } catch (UnknownIdentifierException | UnsupportedMessageException ex) { throw ex.raise(); } return new TruffleEntry(key); } @Override public void remove() { throw new UnsupportedOperationException("remove not supported."); } } } private final class TruffleEntry implements Entry<Object, Object> { private final Object key; TruffleEntry(Object key) { this.key = key; } @Override public Object getKey() { return key; } @Override public Object getValue() { try { return ForeignAccess.sendRead(nodes.read, object, key); } catch (UnknownIdentifierException | UnsupportedMessageException ex) { throw ex.raise(); } } @Override public Object setValue(Object value) { Object prev = getValue(); try { ForeignAccess.sendWrite(nodes.write, object, key, value); } catch (UnknownIdentifierException | UnsupportedMessageException | UnsupportedTypeException ex) { throw ex.raise(); } return prev; } } } private static class ObjectList extends AbstractList<Object> { private final MessageNodes nodes; protected final TruffleObject object; ObjectList(MessageNodes nodes, TruffleObject object) { this.nodes = nodes; this.object = object; } @Override public Object get(int index) { try { return ForeignAccess.sendRead(nodes.read, object, index); } catch (UnknownIdentifierException | UnsupportedMessageException ex) { throw ex.raise(); } } @Override public Object set(int index, Object element) { Object prev = get(index); try { ForeignAccess.sendWrite(nodes.write, object, index, element); } catch (UnknownIdentifierException | UnsupportedTypeException | UnsupportedMessageException ex) { throw ex.raise(); } return prev; } @Override public int size() { try { Number size = (Number) ForeignAccess.sendGetSize(nodes.getSize, object); return size.intValue(); } catch (UnsupportedMessageException ex) { return 0; } } } static class MessageNodes { final Node keys; final Node hasSize; final Node getSize; final Node read; final Node write; MessageNodes() { keys = Message.KEYS.createNode(); hasSize = Message.HAS_SIZE.createNode(); getSize = Message.GET_SIZE.createNode(); read = Message.READ.createNode(); write = Message.WRITE.createNode(); } } }