Skip to content

Commit 9cb25df

Browse files
committedJan 23, 2018
Merge branch 'jruby-9.1'
2 parents 16988b6 + ba67802 commit 9cb25df

13 files changed

+96
-75
lines changed
 

‎core/src/main/java/org/jruby/Ruby.java

+1
Original file line numberDiff line numberDiff line change
@@ -4707,6 +4707,7 @@ public RubyString freezeAndDedupString(RubyString string) {
47074707
deduped = string.strDup(this);
47084708
deduped.setFrozen(true);
47094709
}
4710+
47104711
return deduped;
47114712
}
47124713

‎core/src/main/java/org/jruby/RubyClass.java

+44-42
Original file line numberDiff line numberDiff line change
@@ -1098,19 +1098,27 @@ public final Collection<RubyClass> subclasses() {
10981098
return subclasses(false);
10991099
}
11001100

1101-
public synchronized Collection<RubyClass> subclasses(boolean includeDescendants) {
1101+
public Collection<RubyClass> subclasses(boolean includeDescendants) {
11021102
Set<RubyClass> subclasses = this.subclasses;
11031103
if (subclasses != null) {
1104-
Collection<RubyClass> mine = new ArrayList<>(subclasses);
1104+
Collection<RubyClass> mine = new ArrayList<>();
1105+
subclassesInner(mine, includeDescendants);
1106+
1107+
return mine;
1108+
}
1109+
return Collections.EMPTY_LIST;
1110+
}
1111+
1112+
private void subclassesInner(Collection<RubyClass> mine, boolean includeDescendants) {
1113+
Set<RubyClass> subclasses = this.subclasses;
1114+
if (subclasses != null) {
1115+
mine.addAll(subclasses);
11051116
if (includeDescendants) {
11061117
for (RubyClass klass: subclasses) {
1107-
mine.addAll(klass.subclasses(includeDescendants));
1118+
klass.subclassesInner(mine, includeDescendants);
11081119
}
11091120
}
1110-
1111-
return mine;
11121121
}
1113-
return Collections.EMPTY_LIST;
11141122
}
11151123

11161124
/**
@@ -1122,26 +1130,31 @@ public synchronized Collection<RubyClass> subclasses(boolean includeDescendants)
11221130
*
11231131
* @param subclass The subclass to add
11241132
*/
1125-
public synchronized void addSubclass(RubyClass subclass) {
1126-
synchronized (runtime.getHierarchyLock()) {
1127-
Set<RubyClass> subclasses = this.subclasses;
1128-
if (subclasses == null) this.subclasses = subclasses = new WeakHashSet<>(4);
1129-
subclasses.add(subclass);
1133+
public void addSubclass(RubyClass subclass) {
1134+
Set<RubyClass> subclasses = this.subclasses;
1135+
if (subclasses == null) {
1136+
// check again
1137+
synchronized (this) {
1138+
subclasses = this.subclasses;
1139+
if (subclasses == null) {
1140+
this.subclasses = subclasses = Collections.synchronizedSet(new WeakHashSet<RubyClass>(4));
1141+
}
1142+
}
11301143
}
1144+
1145+
subclasses.add(subclass);
11311146
}
11321147

11331148
/**
11341149
* Remove a subclass from the weak set of subclasses.
11351150
*
11361151
* @param subclass The subclass to remove
11371152
*/
1138-
public synchronized void removeSubclass(RubyClass subclass) {
1139-
synchronized (runtime.getHierarchyLock()) {
1140-
Set<RubyClass> subclasses = this.subclasses;
1141-
if (subclasses == null) return;
1153+
public void removeSubclass(RubyClass subclass) {
1154+
Set<RubyClass> subclasses = this.subclasses;
1155+
if (subclasses == null) return;
11421156

1143-
subclasses.remove(subclass);
1144-
}
1157+
subclasses.remove(subclass);
11451158
}
11461159

11471160
/**
@@ -1150,25 +1163,21 @@ public synchronized void removeSubclass(RubyClass subclass) {
11501163
* @param subclass The subclass to remove
11511164
* @param newSubclass The subclass to replace it with
11521165
*/
1153-
public synchronized void replaceSubclass(RubyClass subclass, RubyClass newSubclass) {
1154-
synchronized (runtime.getHierarchyLock()) {
1155-
Set<RubyClass> subclasses = this.subclasses;
1156-
if (subclasses == null) return;
1166+
public void replaceSubclass(RubyClass subclass, RubyClass newSubclass) {
1167+
Set<RubyClass> subclasses = this.subclasses;
1168+
if (subclasses == null) return;
11571169

1158-
subclasses.remove(subclass);
1159-
subclasses.add(newSubclass);
1160-
}
1170+
subclasses.remove(subclass);
1171+
subclasses.add(newSubclass);
11611172
}
11621173

11631174
@Override
11641175
public void becomeSynchronized() {
11651176
// make this class and all subclasses sync
1166-
synchronized (runtime.getHierarchyLock()) {
1167-
super.becomeSynchronized();
1168-
Set<RubyClass> subclasses = this.subclasses;
1169-
if (subclasses != null) {
1170-
for (RubyClass subclass : subclasses) subclass.becomeSynchronized();
1171-
}
1177+
super.becomeSynchronized();
1178+
Set<RubyClass> subclasses = this.subclasses;
1179+
if (subclasses != null) {
1180+
for (RubyClass subclass : subclasses) subclass.becomeSynchronized();
11721181
}
11731182
}
11741183

@@ -1188,11 +1197,9 @@ public void becomeSynchronized() {
11881197
public void invalidateCacheDescendants() {
11891198
super.invalidateCacheDescendants();
11901199

1191-
synchronized (runtime.getHierarchyLock()) {
1192-
Set<RubyClass> subclasses = this.subclasses;
1193-
if (subclasses != null) {
1194-
for (RubyClass subclass : subclasses) subclass.invalidateCacheDescendants();
1195-
}
1200+
Set<RubyClass> subclasses = this.subclasses;
1201+
if (subclasses != null) {
1202+
for (RubyClass subclass : subclasses) subclass.invalidateCacheDescendants();
11961203
}
11971204
}
11981205

@@ -1208,12 +1215,7 @@ public void addInvalidatorsAndFlush(List<Invalidator> invalidators) {
12081215
if (subclasses == null || subclasses.isEmpty()) return;
12091216

12101217
// cascade into subclasses
1211-
synchronized (runtime.getHierarchyLock()) {
1212-
subclasses = this.subclasses;
1213-
if (subclasses != null) {
1214-
for (RubyClass subclass : subclasses) subclass.addInvalidatorsAndFlush(invalidators);
1215-
}
1216-
}
1218+
for (RubyClass subclass : subclasses) subclass.addInvalidatorsAndFlush(invalidators);
12171219
}
12181220

12191221
public final Ruby getClassRuntime() {
@@ -2326,7 +2328,7 @@ public IRubyObject invoke(ThreadContext context, IRubyObject self, String name,
23262328
protected final Ruby runtime;
23272329
private ObjectAllocator allocator; // the default allocator
23282330
protected ObjectMarshal marshal;
2329-
private Set<RubyClass> subclasses;
2331+
private volatile Set<RubyClass> subclasses;
23302332
public static final int CS_IDX_INITIALIZE = 0;
23312333
public enum CS_NAMES {
23322334
INITIALIZE("initialize");

‎core/src/main/java/org/jruby/RubyModule.java

+26-4
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
import org.jruby.runtime.ivars.MethodData;
105105
import org.jruby.runtime.marshal.MarshalStream;
106106
import org.jruby.runtime.marshal.UnmarshalStream;
107+
import org.jruby.runtime.opto.ConstantInvalidator;
107108
import org.jruby.runtime.opto.Invalidator;
108109
import org.jruby.runtime.opto.OptoFactory;
109110
import org.jruby.runtime.profile.MethodEnhancer;
@@ -1360,13 +1361,18 @@ private CacheEntry cacheHit(String name) {
13601361
return null;
13611362
}
13621363

1363-
private void invalidateConstantCacheForModuleInclusion(RubyModule module)
1364-
{
1364+
private void invalidateConstantCacheForModuleInclusion(RubyModule module) {
1365+
Map<String, Invalidator> invalidators = null;
13651366
for (RubyModule mod : gatherModules(module)) {
1366-
for (String key : mod.getConstantMap().keySet()) {
1367-
invalidateConstantCache(key);
1367+
for (String name : mod.getConstantMap().keySet()) {
1368+
if (invalidators == null) invalidators = new HashMap<>();
1369+
invalidators.put(name, getRuntime().getConstantInvalidator(name));
13681370
}
13691371
}
1372+
if (invalidators != null) {
1373+
List<Invalidator> values = new ArrayList(invalidators.values());
1374+
values.get(0).invalidateAll(values);
1375+
}
13701376
}
13711377

13721378
protected static abstract class CacheEntryFactory {
@@ -1563,6 +1569,19 @@ protected void invalidateConstantCache(String constantName) {
15631569
getRuntime().getConstantInvalidator(constantName).invalidate();
15641570
}
15651571

1572+
protected void invalidateConstantCaches(Set<String> constantNames) {
1573+
if (constantNames.size() > 0) {
1574+
Ruby runtime = getRuntime();
1575+
1576+
List<Invalidator> constantInvalidators = new ArrayList<>(constantNames.size());
1577+
for (String name : constantNames) {
1578+
constantInvalidators.add(runtime.getConstantInvalidator(name));
1579+
}
1580+
1581+
constantInvalidators.get(0).invalidateAll(constantInvalidators);
1582+
}
1583+
}
1584+
15661585
/**
15671586
* Search through this module and supermodules for method definitions. Cache superclass definitions in this class.
15681587
*
@@ -2601,6 +2620,9 @@ public RubyModule append_features(IRubyObject include) {
26012620
*/
26022621
@JRubyMethod(name = "extend_object", required = 1, visibility = PRIVATE)
26032622
public IRubyObject extend_object(IRubyObject obj) {
2623+
if (!isModule()) {
2624+
throw getRuntime().newTypeError(this, getRuntime().getModule());
2625+
}
26042626
obj.getSingletonClass().includeModule(this);
26052627
return obj;
26062628
}

‎core/src/main/java/org/jruby/RubyRational.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -765,7 +765,7 @@ public IRubyObject op_cmp(ThreadContext context, IRubyObject other) {
765765
}
766766
return f_cmp(context, f_sub(context, num1, num2), RubyFixnum.zero(context.runtime));
767767
}
768-
return coerceBin(context, sites(context).op_cmp, other);
768+
return coerceCmp(context, sites(context).op_cmp, other);
769769
}
770770

771771
/** nurat_equal_p
@@ -807,6 +807,13 @@ public IRubyObject op_coerce(ThreadContext context, IRubyObject other) {
807807
return runtime.newArray(other, f_to_f(context, this));
808808
} else if (other instanceof RubyRational) {
809809
return runtime.newArray(other, this);
810+
} else if (other instanceof RubyComplex) {
811+
RubyComplex otherComplex = (RubyComplex)other;
812+
if (k_exact_p(otherComplex.getImage()) && f_zero_p(context, otherComplex.getImage())) {
813+
return runtime.newArray(RubyRational.newRationalBang(context, getMetaClass(), otherComplex.getReal()), this);
814+
} else {
815+
return runtime.newArray(other, RubyComplex.newComplexCanonicalize(context, this));
816+
}
810817
}
811818
throw runtime.newTypeError(other.getMetaClass() + " can't be coerced into " + getMetaClass());
812819
}

‎core/src/main/java/org/jruby/RubyString.java

+4
Original file line numberDiff line numberDiff line change
@@ -5311,6 +5311,10 @@ private RubySymbol to_sym() {
53115311
RubySymbol specialCaseIntern = checkSpecialCasesIntern(value);
53125312
if (specialCaseIntern != null) return specialCaseIntern;
53135313

5314+
if (scanForCodeRange() == CR_BROKEN) {
5315+
throw getRuntime().newEncodingError("invalid symbol in encoding " + getEncoding() + " :" + inspect());
5316+
}
5317+
53145318
RubySymbol symbol = getRuntime().getSymbolTable().getSymbol(value);
53155319
if (symbol.getBytes() == value) shareLevel = SHARE_LEVEL_BYTELIST;
53165320
return symbol;

‎core/src/main/java/org/jruby/RubySymbol.java

+8-13
Original file line numberDiff line numberDiff line change
@@ -256,27 +256,22 @@ public IRubyObject inspect(ThreadContext context) {
256256
}
257257

258258
final RubyString inspect(final Ruby runtime) {
259-
ByteList result = new ByteList(symbolBytes.getRealSize() + 1);
260-
result.setEncoding(symbolBytes.getEncoding());
261-
result.append((byte)':');
262-
result.append(symbolBytes);
263-
264259
// TODO: 1.9 rb_enc_symname_p
265260
Encoding resenc = runtime.getDefaultInternalEncoding();
266261
if (resenc == null) resenc = runtime.getDefaultExternalEncoding();
267262

268-
RubyString str = RubyString.newString(runtime, result);
263+
RubyString str = RubyString.newString(runtime, symbolBytes);
269264

270-
if (isPrintable() && (resenc.equals(symbolBytes.getEncoding()) || str.isAsciiOnly()) && isSymbolName19(symbol)) {
271-
return str;
265+
if (!(isPrintable() && (resenc.equals(symbolBytes.getEncoding()) || str.isAsciiOnly()) && isSymbolName19(symbol))) {
266+
str = str.inspect(runtime);
272267
}
273268

274-
str = str.inspect(runtime);
275-
ByteList bytes = str.getByteList();
276-
bytes.set(0, ':');
277-
bytes.set(1, '"');
269+
ByteList result = new ByteList(str.getByteList().getRealSize() + 1);
270+
result.setEncoding(str.getEncoding());
271+
result.append((byte)':');
272+
result.append(str.getBytes());
278273

279-
return str;
274+
return RubyString.newString(runtime, result);
280275
}
281276

282277
@Deprecated

‎core/src/main/java/org/jruby/lexer/LexingCommon.java

-6
Original file line numberDiff line numberDiff line change
@@ -984,9 +984,6 @@ public static int magicCommentMarker(ByteList str, int begin) {
984984
return -1;
985985
}
986986

987-
public static final String magicString = "^[^\\S]*([^\\s\'\":;]+)\\s*:\\s*(\"(?:\\\\.|[^\"])*\"|[^\"\\s;]+)[\\s;]*[^\\S]*$";
988-
public static final Regex magicRegexp = new Regex(magicString.getBytes(), 0, magicString.length(), 0, Encoding.load("ASCII"));
989-
990987
public boolean parser_magic_comment(ByteList magicLine) {
991988
boolean indicator = false;
992989
int vbeg, vend;
@@ -1006,9 +1003,6 @@ public boolean parser_magic_comment(ByteList magicLine) {
10061003

10071004
/* %r"([^\\s\'\":;]+)\\s*:\\s*(\"(?:\\\\.|[^\"])*\"|[^\"\\s;]+)[\\s;]*" */
10081005
while (length > 0) {
1009-
int i;
1010-
long n = 0;
1011-
10121006
for (; length > 0; str++, --length) {
10131007
char c = magicLine.charAt(str);
10141008

‎core/src/main/java/org/jruby/lexer/yacc/RubyLexer.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -905,8 +905,10 @@ private int yylex() throws IOException {
905905
continue;
906906
case '#': { /* it's a comment */
907907
this.tokenSeen = tokenSeen;
908-
if (!parser_magic_comment(lexb.makeShared(lex_p, lex_pend - lex_p))) {
909-
if (comment_at_top()) set_file_encoding(lex_p, lex_pend);
908+
if (!tokenSeen || !warnings.isVerbose()) {
909+
if (!parser_magic_comment(lexb.makeShared(lex_p, lex_pend - lex_p))) {
910+
if (comment_at_top()) set_file_encoding(lex_p, lex_pend);
911+
}
910912
}
911913
lex_p = lex_pend;
912914
}
@@ -1916,6 +1918,7 @@ private int questionMark() throws IOException {
19161918
}
19171919

19181920
ByteList oneCharBL = new ByteList(1);
1921+
oneCharBL.setEncoding(getEncoding());
19191922
oneCharBL.append(c);
19201923
yaccValue = new StrNode(getPosition(), oneCharBL);
19211924
setState(EXPR_END);

‎test/mri/excludes/Rational_Test.rb

-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
exclude :test_cmp, "needs investigation"
2-
exclude :test_coerce, "needs investigation"
31
exclude :test_coerce2, "needs investigation"
42
exclude :test_conv, "needs investigation"
53
exclude :test_marshal, "needs investigation"

‎test/mri/excludes/TestClass.rb

-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
exclude :test_cannot_reinitialize_class_with_initialize_copy, "broken subprocess logic in setup"
22
exclude :test_check_inheritable, "needs investigation"
3-
exclude :test_extend_object, "needs investigation"
43
exclude :test_invalid_jump_from_class_definition, "needs investigation"
54
exclude :test_method_redefinition, "needs investigation"
65
exclude :test_redefine_private_class, "needs investigation"

‎test/mri/excludes/TestM17N.rb

-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,3 @@
22
exclude :test_nonascii_method_name, "lexer is not pulling mbc characters off the wire correctly"
33
exclude :test_split, "our impl has diverged and does not appear to handle encoded null char properly"
44
exclude :test_symbol, "management of differently-encoded symbols is not right"
5-
exclude :test_symbol_op, "some symbols are created early and do not have UTF-8 encoding; management of differently-encoded symbols is not right"

‎test/mri/excludes/TestStringchar.rb

-1
This file was deleted.

‎test/mri/excludes/TestSymbol.rb

-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
exclude :test_casecmp?, "missing 2.4 case-folding logic (#4731)"
2-
exclude :test_ascii_incomat_inspect, "needs investigation"
31
exclude :test_inspect, "needs investigation"
42
exclude :test_to_proc_arg, "we have plans to do different caching here, see 69662ab8cd1616a2ee076488226a473648fc6267"
53
exclude :test_to_proc_binding, "needs investigation #4303"

0 commit comments

Comments
 (0)
Please sign in to comment.