private Object lookupRestKeywordArgumentHash(VirtualFrame frame) { CompilerDirectives.transferToInterpreter(); final DynamicObject hash = RubyArguments.getUserKeywordsHash(frame.getArguments(), minimum); if (hash == null) { return Layouts.HASH.createHash( getContext().getCoreLibrary().getHashFactory(), null, null, null, 0, null, null, false); } final List<Map.Entry<Object, Object>> entries = new ArrayList<>(); outer: for (Map.Entry<Object, Object> keyValue : HashOperations.iterableKeyValues(hash)) { for (String excludedKeyword : excludedKeywords) { if (excludedKeyword.equals(keyValue.getKey().toString())) { continue outer; } } entries.add(keyValue); } return BucketsStrategy.create(getContext(), entries, Layouts.HASH.getCompareByIdentity(hash)); }
public static boolean verifyStore(RubyContext context, DynamicObject hash) { return verifyStore( context, Layouts.HASH.getStore(hash), Layouts.HASH.getSize(hash), Layouts.HASH.getFirstInSequence(hash), Layouts.HASH.getLastInSequence(hash)); }
@ExplodeLoop @Specialization(guards = {"isPackedHash(hash)", "!isRubyString(key)"}) public Object setPackedArray( VirtualFrame frame, DynamicObject hash, Object key, Object value, boolean byIdentity) { assert HashNodes.verifyStore(hash); final int hashed = hashNode.hash(frame, key); final Object[] store = (Object[]) Layouts.HASH.getStore(hash); final int size = Layouts.HASH.getSize(hash); for (int n = 0; n < PackedArrayStrategy.MAX_ENTRIES; n++) { if (n < size) { if (hashed == PackedArrayStrategy.getHashed(store, n)) { final boolean equal; if (byIdentityProfile.profile(byIdentity)) { equal = equalNode.executeReferenceEqual(frame, key, PackedArrayStrategy.getKey(store, n)); } else { equal = eqlNode.callBoolean(frame, key, "eql?", null, PackedArrayStrategy.getKey(store, n)); } if (equal) { PackedArrayStrategy.setValue(store, n, value); assert HashNodes.verifyStore(hash); return value; } } } } extendProfile.enter(); if (strategyProfile.profile(size + 1 <= PackedArrayStrategy.MAX_ENTRIES)) { PackedArrayStrategy.setHashedKeyValue(store, size, hashed, key, value); Layouts.HASH.setSize(hash, size + 1); return value; } else { PackedArrayStrategy.promoteToBuckets(hash, store, size); BucketsStrategy.addNewEntry(hash, hashed, key, value); } assert HashNodes.verifyStore(hash); return value; }
@CompilerDirectives.TruffleBoundary public static Iterator<Map.Entry<Object, Object>> iterateKeyValues(DynamicObject hash) { assert RubyGuards.isRubyHash(hash); if (HashGuards.isNullHash(hash)) { return Collections.emptyIterator(); } if (HashGuards.isPackedHash(hash)) { return PackedArrayStrategy.iterateKeyValues( (Object[]) Layouts.HASH.getStore(hash), Layouts.HASH.getSize(hash)); } else if (HashGuards.isBucketHash(hash)) { return BucketsStrategy.iterateKeyValues(Layouts.HASH.getFirstInSequence(hash)); } else { throw new UnsupportedOperationException(); } }
@Specialization(guards = {"isBucketHash(hash)", "!isRubyString(key)"}) public Object setBuckets( VirtualFrame frame, DynamicObject hash, Object key, Object value, boolean byIdentity) { assert HashNodes.verifyStore(hash); if (lookupEntryNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); lookupEntryNode = insert(new LookupEntryNode(getContext(), getEncapsulatingSourceSection())); } final HashLookupResult result = lookupEntryNode.lookup(frame, hash, key); final Entry entry = result.getEntry(); if (foundProfile.profile(entry == null)) { final Entry[] entries = (Entry[]) Layouts.HASH.getStore(hash); final Entry newEntry = new Entry(result.getHashed(), key, value); if (bucketCollisionProfile.profile(result.getPreviousEntry() == null)) { entries[result.getIndex()] = newEntry; } else { result.getPreviousEntry().setNextInLookup(newEntry); } final Entry lastInSequence = Layouts.HASH.getLastInSequence(hash); if (appendingProfile.profile(lastInSequence == null)) { Layouts.HASH.setFirstInSequence(hash, newEntry); } else { lastInSequence.setNextInSequence(newEntry); newEntry.setPreviousInSequence(lastInSequence); } Layouts.HASH.setLastInSequence(hash, newEntry); final int newSize = Layouts.HASH.getSize(hash) + 1; Layouts.HASH.setSize(hash, newSize); // TODO CS 11-May-15 could store the next size for resize instead of doing a float operation // each time if (resizeProfile.profile(newSize / (double) entries.length > BucketsStrategy.LOAD_FACTOR)) { BucketsStrategy.resize(hash); } } else { entry.setKeyValue(result.getHashed(), key, value); } assert HashNodes.verifyStore(hash); return value; }
private DynamicObject translate(UnsupportedSpecializationException exception) { if (getContext().getOptions().EXCEPTIONS_PRINT_JAVA) { exception.printStackTrace(); } final StringBuilder builder = new StringBuilder(); builder.append("Truffle doesn't have a case for the "); builder.append(exception.getNode().getClass().getName()); builder.append(" node with values of type "); for (Object value : exception.getSuppliedValues()) { builder.append(" "); if (value == null) { builder.append("null"); } else if (value instanceof DynamicObject) { builder.append( Layouts.MODULE .getFields(Layouts.BASIC_OBJECT.getLogicalClass(((DynamicObject) value))) .getName()); builder.append("("); builder.append(value.getClass().getName()); builder.append(")"); if (RubyGuards.isRubyArray(value)) { final DynamicObject array = (DynamicObject) value; builder.append("["); if (Layouts.ARRAY.getStore(array) == null) { builder.append("null"); } else { builder.append(Layouts.ARRAY.getStore(array).getClass().getName()); } builder.append(","); builder.append(Layouts.ARRAY.getSize(array)); builder.append("]"); } else if (RubyGuards.isRubyHash(value)) { final Object store = Layouts.HASH.getStore((DynamicObject) value); if (store == null) { builder.append("[null]"); } else { builder.append("["); builder.append(store.getClass().getName()); builder.append("]"); } } } else { builder.append(value.getClass().getName()); } if (value instanceof Number || value instanceof Boolean) { builder.append("="); builder.append(value.toString()); } } switch (unsupportedOperationBehavior) { case TYPE_ERROR: return getContext().getCoreLibrary().typeError(builder.toString(), this); case ARGUMENT_ERROR: return getContext().getCoreLibrary().argumentError(builder.toString(), this); default: throw new UnsupportedOperationException(); } }