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));
  }
Example #2
0
 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));
 }
Example #3
0
  @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;
  }
Example #4
0
  @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();
    }
  }
Example #5
0
  @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();
    }
  }