Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions core/src/main/java/org/jruby/RubyHash.java
Original file line number Diff line number Diff line change
Expand Up @@ -2618,8 +2618,10 @@ public static RubyHash unmarshalFrom(org.jruby.runtime.marshal.UnmarshalStream i
return result;
}

public static RubyHash unmarshalFrom(ThreadContext context, RubyInputStream in, MarshalLoader input, boolean defaultValue) {
RubyHash result = (RubyHash) input.entry(Create.newHash(context));
public static RubyHash unmarshalFrom(ThreadContext context, RubyInputStream in, MarshalLoader input, boolean defaultValue, boolean identity) {
RubyHash result = Create.newHash(context);
if (identity) result.setComparedByIdentity(true);
result = (RubyHash) input.entry(result);
int size = input.unmarshalInt(context, in);

for (int i = 0; i < size; i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
import org.jruby.util.io.RubyOutputStream;

import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.function.BiConsumer;

Expand All @@ -84,6 +85,7 @@
* Marshals objects into Ruby's binary marshal format.
*/
public class MarshalDumper {
private static final ByteList HASH_BYTELIST = new ByteList("Hash".getBytes(StandardCharsets.US_ASCII), false);
private final int depthLimit;
private int depth = 0;
private final HashMapInt<IRubyObject> linkCache = new HashMapInt<>(true);
Expand Down Expand Up @@ -315,6 +317,10 @@ private void writeObjectData(ThreadContext context, RubyOutputStream out, IRubyO
case HASH: {
RubyHash hash = (RubyHash) value;

if (hash.isComparedByIdentity()) {
out.write(TYPE_UCLASS);
dumpSymbol(out, HASH_BYTELIST);
}
if (hash.getIfNone() == RubyBasicObject.UNDEF) {
out.write('{');
} else if (hash.hasDefaultProc()) {
Expand Down
17 changes: 9 additions & 8 deletions core/src/main/java/org/jruby/runtime/marshal/MarshalLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -250,8 +250,8 @@ private IRubyObject objectFor(ThreadContext context, RubyInputStream in, int typ
case TYPE_STRING -> objectForString(context, in, partial);
case TYPE_REGEXP -> objectForRegexp(context, in, state, partial);
case TYPE_ARRAY -> objectForArray(context, in, partial);
case TYPE_HASH -> objectForHash(context, in, partial);
case TYPE_HASH_DEF -> objectForHashDefault(context, in, partial);
case TYPE_HASH -> objectForHash(context, in, partial, false);
case TYPE_HASH_DEF -> objectForHashDefault(context, in, partial, false);
case TYPE_STRUCT -> objectForStruct(context, in, partial);
case TYPE_USERDEF -> objectForUserDef(context, in, state, partial);
case TYPE_USRMARSHAL -> objectForUsrMarshal(context, in, extendedModules);
Expand Down Expand Up @@ -337,12 +337,12 @@ private IRubyObject objectForStruct(ThreadContext context, RubyInputStream in, b
return leave(context, RubyStruct.unmarshalFrom(context, in, this), partial);
}

private IRubyObject objectForHashDefault(ThreadContext context, RubyInputStream in, boolean partial) {
return leave(context, RubyHash.unmarshalFrom(context, in, this, true), partial);
private IRubyObject objectForHashDefault(ThreadContext context, RubyInputStream in, boolean partial, boolean identity) {
return leave(context, RubyHash.unmarshalFrom(context, in, this, true, identity), partial);
}

private IRubyObject objectForHash(ThreadContext context, RubyInputStream in, boolean partial) {
return leave(context, RubyHash.unmarshalFrom(context, in, this, false), partial);
private IRubyObject objectForHash(ThreadContext context, RubyInputStream in, boolean partial, boolean identity) {
return leave(context, RubyHash.unmarshalFrom(context, in, this, false, identity), partial);
}

private IRubyObject objectForArray(ThreadContext context, RubyInputStream in, boolean partial) {
Expand Down Expand Up @@ -388,8 +388,9 @@ private IRubyObject objectForUClass(ThreadContext context, RubyInputStream in, b

int type = r_byte(context, in);
if (c == hashClass(context) && (type == TYPE_HASH || type == TYPE_HASH_DEF)) {
// FIXME: Missing logic to make the following methods use compare_by_identity (and construction of that)
return type == TYPE_HASH ? objectForHash(context, in, partial) : objectForHashDefault(context, in, partial);
return type == TYPE_HASH ?
objectForHash(context, in, partial, true) :
objectForHashDefault(context, in, partial, true);
}

IRubyObject obj = objectFor(context, in, type, null, partial, extendedModules);
Expand Down
2 changes: 0 additions & 2 deletions spec/tags/ruby/core/marshal/dump_tags.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ fails:Marshal.dump with an object responding to #_dump dumps the String in multi
fails:Marshal.dump with an object responding to #_dump raises TypeError if an Object is an instance of an anonymous class
fails:Marshal.dump with a Class dumps a class with multibyte characters in name
fails:Marshal.dump with a Module dumps a module with multibyte characters in name
fails:Marshal.dump with a Hash dumps a Hash with compare_by_identity
fails:Marshal.dump with a Hash dumps a Hash subclass with compare_by_identity
fails:Marshal.dump with an Object raises TypeError if an Object extends an anonymous module
fails:Marshal.dump with a Time dumps a Time subclass with multibyte characters in name
fails:Marshal.dump with a Time raises TypeError with an anonymous Time subclass
Expand Down
2 changes: 0 additions & 2 deletions spec/tags/ruby/core/marshal/load_tags.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ fails:Marshal.load when called with freeze: true returns frozen object having #_
fails:Marshal.load when called with freeze: true returns frozen object responding to #marshal_dump and #marshal_load
fails:Marshal.load when called with freeze: true returns frozen object extended by a module
fails:Marshal.load when called on objects with custom _dump methods loads the String in multibyte encoding
fails:Marshal.load for a Hash preserves compare_by_identity behaviour
fails:Marshal.load for a Hash preserves compare_by_identity behaviour for a Hash subclass
fails:Marshal.load for a Rational loads
fails:Marshal.load for a Complex loads
fails:Marshal.load raises an ArgumentError when the dumped data is truncated
Expand Down
2 changes: 0 additions & 2 deletions spec/tags/ruby/core/marshal/restore_tags.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ fails:Marshal.restore when called with freeze: true returns frozen object having
fails:Marshal.restore when called with freeze: true returns frozen object responding to #marshal_dump and #marshal_load
fails:Marshal.restore when called with freeze: true returns frozen object extended by a module
fails:Marshal.restore when called on objects with custom _dump methods loads the String in multibyte encoding
fails:Marshal.restore for a Hash preserves compare_by_identity behaviour
fails:Marshal.restore for a Hash preserves compare_by_identity behaviour for a Hash subclass
fails:Marshal.restore for a Rational loads
fails:Marshal.restore for a Complex loads
fails:Marshal.restore raises an ArgumentError when the dumped data is truncated
Expand Down
2 changes: 0 additions & 2 deletions test/mri/excludes/TestMarshal.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
exclude :test_change_struct, "work in progress"
exclude :test_class_ivar, "needs investigation"
exclude :test_hash_compared_by_identity, "work in progress"
exclude :test_hash_default_compared_by_identity, "work in progress"
exclude :test_inconsistent_struct, "needs investigation"
exclude :test_load_range_as_struct, "needs investigation"
exclude :test_marshal_complex, "needs investigation"
Expand Down