@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; }
@Specialization(guards = {"isNullHash(hash)", "!isRubyString(key)"}) public Object setNull( VirtualFrame frame, DynamicObject hash, Object key, Object value, boolean byIdentity) { HashNodes.setStore( hash, PackedArrayStrategy.createStore(hashNode.hash(frame, key), key, value), 1, null, null); assert HashNodes.verifyStore(hash); return value; }
@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; }
@ExplodeLoop @Override public Object execute(VirtualFrame frame) { final Object[] store = PackedArrayStrategy.createStore(); int size = 0; initializers: for (int n = 0; n < keyValues.length / 2; n++) { Object key = keyValues[n * 2].execute(frame); if (stringKeyProfile.profile(RubyGuards.isRubyString(key))) { if (isFrozenNode == null) { CompilerDirectives.transferToInterpreter(); isFrozenNode = insert(IsFrozenNodeGen.create(getContext(), getSourceSection(), null)); } if (!isFrozenNode.executeIsFrozen(key)) { key = freezeNode.call(frame, dupNode.call(frame, key, "dup", null), "freeze", null); } } final int hashed = hashNode.hash(frame, key); final Object value = keyValues[n * 2 + 1].execute(frame); for (int i = 0; i < n; i++) { if (i < size && hashed == PackedArrayStrategy.getHashed(store, i) && equalNode.callBoolean( frame, key, "eql?", null, PackedArrayStrategy.getKey(store, i))) { PackedArrayStrategy.setKey(store, i, key); PackedArrayStrategy.setValue(store, i, value); continue initializers; } } PackedArrayStrategy.setHashedKeyValue(store, size, hashed, key, value); size++; } return HashNodes.createHash(getContext().getCoreLibrary().getHashClass(), store, size); }
@ExplodeLoop @Override public Object execute(VirtualFrame frame) { return HashNodes.createEmptyHash(getContext().getCoreLibrary().getHashClass()); }