Skip to content

Commit aa0a082

Browse files
committed
[GR-32712] Make RubyRegexp fields final
PullRequest: truffleruby/2829
2 parents 2eb2bcc + 51dc1c9 commit aa0a082

File tree

10 files changed

+42
-112
lines changed

10 files changed

+42
-112
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
fails:Regexp#initialize raises a SecurityError on a Regexp literal
2+
fails:Regexp#initialize raises a TypeError on an initialized non-literal Regexp
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
fails:Regexps with encoding modifiers uses BINARY when is not initialized

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

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@
7373
import org.truffleruby.core.proc.ProcNodes.ProcNewNode;
7474
import org.truffleruby.core.proc.ProcOperations;
7575
import org.truffleruby.core.proc.RubyProc;
76-
import org.truffleruby.core.regexp.RubyRegexp;
7776
import org.truffleruby.core.rope.CodeRange;
7877
import org.truffleruby.core.rope.Rope;
7978
import org.truffleruby.core.rope.RopeNodes;
@@ -498,12 +497,6 @@ protected RubyDynamicObject copyImmutableString(ImmutableRubyString string,
498497
return (RubyDynamicObject) allocateNode().call(context.getCoreLibrary().stringClass, "__allocate__");
499498
}
500499

501-
@Specialization
502-
protected RubyRegexp copyRubyRegexp(RubyRegexp regexp,
503-
@CachedContext(RubyLanguage.class) RubyContext context) {
504-
return (RubyRegexp) allocateNode().call(context.getCoreLibrary().regexpClass, "__allocate__");
505-
}
506-
507500
@Specialization
508501
protected RubyEncoding copyRubyEncoding(RubyEncoding encoding,
509502
@CachedContext(RubyLanguage.class) RubyContext context) {

src/main/java/org/truffleruby/core/regexp/InterpolatedRegexpNode.java

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -127,25 +127,21 @@ protected RubyRegexp createRegexp(RopeWithEncoding[] strings) {
127127
// in the Regex object as the "user object". Since ropes are immutable, we need to take this updated copy when
128128
// constructing the final regexp.
129129
final RopeWithEncoding ropeWithEncoding = (RopeWithEncoding) regexp1.getUserObject();
130-
final RubyRegexp regexp = new RubyRegexp(
131-
regexp1,
132-
ropeWithEncoding.getRope(),
133-
ropeWithEncoding.getEncoding(),
134-
options,
135-
new EncodingCache(),
136-
new TRegexCache());
137130

131+
Rope source = ropeWithEncoding.getRope();
138132
if (options.isEncodingNone()) {
139-
final Rope source = regexp.source;
140-
141133
if (!all7Bit(preprocessed.getRope().getBytes())) {
142-
regexp.source = RopeOperations.withEncoding(source, ASCIIEncoding.INSTANCE);
134+
source = RopeOperations.withEncoding(source, ASCIIEncoding.INSTANCE);
143135
} else {
144-
regexp.source = RopeOperations.withEncoding(source, USASCIIEncoding.INSTANCE);
136+
source = RopeOperations.withEncoding(source, USASCIIEncoding.INSTANCE);
145137
}
146138
}
147139

148-
return regexp;
140+
return new RubyRegexp(
141+
regexp1,
142+
source,
143+
ropeWithEncoding.getEncoding(),
144+
options);
149145
}
150146

151147
private static boolean all7Bit(byte[] bytes) {

src/main/java/org/truffleruby/core/regexp/RegexpNodes.java

Lines changed: 13 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@
5353
@CoreModule(value = "Regexp", isClass = true)
5454
public abstract class RegexpNodes {
5555

56-
public static void initialize(RubyLanguage language, RubyRegexp regexp, Rope setSource,
56+
public static RubyRegexp create(RubyLanguage language,
57+
Rope setSource,
5758
RubyEncoding setSourceEncoding,
5859
int options,
5960
Node currentNode) throws DeferredRaiseException {
@@ -69,17 +70,11 @@ public static void initialize(RubyLanguage language, RubyRegexp regexp, Rope set
6970
// in the Regex object as the "user object". Since ropes are immutable, we need to take this updated copy when
7071
// constructing the final regexp.
7172
final RopeWithEncoding sourceWithEncoding = (RopeWithEncoding) regex.getUserObject();
72-
regexp.source = sourceWithEncoding.getRope();
73-
regexp.encoding = sourceWithEncoding.getEncoding();
74-
regexp.options = regexpOptions;
75-
regexp.regex = regex;
76-
regexp.cachedEncodings = new EncodingCache();
77-
regexp.tregexCache = new TRegexCache();
78-
}
79-
80-
public static RubyRegexp createRubyRegexp(Regex regex, Rope source, RubyEncoding encoding,
81-
RegexpOptions options, EncodingCache cache, TRegexCache tregexCache) {
82-
return new RubyRegexp(regex, source, encoding, options, cache, tregexCache);
73+
return new RubyRegexp(
74+
regex,
75+
sourceWithEncoding.getRope(),
76+
sourceWithEncoding.getEncoding(),
77+
regexpOptions);
8378
}
8479

8580
@CoreMethod(names = "hash")
@@ -237,13 +232,7 @@ public abstract static class AllocateNode extends CoreMethodArrayArgumentsNode {
237232

238233
@Specialization
239234
protected RubyRegexp allocate(RubyClass rubyClass) {
240-
return new RubyRegexp(
241-
null,
242-
null,
243-
null,
244-
RegexpOptions.NULL_OPTIONS,
245-
null,
246-
null);
235+
throw new RaiseException(getContext(), coreExceptions().typeErrorAllocatorUndefinedFor(rubyClass, this));
247236
}
248237

249238
}
@@ -258,30 +247,17 @@ protected boolean fixedEncoding(RubyRegexp regexp) {
258247

259248
}
260249

261-
@CoreMethod(names = "compile", required = 2, lowerFixnum = 2, visibility = Visibility.PRIVATE)
250+
@Primitive(name = "regexp_compile", lowerFixnum = 1)
262251
@ImportStatic(RegexpGuards.class)
263-
public abstract static class RegexpCompileNode extends CoreMethodArrayArgumentsNode {
264-
265-
@Specialization(guards = "isRegexpLiteral(regexp)")
266-
protected RubyRegexp initializeRegexpLiteral(RubyRegexp regexp, Object pattern, int options) {
267-
throw new RaiseException(getContext(), coreExceptions().securityError("can't modify literal regexp", this));
268-
}
252+
public abstract static class RegexpCompileNode extends PrimitiveArrayArgumentsNode {
269253

270-
@Specialization(
271-
guards = { "!isRegexpLiteral(regexp)", "isInitialized(regexp)" })
272-
protected RubyRegexp initializeAlreadyInitialized(RubyRegexp regexp, Object pattern, int options) {
273-
throw new RaiseException(getContext(), coreExceptions().typeError("already initialized regexp", this));
274-
}
275-
276-
@Specialization(
277-
guards = { "libPattern.isRubyString(pattern)", "!isRegexpLiteral(regexp)", "!isInitialized(regexp)" })
278-
protected RubyRegexp initialize(RubyRegexp regexp, Object pattern, int options,
254+
@Specialization(guards = "libPattern.isRubyString(pattern)")
255+
protected RubyRegexp initialize(Object pattern, int options,
279256
@Cached BranchProfile errorProfile,
280257
@CachedLibrary(limit = "2") RubyStringLibrary libPattern) {
281258
try {
282-
RegexpNodes.initialize(
259+
return RegexpNodes.create(
283260
getLanguage(),
284-
regexp,
285261
libPattern.getRope(pattern),
286262
libPattern.getEncoding(pattern),
287263
options,
@@ -290,32 +266,6 @@ protected RubyRegexp initialize(RubyRegexp regexp, Object pattern, int options,
290266
errorProfile.enter();
291267
throw dre.getException(getContext());
292268
}
293-
return regexp;
294-
}
295-
}
296-
297-
@CoreMethod(names = "initialize_copy", required = 1, needsSelf = true)
298-
@ImportStatic(RegexpGuards.class)
299-
public abstract static class RegexpInitializeCopyNode extends CoreMethodArrayArgumentsNode {
300-
301-
@Specialization(guards = "isRegexpLiteral(regexp)")
302-
protected RubyRegexp initializeRegexpLiteral(RubyRegexp regexp, RubyRegexp other) {
303-
throw new RaiseException(getContext(), coreExceptions().securityError("can't modify literal regexp", this));
304-
}
305-
306-
@Specialization(guards = { "!isRegexpLiteral(regexp)", "isInitialized(regexp)" })
307-
protected RubyRegexp initializeAlreadyInitialized(RubyRegexp regexp, RubyRegexp other) {
308-
throw new RaiseException(getContext(), coreExceptions().typeError("already initialized regexp", this));
309-
}
310-
311-
@Specialization(guards = { "!isRegexpLiteral(regexp)", "!isInitialized(regexp)" })
312-
protected RubyRegexp initialize(RubyRegexp regexp, RubyRegexp other) {
313-
regexp.regex = other.regex;
314-
regexp.source = other.source;
315-
regexp.options = other.options;
316-
regexp.cachedEncodings = other.cachedEncodings;
317-
regexp.tregexCache = other.tregexCache;
318-
return regexp;
319269
}
320270
}
321271

src/main/java/org/truffleruby/core/regexp/RubyRegexp.java

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,27 +29,25 @@
2929
@ExportLibrary(InteropLibrary.class)
3030
public class RubyRegexp extends ImmutableRubyObject implements TruffleObject {
3131

32-
public Regex regex;
33-
public Rope source;
34-
public RubyEncoding encoding;
35-
public RegexpOptions options;
36-
public EncodingCache cachedEncodings;
37-
public TRegexCache tregexCache;
32+
public final Regex regex;
33+
public final Rope source;
34+
public final RubyEncoding encoding;
35+
public final RegexpOptions options;
36+
public final EncodingCache cachedEncodings;
37+
public final TRegexCache tregexCache;
3838

3939
public RubyRegexp(
4040
Regex regex,
4141
Rope source,
4242
RubyEncoding encoding,
43-
RegexpOptions options,
44-
EncodingCache encodingCache,
45-
TRegexCache tregexCache) {
43+
RegexpOptions options) {
4644
assert (source == null && encoding == null) || source.encoding == encoding.jcoding;
4745
this.regex = regex;
4846
this.source = source;
4947
this.encoding = encoding;
5048
this.options = options;
51-
this.cachedEncodings = encodingCache;
52-
this.tregexCache = tregexCache;
49+
this.cachedEncodings = new EncodingCache();
50+
this.tregexCache = new TRegexCache();
5351
}
5452

5553
// region InteropLibrary messages

src/main/java/org/truffleruby/core/regexp/TruffleRegexpNodes.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -260,9 +260,7 @@ public RubyRegexp createRegexp(Rope pattern, RubyEncoding encoding) throws Defer
260260
regex,
261261
ropeWithEncoding.getRope(),
262262
ropeWithEncoding.getEncoding(),
263-
regexpOptions,
264-
new EncodingCache(),
265-
new TRegexCache());
263+
regexpOptions);
266264
}
267265
}
268266

src/main/java/org/truffleruby/parser/BodyTranslator.java

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,11 @@
4949
import org.truffleruby.core.numeric.BignumOperations;
5050
import org.truffleruby.core.range.RangeNodesFactory;
5151
import org.truffleruby.core.regexp.ClassicRegexp;
52-
import org.truffleruby.core.regexp.EncodingCache;
5352
import org.truffleruby.core.regexp.InterpolatedRegexpNode;
5453
import org.truffleruby.core.regexp.MatchDataNodes.GetIndexNode;
5554
import org.truffleruby.core.regexp.RegexWarnDeferredCallback;
56-
import org.truffleruby.core.regexp.RegexpNodes;
5755
import org.truffleruby.core.regexp.RegexpOptions;
5856
import org.truffleruby.core.regexp.RubyRegexp;
59-
import org.truffleruby.core.regexp.TRegexCache;
6057
import org.truffleruby.core.regexp.TruffleRegexpNodes;
6158
import org.truffleruby.core.rope.LeafRope;
6259
import org.truffleruby.core.rope.Rope;
@@ -2679,13 +2676,7 @@ public RubyNode visitRegexpNode(RegexpParseNode node) {
26792676
// in the Regex object as the "user object". Since ropes are immutable, we need to take this updated copy when
26802677
// constructing the final regexp.
26812678
final RopeWithEncoding updatedRope = (RopeWithEncoding) regex.getUserObject();
2682-
final RubyRegexp regexp = RegexpNodes.createRubyRegexp(
2683-
regex,
2684-
updatedRope.getRope(),
2685-
updatedRope.getEncoding(),
2686-
options,
2687-
new EncodingCache(),
2688-
new TRegexCache());
2679+
final RubyRegexp regexp = new RubyRegexp(regex, updatedRope.getRope(), updatedRope.getEncoding(), options);
26892680

26902681
final ObjectLiteralNode literalNode = new ObjectLiteralNode(regexp);
26912682
literalNode.unsafeSetSourceSection(node.getPosition());

src/main/ruby/truffleruby/core/regexp.rb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,6 @@ class Regexp
5151

5252
OPTION_MASK = IGNORECASE | EXTENDED | MULTILINE | FIXEDENCODING | NOENCODING | DONT_CAPTURE_GROUP | CAPTURE_GROUP
5353

54-
class << self
55-
alias_method :compile, :new
56-
end
57-
5854
def self.try_convert(obj)
5955
Truffle::Type.try_convert obj, Regexp, :to_regexp
6056
end
@@ -134,7 +130,7 @@ def self.union(*patterns)
134130
end
135131
Truffle::Graal.always_split(method(:union))
136132

137-
def initialize(pattern, opts=nil, lang=nil)
133+
def self.new(pattern, opts=nil, lang=nil)
138134
if Primitive.object_kind_of?(pattern, Regexp)
139135
opts = pattern.options
140136
pattern = pattern.source
@@ -151,7 +147,11 @@ def initialize(pattern, opts=nil, lang=nil)
151147
code = lang[0] if lang
152148
opts |= NOENCODING if code == ?n or code == ?N
153149

154-
compile pattern, opts # may be overridden by subclasses
150+
Primitive.regexp_compile pattern, opts # may be overridden by subclasses
151+
end
152+
153+
class << self
154+
alias_method :compile, :new
155155
end
156156

157157
def =~(str)

test/mri/excludes/TestRegexp.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,4 @@
2929
exclude :test_to_s_extended_subexp, "needs investigation"
3030
exclude :test_union, "needs investigation"
3131
exclude :test_invalid_free_at_parse_depth_limit_over, "needs investigation"
32+
exclude :test_dup, "initialize_copy not implemented in TruffleRuby"

0 commit comments

Comments
 (0)