Skip to content

Commit 123bc59

Browse files
committed
[GR-19220] Implement rb_hash_start (#1841).
PullRequest: truffleruby/1173
2 parents 30bb211 + 2b58954 commit 123bc59

File tree

7 files changed

+53
-38
lines changed

7 files changed

+53
-38
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ Compatibility:
4646
* Implemented `MatchData#dup` (#1792, @XrXr).
4747
* Implemented a native storage strategy for arrays to allow better C extension compatibility.
4848
* Implemented `rb_check_symbol_cstr` (#1814).
49+
* Implemented `rb_hash_start` (#1841, @XrXr).
4950

5051
Performance:
5152

lib/truffle/truffle/cext.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,10 @@ def RFLOAT_VALUE(value)
565565
value
566566
end
567567

568+
def rb_hash_start(h)
569+
TrufflePrimitive.vm_hash_start(h)
570+
end
571+
568572
def rb_obj_classname(object)
569573
object.class.name
570574
end

spec/ruby/optional/capi/ext/hash_spec.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,15 @@ VALUE hash_spec_rb_hash_set_ifnone(VALUE self, VALUE hash, VALUE def) {
113113
return rb_hash_set_ifnone(hash, def);
114114
}
115115

116+
VALUE hash_spec_compute_a_hash_code(VALUE self, VALUE seed) {
117+
int int_seed = FIX2INT(seed);
118+
st_index_t h = rb_hash_start(int_seed);
119+
h = rb_hash_uint32(h, 540u);
120+
h = rb_hash_uint32(h, 340u);
121+
h = rb_hash_end(h);
122+
return ULONG2NUM(h);
123+
}
124+
116125
void Init_hash_spec(void) {
117126
VALUE cls = rb_define_class("CApiHashSpecs", rb_cObject);
118127
rb_define_method(cls, "rb_hash", hash_spec_rb_hash, 1);
@@ -136,6 +145,7 @@ void Init_hash_spec(void) {
136145
rb_define_method(cls, "rb_hash_new", hash_spec_rb_hash_new, 0);
137146
rb_define_method(cls, "rb_hash_size", hash_spec_rb_hash_size, 1);
138147
rb_define_method(cls, "rb_hash_set_ifnone", hash_spec_rb_hash_set_ifnone, 2);
148+
rb_define_method(cls, "compute_a_hash_code", hash_spec_compute_a_hash_code, 1);
139149
}
140150

141151
#ifdef __cplusplus

spec/ruby/optional/capi/hash_spec.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,4 +254,13 @@ def h.to_hash; 42; end
254254
-> { @s.rb_Hash(h) }.should raise_error(TypeError)
255255
end
256256
end
257+
258+
describe "hash code functions" do
259+
it "computes a deterministic number" do
260+
hash_code = @s.compute_a_hash_code(53)
261+
hash_code.should be_an_instance_of(Integer)
262+
hash_code.should == @s.compute_a_hash_code(53)
263+
@s.compute_a_hash_code(90) == @s.compute_a_hash_code(90)
264+
end
265+
end
257266
end

src/main/c/cext/ruby.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4350,7 +4350,7 @@ VALUE rb_str_cat_cstr(VALUE str, const char *ptr) {
43504350
}
43514351

43524352
st_index_t rb_hash_start(st_index_t h) {
4353-
rb_tr_error("rb_hash_start not implemented");
4353+
return (st_index_t) polyglot_as_i64(polyglot_invoke(RUBY_CEXT, "rb_hash_start", h));
43544354
}
43554355

43564356
int rb_str_hash_cmp(VALUE str1, VALUE str2) {

src/main/java/org/truffleruby/cext/ValueWrapper.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,10 @@
99
*/
1010
package org.truffleruby.cext;
1111

12-
import org.truffleruby.RubyContext;
13-
import org.truffleruby.RubyLanguage;
1412
import org.truffleruby.cext.ValueWrapperManager.AllocateHandleNode;
1513
import org.truffleruby.core.MarkingServiceNodes.KeepAliveNode;
1614

1715
import com.oracle.truffle.api.dsl.Cached;
18-
import com.oracle.truffle.api.dsl.CachedContext;
1916
import com.oracle.truffle.api.interop.InteropLibrary;
2017
import org.truffleruby.cext.ValueWrapperManager.HandleBlock;
2118

@@ -72,7 +69,7 @@ public boolean equals(Object other) {
7269

7370
@Override
7471
public int hashCode() {
75-
return this.object.hashCode();
72+
return object.hashCode();
7673
}
7774

7875
@ExportMessage
@@ -87,21 +84,22 @@ public void toNative() {
8784
@ExportMessage
8885
public static long asPointer(
8986
ValueWrapper wrapper,
90-
@CachedContext(RubyLanguage.class) RubyContext context,
9187
@Cached KeepAliveNode keepAliveNode,
9288
@Cached AllocateHandleNode createNativeHandleNode,
9389
@Cached BranchProfile createHandleProfile,
9490
@Cached BranchProfile taggedObjBranchProfile) {
95-
9691
long handle = wrapper.getHandle();
92+
9793
if (handle == ValueWrapperManager.UNSET_HANDLE) {
9894
createHandleProfile.enter();
9995
handle = createNativeHandleNode.execute(wrapper);
10096
}
97+
10198
if (ValueWrapperManager.isTaggedObject(handle)) {
10299
taggedObjBranchProfile.enter();
103100
keepAliveNode.execute(wrapper);
104101
}
102+
105103
return handle;
106104
}
107105
}

src/main/java/org/truffleruby/core/VMPrimitiveNodes.java

Lines changed: 24 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
import org.truffleruby.core.kernel.KernelNodesFactory;
5656
import org.truffleruby.core.proc.ProcOperations;
5757
import org.truffleruby.core.rope.CodeRange;
58-
import org.truffleruby.core.string.StringNodes;
58+
import org.truffleruby.core.string.StringNodes.MakeStringNode;
5959
import org.truffleruby.core.string.StringOperations;
6060
import org.truffleruby.language.backtrace.Backtrace;
6161
import org.truffleruby.language.control.ExitException;
@@ -84,13 +84,12 @@ public abstract class VMPrimitiveNodes {
8484
@Primitive(name = "vm_catch", needsSelf = false)
8585
public abstract static class CatchNode extends PrimitiveArrayArgumentsNode {
8686

87-
@Child private YieldNode dispatchNode = YieldNode.create();
88-
8987
@Specialization
90-
protected Object doCatch(VirtualFrame frame, Object tag, DynamicObject block,
88+
protected Object doCatch(Object tag, DynamicObject block,
9189
@Cached BranchProfile catchProfile,
9290
@Cached("createBinaryProfile()") ConditionProfile matchProfile,
93-
@Cached ReferenceEqualNode referenceEqualNode) {
91+
@Cached ReferenceEqualNode referenceEqualNode,
92+
@Cached YieldNode dispatchNode) {
9493
try {
9594
return dispatchNode.executeDispatch(block, tag);
9695
} catch (ThrowException e) {
@@ -106,7 +105,7 @@ protected Object doCatch(VirtualFrame frame, Object tag, DynamicObject block,
106105

107106
// The hard #exit!
108107
@Primitive(name = "vm_exit", needsSelf = false, lowerFixnum = 1)
109-
public static abstract class VMExitPrimitiveNode extends PrimitiveArrayArgumentsNode {
108+
public static abstract class VMExitNode extends PrimitiveArrayArgumentsNode {
110109

111110
@Specialization
112111
protected Object vmExit(int status) {
@@ -149,16 +148,10 @@ protected boolean vmMethodIsBasic(VirtualFrame frame, DynamicObject method) {
149148
@Primitive(name = "vm_method_lookup", needsSelf = false)
150149
public static abstract class VMMethodLookupNode extends PrimitiveArrayArgumentsNode {
151150

152-
@Child private NameToJavaStringNode nameToJavaStringNode;
153-
@Child private LookupMethodNode lookupMethodNode;
154-
155-
public VMMethodLookupNode() {
156-
nameToJavaStringNode = NameToJavaStringNode.create();
157-
lookupMethodNode = LookupMethodNode.create();
158-
}
159-
160151
@Specialization
161-
protected DynamicObject vmMethodLookup(VirtualFrame frame, Object receiver, Object name) {
152+
protected DynamicObject vmMethodLookup(VirtualFrame frame, Object receiver, Object name,
153+
@Cached NameToJavaStringNode nameToJavaStringNode,
154+
@Cached LookupMethodNode lookupMethodNode) {
162155
// TODO BJF Sep 14, 2016 Handle private
163156
final String normalizedName = nameToJavaStringNode.executeToJavaString(name);
164157
InternalMethod method = lookupMethodNode.lookupIgnoringVisibility(frame, receiver, normalizedName);
@@ -171,7 +164,7 @@ protected DynamicObject vmMethodLookup(VirtualFrame frame, Object receiver, Obje
171164
}
172165

173166
@Primitive(name = "vm_object_respond_to", needsSelf = false)
174-
public static abstract class VMObjectRespondToPrimitiveNode extends PrimitiveArrayArgumentsNode {
167+
public static abstract class VMObjectRespondToNode extends PrimitiveArrayArgumentsNode {
175168

176169
@Child private KernelNodes.RespondToNode respondToNode = KernelNodesFactory.RespondToNodeFactory
177170
.create(null, null, null);
@@ -185,7 +178,7 @@ protected boolean vmObjectRespondTo(VirtualFrame frame, Object object, Object na
185178

186179

187180
@Primitive(name = "vm_object_singleton_class", needsSelf = false)
188-
public static abstract class VMObjectSingletonClassPrimitiveNode extends PrimitiveArrayArgumentsNode {
181+
public static abstract class VMObjectSingletonClassNode extends PrimitiveArrayArgumentsNode {
189182

190183
@Child private KernelNodes.SingletonClassMethodNode singletonClassNode = KernelNodesFactory.SingletonClassMethodNodeFactory
191184
.create(null);
@@ -228,7 +221,7 @@ public static void reRaiseException(RubyContext context, DynamicObject exception
228221
}
229222

230223
@Primitive(name = "vm_set_module_name", needsSelf = false)
231-
public static abstract class VMSetModuleNamePrimitiveNode extends PrimitiveArrayArgumentsNode {
224+
public static abstract class VMSetModuleNameNode extends PrimitiveArrayArgumentsNode {
232225

233226
@Specialization
234227
protected Object vmSetModuleName(Object object) {
@@ -248,7 +241,7 @@ protected Object doThrow(Object tag, Object value) {
248241
}
249242

250243
@Primitive(name = "vm_watch_signal", needsSelf = false)
251-
public static abstract class VMWatchSignalPrimitiveNode extends PrimitiveArrayArgumentsNode {
244+
public static abstract class VMWatchSignalNode extends PrimitiveArrayArgumentsNode {
252245

253246
@TruffleBoundary
254247
@Specialization(guards = { "isRubyString(signalName)", "isRubyString(action)" })
@@ -386,7 +379,7 @@ private boolean registerHandler(String signalName, Runnable newHandler) {
386379
}
387380

388381
@Primitive(name = "vm_get_config_item", needsSelf = false)
389-
public abstract static class VMGetConfigItemPrimitiveNode extends PrimitiveArrayArgumentsNode {
382+
public abstract static class VMGetConfigItemNode extends PrimitiveArrayArgumentsNode {
390383

391384
@TruffleBoundary
392385
@Specialization(guards = "isRubyString(key)")
@@ -403,14 +396,13 @@ protected Object get(DynamicObject key) {
403396
}
404397

405398
@Primitive(name = "vm_get_config_section", needsSelf = false)
406-
public abstract static class VMGetConfigSectionPrimitiveNode extends PrimitiveArrayArgumentsNode {
407-
408-
@Child private StringNodes.MakeStringNode makeStringNode = StringNodes.MakeStringNode.create();
409-
@Child private YieldNode yieldNode = YieldNode.create();
399+
public abstract static class VMGetConfigSectionNode extends PrimitiveArrayArgumentsNode {
410400

411401
@TruffleBoundary
412402
@Specialization(guards = { "isRubyString(section)", "isRubyProc(block)" })
413-
protected DynamicObject getSection(DynamicObject section, DynamicObject block) {
403+
protected DynamicObject getSection(DynamicObject section, DynamicObject block,
404+
@Cached MakeStringNode makeStringNode,
405+
@Cached YieldNode yieldNode) {
414406
for (Entry<String, Object> entry : getContext()
415407
.getNativeConfiguration()
416408
.getSection(StringOperations.getString(section))) {
@@ -425,7 +417,7 @@ protected DynamicObject getSection(DynamicObject section, DynamicObject block) {
425417
}
426418

427419
@Primitive(name = "vm_set_class", needsSelf = false)
428-
public abstract static class VMSetClassPrimitiveNode extends PrimitiveArrayArgumentsNode {
420+
public abstract static class VMSetClassNode extends PrimitiveArrayArgumentsNode {
429421

430422
@Specialization(guards = "isRubyClass(newClass)")
431423
protected DynamicObject setClass(DynamicObject object, DynamicObject newClass) {
@@ -444,7 +436,7 @@ public abstract static class VMDevUrandomBytes extends PrimitiveArrayArgumentsNo
444436

445437
@Specialization(guards = "count >= 0")
446438
protected DynamicObject readRandomBytes(int count,
447-
@Cached StringNodes.MakeStringNode makeStringNode) {
439+
@Cached MakeStringNode makeStringNode) {
448440
final byte[] bytes = getContext().getRandomSeedBytes(count);
449441

450442
return makeStringNode.executeMake(bytes, ASCIIEncoding.INSTANCE, CodeRange.CR_UNKNOWN);
@@ -462,7 +454,7 @@ protected DynamicObject negativeCount(int count) {
462454
}
463455

464456
@Primitive(name = "vm_hash_start", needsSelf = false)
465-
public abstract static class VMHashStart extends PrimitiveArrayArgumentsNode {
457+
public abstract static class VMHashStartNode extends PrimitiveArrayArgumentsNode {
466458

467459
@Specialization
468460
protected long startHash(long salt) {
@@ -495,7 +487,7 @@ protected Object startHashNotNumber(Object salt,
495487
}
496488

497489
@Primitive(name = "vm_hash_update", needsSelf = false)
498-
public abstract static class VMHashUpdate extends PrimitiveArrayArgumentsNode {
490+
public abstract static class VMHashUpdateNode extends PrimitiveArrayArgumentsNode {
499491

500492
@Specialization
501493
protected long updateHash(long hash, long value) {
@@ -507,7 +499,6 @@ protected long updateHash(long hash, DynamicObject value) {
507499
return Hashing.update(hash, Layouts.BIGNUM.getValue(value).hashCode());
508500
}
509501

510-
511502
@Specialization(guards = "!isRubyNumber(value)")
512503
protected Object updateHash(long hash, Object value,
513504
@Cached("createPrivate()") CallDispatchHeadNode coerceToIntNode,
@@ -529,11 +520,13 @@ protected Object updateHash(long hash, Object value,
529520
}
530521

531522
@Primitive(name = "vm_hash_end", needsSelf = false)
532-
public abstract static class VMHashEnd extends PrimitiveArrayArgumentsNode {
523+
public abstract static class VMHashEndNode extends PrimitiveArrayArgumentsNode {
533524

534525
@Specialization
535526
protected long endHash(long hash) {
536527
return Hashing.end(hash);
537528
}
529+
538530
}
531+
539532
}

0 commit comments

Comments
 (0)