Skip to content

Commit 193fc87

Browse files
committed
[GR-45116] No need to check the hierarchy Assumption for object.is_a?(SomeClass)
PullRequest: truffleruby/3774
2 parents c36757d + 18fe5ed commit 193fc87

File tree

12 files changed

+88
-23
lines changed

12 files changed

+88
-23
lines changed

ci/common.jsonnet

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,24 @@ local common_json = import "../common.json";
208208
],
209209
},
210210

211+
// OS specific file handling
212+
os_utils:: {
213+
local lib_format = {
214+
"windows": "%s.dll",
215+
"linux": "lib%s.so",
216+
"darwin": "lib%s.dylib"
217+
},
218+
219+
# Converts unixpath to an OS specific path
220+
os_path(unixpath):: if self.os == "windows" then std.strReplace(unixpath, "/", "\\") else unixpath,
221+
222+
# Converts unixpath to an OS specific path for an executable
223+
os_exe(unixpath):: if self.os == "windows" then self.os_path(unixpath) + ".exe" else unixpath,
224+
225+
# Converts a base library name to an OS specific file name
226+
os_lib(name):: lib_format[self.os] % name,
227+
},
228+
211229
local ol7 = {
212230
docker+: {
213231
image: "buildslave_ol7",

lib/cext/ABI_version.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
5
1+
6

lib/cext/include/truffleruby/config_linux_aarch64.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,10 @@
165165
#define RUBY_ALIAS_FUNCTION_VOID(prot, name, args) RUBY_ALIAS_FUNCTION_TYPE(void, prot, name, args)
166166
#define HAVE_GCC_ATOMIC_BUILTINS 1
167167
#define HAVE_GCC_SYNC_BUILTINS 1
168+
#define UNREACHABLE __builtin_unreachable()
168169
#define RUBY_FUNC_EXPORTED __attribute__ ((__visibility__("default"))) extern
169170
#define RUBY_FUNC_NONNULL(n,x) __attribute__ ((__nonnull__(n))) x
171+
#define RUBY_FUNCTION_NAME_STRING __func__
170172
#define ENUM_OVER_INT 1
171173
#define HAVE_DECL_SYS_NERR 1
172174
#define HAVE_DECL_GETENV 1

lib/cext/include/truffleruby/config_linux_amd64.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,10 @@
168168
#define RUBY_ALIAS_FUNCTION_VOID(prot, name, args) RUBY_ALIAS_FUNCTION_TYPE(void, prot, name, args)
169169
#define HAVE_GCC_ATOMIC_BUILTINS 1
170170
#define HAVE_GCC_SYNC_BUILTINS 1
171+
#define UNREACHABLE __builtin_unreachable()
171172
#define RUBY_FUNC_EXPORTED __attribute__ ((__visibility__("default"))) extern
172173
#define RUBY_FUNC_NONNULL(n,x) __attribute__ ((__nonnull__(n))) x
174+
#define RUBY_FUNCTION_NAME_STRING __func__
173175
#define ENUM_OVER_INT 1
174176
#define HAVE_DECL_SYS_NERR 1
175177
#define HAVE_DECL_GETENV 1
@@ -431,9 +433,8 @@
431433
#define DLEXT_MAXLEN 3
432434
#define DLEXT ".so"
433435
#define HAVE__SETJMP 1
434-
#define RUBY_SETJMP(env) _setjmp((env))
435-
#define RUBY_LONGJMP(env,val) _longjmp((env),val)
436-
#define RUBY_JMP_BUF jmp_buf
436+
#define RUBY_SETJMP(env) __builtin_setjmp((void **)(env))
437+
#define RUBY_LONGJMP(env,val) __builtin_longjmp((void **)(env),val)
437438
#define USE_MJIT 1
438439
#define HAVE_PTHREAD_H 1
439440
#define THREAD_IMPL_H "thread_pthread.h"

mx.truffleruby/suite.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
{
88
"name": "regex",
99
"subdir": True,
10-
"version": "c1f4265c6492e5eae21cd16c6fe51bb4c5b79661",
10+
"version": "db464f45d94a76851b5d1c9e6c2401157c9b9ac5",
1111
"urls": [
1212
{"url": "https://github.com/oracle/graal.git", "kind": "git"},
1313
{"url": "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind": "binary"},
@@ -16,7 +16,7 @@
1616
{
1717
"name": "sulong",
1818
"subdir": True,
19-
"version": "c1f4265c6492e5eae21cd16c6fe51bb4c5b79661",
19+
"version": "db464f45d94a76851b5d1c9e6c2401157c9b9ac5",
2020
"urls": [
2121
{"url": "https://github.com/oracle/graal.git", "kind": "git"},
2222
{"url": "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind": "binary"},

spec/truffle/interop/meta_object_spec.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,19 @@
4141
Truffle::Interop.should_not.has_meta_parents?(Enumerable)
4242
end
4343
end
44+
45+
describe "Truffle::Interop.meta_object?" do
46+
it "returns true for a Class" do
47+
Truffle::Interop.should.meta_object?(String)
48+
Truffle::Interop.should.meta_object?(Class.new)
49+
end
50+
51+
it "returns true for a Module" do
52+
Truffle::Interop.should.meta_object?(Kernel)
53+
Truffle::Interop.should.meta_object?(Module.new)
54+
end
55+
56+
it "returns false for objects" do
57+
Truffle::Interop.should_not.meta_object?(Object.new)
58+
end
59+
end

src/main/java/org/truffleruby/core/klass/RubyClass.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,10 @@ public RubyClass(
5959
assert !isSingleton || givenBaseName == null;
6060
this.isSingleton = isSingleton;
6161
this.attached = attached;
62+
this.nonSingletonClass = computeNonSingletonClass(isSingleton, superclass);
63+
this.directNonSingletonSubclasses = new ConcurrentWeakSet<>();
6264

6365
if (superclass instanceof RubyClass) {
64-
if (lexicalParent == null && givenBaseName != null) {
65-
fields.setFullName(givenBaseName);
66-
}
6766
// superclass should be set after "full name"
6867
this.superclass = superclass;
6968
this.ancestorClasses = computeAncestorClasses((RubyClass) superclass);
@@ -75,13 +74,13 @@ public RubyClass(
7574
}
7675
} else { // BasicObject (nil superclass)
7776
assert superclass == nil;
77+
assert givenBaseName == "BasicObject";
7878
this.superclass = superclass;
7979
this.ancestorClasses = EMPTY_CLASS_ARRAY;
8080
this.depth = 0;
8181
}
8282

83-
this.directNonSingletonSubclasses = new ConcurrentWeakSet<>();
84-
this.nonSingletonClass = computeNonSingletonClass(isSingleton, superclass);
83+
fields.afterConstructed();
8584
}
8685

8786

@@ -91,6 +90,7 @@ public RubyClass(
9190
this.isSingleton = false;
9291
this.attached = null;
9392
this.nonSingletonClass = this;
93+
this.directNonSingletonSubclasses = new ConcurrentWeakSet<>();
9494

9595
RubyClass basicObjectClass = ClassNodes.createBootClass(language, this, nil, "BasicObject");
9696
RubyClass objectClass = ClassNodes.createBootClass(language, this, basicObjectClass, "Object");
@@ -100,8 +100,9 @@ public RubyClass(
100100
this.superclass = superclass;
101101
this.ancestorClasses = computeAncestorClasses(superclass);
102102
this.depth = superclass.depth + 1;
103-
this.directNonSingletonSubclasses = new ConcurrentWeakSet<>();
104103
fields.setSuperClass(superclass);
104+
105+
fields.afterConstructed();
105106
}
106107

107108
private RubyClass computeNonSingletonClass(boolean isSingleton, Object superclassObject) {

src/main/java/org/truffleruby/core/module/ModuleFields.java

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ public static void debugModuleChain(RubyModule module) {
112112
* map of refined classes and modules (C) to refinement modules (R). */
113113
private final ConcurrentMap<RubyModule, RubyModule> refinements = new ConcurrentHashMap<>();
114114

115+
/** Only set for a Module and not a Class since there is no usage of it for a Class */
115116
private final CyclicAssumption hierarchyUnmodifiedAssumption;
116117

117118
// Concurrency: only modified during boot
@@ -141,17 +142,33 @@ public ModuleFields(
141142
this.lexicalParent = lexicalParent;
142143
this.givenBaseName = givenBaseName;
143144
this.rubyModule = rubyModule;
144-
this.hierarchyUnmodifiedAssumption = new CyclicAssumption("hierarchy is unmodified");
145+
this.hierarchyUnmodifiedAssumption = rubyModule instanceof RubyClass
146+
? null
147+
: new CyclicAssumption("hierarchy is unmodified");
145148
classVariables = new ClassVariableStorage(language);
146149
start = new PrependMarker(this);
147150
this.includedBy = rubyModule instanceof RubyClass ? null : new ConcurrentWeakSet<>();
151+
152+
if (lexicalParent == null && givenBaseName != null) {
153+
setFullName(givenBaseName);
154+
}
155+
}
156+
157+
/** Compute the name eagerly now as it can cause a Shape transition. We need to do so because
158+
* InteropLibrary$Asserts.assertMetaObject calls getMetaQualifiedName() and if getName() at that point adds the
159+
* object_id property then accepts() asserts that follow will fail. We cannot call this in the ModuleFields
160+
* constructor as the name depends on fields of RubyClass (e.g., isSingleton). */
161+
public void afterConstructed() {
162+
getName();
148163
}
149164

150165
public RubyConstant getAdoptedByLexicalParent(
151166
RubyContext context,
152167
RubyModule lexicalParent,
153168
String name,
154169
Node currentNode) {
170+
assert name != null;
171+
155172
RubyConstant previous = lexicalParent.fields.setConstantInternal(
156173
context,
157174
currentNode,
@@ -785,6 +802,10 @@ public boolean isAnonymous() {
785802
return !this.hasFullName;
786803
}
787804

805+
private boolean isClass() {
806+
return rubyModule instanceof RubyClass;
807+
}
808+
788809
public boolean isRefinement() {
789810
return isRefinement;
790811
}
@@ -810,7 +831,9 @@ public String toString() {
810831
}
811832

812833
public void newHierarchyVersion() {
813-
hierarchyUnmodifiedAssumption.invalidate(getName());
834+
if (!isClass()) {
835+
hierarchyUnmodifiedAssumption.invalidate(getName());
836+
}
814837

815838
if (isRefinement()) {
816839
getRefinedModule().fields.invalidateBuiltinsAssumptions();
@@ -870,6 +893,7 @@ private void newMethodVersion(String methodToInvalidate) {
870893
}
871894

872895
public Assumption getHierarchyUnmodifiedAssumption() {
896+
assert !isClass();
873897
return hierarchyUnmodifiedAssumption.getAssumption();
874898
}
875899

@@ -981,12 +1005,10 @@ public ConcurrentMap<RubyModule, RubyModule> getRefinements() {
9811005
return refinements;
9821006
}
9831007

1008+
/** Must be called inside the RubyClass constructor */
9841009
public void setSuperClass(RubyClass superclass) {
9851010
assert rubyModule instanceof RubyClass;
9861011
this.parentModule = superclass.fields.start;
987-
newMethodsVersion(new ArrayList<>(methods.keySet()));
988-
newConstantsVersion(new ArrayList<>(constants.keySet()));
989-
newHierarchyVersion();
9901012
}
9911013

9921014
@Override

src/main/java/org/truffleruby/core/module/ModuleNodes.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,11 @@ public static RubyModule createModule(RubyContext context, SourceSection sourceS
162162
sourceSection,
163163
lexicalParent,
164164
name);
165+
166+
module.fields.afterConstructed();
167+
165168
if (lexicalParent != null) {
166169
module.fields.getAdoptedByLexicalParent(context, lexicalParent, name, currentNode);
167-
} else if (name != null) { // bootstrap module
168-
module.fields.setFullName(name);
169170
}
170171
return module;
171172
}

src/main/java/org/truffleruby/core/module/RubyModule.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,7 @@ public RubyModule(
6161

6262
protected RubyModule(RubyLanguage language, Shape classShape, String constructorOnlyForClassClass) {
6363
super(classShape, constructorOnlyForClassClass);
64-
65-
final ModuleFields fields = new ModuleFields(language, null, null, "Class", this);
66-
fields.setFullName("Class");
67-
this.fields = fields;
64+
this.fields = new ModuleFields(language, null, null, "Class", this);
6865
}
6966

7067
public String getName() {

0 commit comments

Comments
 (0)