Skip to content

Commit b56a357

Browse files
committed
Copy RubyConstant objects on Module#dup
* Necessary to pass the cleaned-up spec in this commit.
1 parent 0f15f5e commit b56a357

File tree

5 files changed

+29
-24
lines changed

5 files changed

+29
-24
lines changed

spec/ruby/core/module/autoload_spec.rb

+4-6
Original file line numberDiff line numberDiff line change
@@ -792,14 +792,12 @@ module ModuleSpecs::Autoload
792792
-> { ModuleSpecs.autoload "a name", @non_existent }.should raise_error(NameError)
793793
end
794794

795-
it "shares the autoload request across dup'ed copies of modules" do
796-
require fixture(__FILE__, "autoload_s.rb")
797-
@remove << :S
795+
it "does not share the autoload request internals across dup'ed copies of modules" do
798796
filename = fixture(__FILE__, "autoload_t.rb")
799797
mod1 = Module.new { autoload :T, filename }
800-
-> {
801-
ModuleSpecs::Autoload::S = mod1
802-
}.should complain(/already initialized constant/)
798+
ModuleSpecs::Autoload::S = mod1
799+
@remove << :S
800+
803801
mod2 = mod1.dup
804802

805803
mod1.autoload?(:T).should == filename

src/main/java/org/truffleruby/core/kernel/KernelNodes.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,7 @@ protected RubyDynamicObject copyable(Object object, Object freeze,
572572
final RubyClass selfMetaClass = metaClassNode.execute(this, object);
573573
if (isSingletonProfile.profile(this, selfMetaClass.isSingleton)) {
574574
final RubyClass newObjectMetaClass = executeSingletonClass(newObject);
575-
newObjectMetaClass.fields.initCopy(selfMetaClass);
575+
newObjectMetaClass.fields.initCopy(getContext(), selfMetaClass, this);
576576
}
577577

578578
final boolean copyFrozen = freeze instanceof Nil;

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

+14-11
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ public ModuleChain getFirstModuleChain() {
229229
}
230230

231231
@TruffleBoundary
232-
public void initCopy(RubyModule from) {
232+
public void initCopy(RubyContext context, RubyModule from, Node node) {
233233
// Do not copy name, the copy is an anonymous module
234234
final ModuleFields fromFields = from.fields;
235235

@@ -246,7 +246,12 @@ public void initCopy(RubyModule from) {
246246
for (Entry<String, ConstantEntry> entry : fromFields.constants.entrySet()) {
247247
final RubyConstant constant = entry.getValue().getConstant();
248248
if (constant != null) {
249-
this.constants.put(entry.getKey(), new ConstantEntry(constant));
249+
if (constant.isAutoload()) {
250+
var autoloadConstant = constant.getAutoloadConstant();
251+
setAutoloadConstant(context, node, constant.getName(), autoloadConstant.getFeature());
252+
} else {
253+
this.constants.put(entry.getKey(), new ConstantEntry(constant.copy(rubyModule)));
254+
}
250255
}
251256
}
252257

@@ -439,30 +444,28 @@ public RubyConstant setConstant(RubyContext context, Node currentNode, String na
439444
}
440445

441446
@TruffleBoundary
442-
public void setAutoloadConstant(RubyContext context, Node currentNode, String name, Object filename,
443-
String javaFilename) {
444-
RubyConstant autoloadConstant = setConstantInternal(context, currentNode, name, null,
445-
new AutoloadConstant(filename));
446-
if (autoloadConstant == null) {
447+
public void setAutoloadConstant(RubyContext context, Node currentNode, String name, Object filename) {
448+
RubyConstant constant = setConstantInternal(context, currentNode, name, null, new AutoloadConstant(filename));
449+
if (constant == null) {
447450
return;
448451
}
449452

450453
if (context.getOptions().LOG_AUTOLOAD) {
451454
RubyLanguage.LOGGER.info(() -> String.format(
452455
"%s: setting up autoload %s with %s",
453456
context.fileLine(context.getCallStack().getTopMostUserSourceSection()),
454-
autoloadConstant,
457+
constant,
455458
filename));
456459
}
457460
final ReentrantLockFreeingMap<String> fileLocks = context.getFeatureLoader().getFileLocks();
458-
final ReentrantLock lock = fileLocks.get(javaFilename);
461+
final ReentrantLock lock = fileLocks.get(constant.getAutoloadConstant().getAutoloadPath());
459462
if (lock.isLocked()) {
460463
// We need to handle the new autoload constant immediately
461464
// if Object.autoload(name, filename) is executed from filename.rb
462-
GetConstantNode.autoloadConstantStart(context, autoloadConstant, currentNode);
465+
GetConstantNode.autoloadConstantStart(context, constant, currentNode);
463466
}
464467

465-
context.getFeatureLoader().addAutoload(autoloadConstant);
468+
context.getFeatureLoader().addAutoload(constant);
466469
}
467470

468471
private RubyConstant setConstantInternal(RubyContext context, Node currentNode, String name, Object value,

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

+5-6
Original file line numberDiff line numberDiff line change
@@ -652,8 +652,7 @@ protected Object autoload(RubyModule module, String name, Object filename,
652652
throw new RaiseException(getContext(), coreExceptions().argumentError("empty file name", this));
653653
}
654654

655-
final String javaStringFilename = RubyGuards.getJavaString(filename);
656-
module.fields.setAutoloadConstant(getContext(), this, name, filename, javaStringFilename);
655+
module.fields.setAutoloadConstant(getContext(), this, name, filename);
657656
return nil;
658657
}
659658
}
@@ -1589,11 +1588,11 @@ public abstract static class InitializeCopyNode extends CoreMethodArrayArguments
15891588

15901589
@Specialization(guards = { "!isRubyClass(self)", "!isRubyClass(from)" })
15911590
protected Object initializeCopyModule(RubyModule self, RubyModule from) {
1592-
self.fields.initCopy(from);
1591+
self.fields.initCopy(getContext(), from, this);
15931592

15941593
final RubyClass selfMetaClass = getSingletonClass(self);
15951594
final RubyClass fromMetaClass = getSingletonClass(from);
1596-
selfMetaClass.fields.initCopy(fromMetaClass);
1595+
selfMetaClass.fields.initCopy(getContext(), fromMetaClass, this);
15971596

15981597
return nil;
15991598
}
@@ -1609,15 +1608,15 @@ protected Object initializeCopyClass(RubyClass self, RubyClass from,
16091608
throw new RaiseException(getContext(), coreExceptions().typeError("can't copy singleton class", this));
16101609
}
16111610

1612-
self.fields.initCopy(from);
1611+
self.fields.initCopy(getContext(), from, this);
16131612

16141613
final RubyClass selfMetaClass = getSingletonClass(self);
16151614
final RubyClass fromMetaClass = from.getMetaClass();
16161615

16171616
assert fromMetaClass.isSingleton;
16181617
assert self.getMetaClass().isSingleton;
16191618

1620-
selfMetaClass.fields.initCopy(fromMetaClass); // copy class methods
1619+
selfMetaClass.fields.initCopy(getContext(), fromMetaClass, this); // copy class methods
16211620

16221621
return nil;
16231622
}

src/main/java/org/truffleruby/language/RubyConstant.java

+5
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,11 @@ private RubyConstant(
7777
this.sourceSection = sourceSection;
7878
}
7979

80+
public RubyConstant copy(RubyModule declaringModule) {
81+
assert !isAutoload();
82+
return new RubyConstant(declaringModule, name, value, isPrivate, null, undefined, isDeprecated, sourceSection);
83+
}
84+
8085
public RubyModule getDeclaringModule() {
8186
return declaringModule;
8287
}

0 commit comments

Comments
 (0)