Skip to content

Commit

Permalink
Showing 13 changed files with 96 additions and 75 deletions.
1 change: 1 addition & 0 deletions core/src/main/java/org/jruby/Ruby.java
Original file line number Diff line number Diff line change
@@ -4707,6 +4707,7 @@ public RubyString freezeAndDedupString(RubyString string) {
deduped = string.strDup(this);
deduped.setFrozen(true);
}

return deduped;
}

86 changes: 44 additions & 42 deletions core/src/main/java/org/jruby/RubyClass.java
Original file line number Diff line number Diff line change
@@ -1098,19 +1098,27 @@ public final Collection<RubyClass> subclasses() {
return subclasses(false);
}

public synchronized Collection<RubyClass> subclasses(boolean includeDescendants) {
public Collection<RubyClass> subclasses(boolean includeDescendants) {
Set<RubyClass> subclasses = this.subclasses;
if (subclasses != null) {
Collection<RubyClass> mine = new ArrayList<>(subclasses);
Collection<RubyClass> mine = new ArrayList<>();
subclassesInner(mine, includeDescendants);

return mine;
}
return Collections.EMPTY_LIST;
}

private void subclassesInner(Collection<RubyClass> mine, boolean includeDescendants) {
Set<RubyClass> subclasses = this.subclasses;
if (subclasses != null) {
mine.addAll(subclasses);
if (includeDescendants) {
for (RubyClass klass: subclasses) {
mine.addAll(klass.subclasses(includeDescendants));
klass.subclassesInner(mine, includeDescendants);
}
}

return mine;
}
return Collections.EMPTY_LIST;
}

/**
@@ -1122,26 +1130,31 @@ public synchronized Collection<RubyClass> subclasses(boolean includeDescendants)
*
* @param subclass The subclass to add
*/
public synchronized void addSubclass(RubyClass subclass) {
synchronized (runtime.getHierarchyLock()) {
Set<RubyClass> subclasses = this.subclasses;
if (subclasses == null) this.subclasses = subclasses = new WeakHashSet<>(4);
subclasses.add(subclass);
public void addSubclass(RubyClass subclass) {
Set<RubyClass> subclasses = this.subclasses;
if (subclasses == null) {
// check again
synchronized (this) {
subclasses = this.subclasses;
if (subclasses == null) {
this.subclasses = subclasses = Collections.synchronizedSet(new WeakHashSet<RubyClass>(4));
}
}
}

subclasses.add(subclass);
}

/**
* Remove a subclass from the weak set of subclasses.
*
* @param subclass The subclass to remove
*/
public synchronized void removeSubclass(RubyClass subclass) {
synchronized (runtime.getHierarchyLock()) {
Set<RubyClass> subclasses = this.subclasses;
if (subclasses == null) return;
public void removeSubclass(RubyClass subclass) {
Set<RubyClass> subclasses = this.subclasses;
if (subclasses == null) return;

subclasses.remove(subclass);
}
subclasses.remove(subclass);
}

/**
@@ -1150,25 +1163,21 @@ public synchronized void removeSubclass(RubyClass subclass) {
* @param subclass The subclass to remove
* @param newSubclass The subclass to replace it with
*/
public synchronized void replaceSubclass(RubyClass subclass, RubyClass newSubclass) {
synchronized (runtime.getHierarchyLock()) {
Set<RubyClass> subclasses = this.subclasses;
if (subclasses == null) return;
public void replaceSubclass(RubyClass subclass, RubyClass newSubclass) {
Set<RubyClass> subclasses = this.subclasses;
if (subclasses == null) return;

subclasses.remove(subclass);
subclasses.add(newSubclass);
}
subclasses.remove(subclass);
subclasses.add(newSubclass);
}

@Override
public void becomeSynchronized() {
// make this class and all subclasses sync
synchronized (runtime.getHierarchyLock()) {
super.becomeSynchronized();
Set<RubyClass> subclasses = this.subclasses;
if (subclasses != null) {
for (RubyClass subclass : subclasses) subclass.becomeSynchronized();
}
super.becomeSynchronized();
Set<RubyClass> subclasses = this.subclasses;
if (subclasses != null) {
for (RubyClass subclass : subclasses) subclass.becomeSynchronized();
}
}

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

synchronized (runtime.getHierarchyLock()) {
Set<RubyClass> subclasses = this.subclasses;
if (subclasses != null) {
for (RubyClass subclass : subclasses) subclass.invalidateCacheDescendants();
}
Set<RubyClass> subclasses = this.subclasses;
if (subclasses != null) {
for (RubyClass subclass : subclasses) subclass.invalidateCacheDescendants();
}
}

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

// cascade into subclasses
synchronized (runtime.getHierarchyLock()) {
subclasses = this.subclasses;
if (subclasses != null) {
for (RubyClass subclass : subclasses) subclass.addInvalidatorsAndFlush(invalidators);
}
}
for (RubyClass subclass : subclasses) subclass.addInvalidatorsAndFlush(invalidators);
}

public final Ruby getClassRuntime() {
@@ -2326,7 +2328,7 @@ public IRubyObject invoke(ThreadContext context, IRubyObject self, String name,
protected final Ruby runtime;
private ObjectAllocator allocator; // the default allocator
protected ObjectMarshal marshal;
private Set<RubyClass> subclasses;
private volatile Set<RubyClass> subclasses;
public static final int CS_IDX_INITIALIZE = 0;
public enum CS_NAMES {
INITIALIZE("initialize");
30 changes: 26 additions & 4 deletions core/src/main/java/org/jruby/RubyModule.java
Original file line number Diff line number Diff line change
@@ -104,6 +104,7 @@
import org.jruby.runtime.ivars.MethodData;
import org.jruby.runtime.marshal.MarshalStream;
import org.jruby.runtime.marshal.UnmarshalStream;
import org.jruby.runtime.opto.ConstantInvalidator;
import org.jruby.runtime.opto.Invalidator;
import org.jruby.runtime.opto.OptoFactory;
import org.jruby.runtime.profile.MethodEnhancer;
@@ -1360,13 +1361,18 @@ private CacheEntry cacheHit(String name) {
return null;
}

private void invalidateConstantCacheForModuleInclusion(RubyModule module)
{
private void invalidateConstantCacheForModuleInclusion(RubyModule module) {
Map<String, Invalidator> invalidators = null;
for (RubyModule mod : gatherModules(module)) {
for (String key : mod.getConstantMap().keySet()) {
invalidateConstantCache(key);
for (String name : mod.getConstantMap().keySet()) {
if (invalidators == null) invalidators = new HashMap<>();
invalidators.put(name, getRuntime().getConstantInvalidator(name));
}
}
if (invalidators != null) {
List<Invalidator> values = new ArrayList(invalidators.values());
values.get(0).invalidateAll(values);
}
}

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

protected void invalidateConstantCaches(Set<String> constantNames) {
if (constantNames.size() > 0) {
Ruby runtime = getRuntime();

List<Invalidator> constantInvalidators = new ArrayList<>(constantNames.size());
for (String name : constantNames) {
constantInvalidators.add(runtime.getConstantInvalidator(name));
}

constantInvalidators.get(0).invalidateAll(constantInvalidators);
}
}

/**
* Search through this module and supermodules for method definitions. Cache superclass definitions in this class.
*
@@ -2601,6 +2620,9 @@ public RubyModule append_features(IRubyObject include) {
*/
@JRubyMethod(name = "extend_object", required = 1, visibility = PRIVATE)
public IRubyObject extend_object(IRubyObject obj) {
if (!isModule()) {
throw getRuntime().newTypeError(this, getRuntime().getModule());
}
obj.getSingletonClass().includeModule(this);
return obj;
}
9 changes: 8 additions & 1 deletion core/src/main/java/org/jruby/RubyRational.java
Original file line number Diff line number Diff line change
@@ -765,7 +765,7 @@ public IRubyObject op_cmp(ThreadContext context, IRubyObject other) {
}
return f_cmp(context, f_sub(context, num1, num2), RubyFixnum.zero(context.runtime));
}
return coerceBin(context, sites(context).op_cmp, other);
return coerceCmp(context, sites(context).op_cmp, other);
}

/** nurat_equal_p
@@ -807,6 +807,13 @@ public IRubyObject op_coerce(ThreadContext context, IRubyObject other) {
return runtime.newArray(other, f_to_f(context, this));
} else if (other instanceof RubyRational) {
return runtime.newArray(other, this);
} else if (other instanceof RubyComplex) {
RubyComplex otherComplex = (RubyComplex)other;
if (k_exact_p(otherComplex.getImage()) && f_zero_p(context, otherComplex.getImage())) {
return runtime.newArray(RubyRational.newRationalBang(context, getMetaClass(), otherComplex.getReal()), this);
} else {
return runtime.newArray(other, RubyComplex.newComplexCanonicalize(context, this));
}
}
throw runtime.newTypeError(other.getMetaClass() + " can't be coerced into " + getMetaClass());
}
4 changes: 4 additions & 0 deletions core/src/main/java/org/jruby/RubyString.java
Original file line number Diff line number Diff line change
@@ -5311,6 +5311,10 @@ private RubySymbol to_sym() {
RubySymbol specialCaseIntern = checkSpecialCasesIntern(value);
if (specialCaseIntern != null) return specialCaseIntern;

if (scanForCodeRange() == CR_BROKEN) {
throw getRuntime().newEncodingError("invalid symbol in encoding " + getEncoding() + " :" + inspect());
}

RubySymbol symbol = getRuntime().getSymbolTable().getSymbol(value);
if (symbol.getBytes() == value) shareLevel = SHARE_LEVEL_BYTELIST;
return symbol;
21 changes: 8 additions & 13 deletions core/src/main/java/org/jruby/RubySymbol.java
Original file line number Diff line number Diff line change
@@ -256,27 +256,22 @@ public IRubyObject inspect(ThreadContext context) {
}

final RubyString inspect(final Ruby runtime) {
ByteList result = new ByteList(symbolBytes.getRealSize() + 1);
result.setEncoding(symbolBytes.getEncoding());
result.append((byte)':');
result.append(symbolBytes);

// TODO: 1.9 rb_enc_symname_p
Encoding resenc = runtime.getDefaultInternalEncoding();
if (resenc == null) resenc = runtime.getDefaultExternalEncoding();

RubyString str = RubyString.newString(runtime, result);
RubyString str = RubyString.newString(runtime, symbolBytes);

if (isPrintable() && (resenc.equals(symbolBytes.getEncoding()) || str.isAsciiOnly()) && isSymbolName19(symbol)) {
return str;
if (!(isPrintable() && (resenc.equals(symbolBytes.getEncoding()) || str.isAsciiOnly()) && isSymbolName19(symbol))) {
str = str.inspect(runtime);
}

str = str.inspect(runtime);
ByteList bytes = str.getByteList();
bytes.set(0, ':');
bytes.set(1, '"');
ByteList result = new ByteList(str.getByteList().getRealSize() + 1);
result.setEncoding(str.getEncoding());
result.append((byte)':');
result.append(str.getBytes());

return str;
return RubyString.newString(runtime, result);
}

@Deprecated
6 changes: 0 additions & 6 deletions core/src/main/java/org/jruby/lexer/LexingCommon.java
Original file line number Diff line number Diff line change
@@ -984,9 +984,6 @@ public static int magicCommentMarker(ByteList str, int begin) {
return -1;
}

public static final String magicString = "^[^\\S]*([^\\s\'\":;]+)\\s*:\\s*(\"(?:\\\\.|[^\"])*\"|[^\"\\s;]+)[\\s;]*[^\\S]*$";
public static final Regex magicRegexp = new Regex(magicString.getBytes(), 0, magicString.length(), 0, Encoding.load("ASCII"));

public boolean parser_magic_comment(ByteList magicLine) {
boolean indicator = false;
int vbeg, vend;
@@ -1006,9 +1003,6 @@ public boolean parser_magic_comment(ByteList magicLine) {

/* %r"([^\\s\'\":;]+)\\s*:\\s*(\"(?:\\\\.|[^\"])*\"|[^\"\\s;]+)[\\s;]*" */
while (length > 0) {
int i;
long n = 0;

for (; length > 0; str++, --length) {
char c = magicLine.charAt(str);

7 changes: 5 additions & 2 deletions core/src/main/java/org/jruby/lexer/yacc/RubyLexer.java
Original file line number Diff line number Diff line change
@@ -905,8 +905,10 @@ private int yylex() throws IOException {
continue;
case '#': { /* it's a comment */
this.tokenSeen = tokenSeen;
if (!parser_magic_comment(lexb.makeShared(lex_p, lex_pend - lex_p))) {
if (comment_at_top()) set_file_encoding(lex_p, lex_pend);
if (!tokenSeen || !warnings.isVerbose()) {
if (!parser_magic_comment(lexb.makeShared(lex_p, lex_pend - lex_p))) {
if (comment_at_top()) set_file_encoding(lex_p, lex_pend);
}
}
lex_p = lex_pend;
}
@@ -1916,6 +1918,7 @@ private int questionMark() throws IOException {
}

ByteList oneCharBL = new ByteList(1);
oneCharBL.setEncoding(getEncoding());
oneCharBL.append(c);
yaccValue = new StrNode(getPosition(), oneCharBL);
setState(EXPR_END);
2 changes: 0 additions & 2 deletions test/mri/excludes/Rational_Test.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
exclude :test_cmp, "needs investigation"
exclude :test_coerce, "needs investigation"
exclude :test_coerce2, "needs investigation"
exclude :test_conv, "needs investigation"
exclude :test_marshal, "needs investigation"
1 change: 0 additions & 1 deletion test/mri/excludes/TestClass.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
exclude :test_cannot_reinitialize_class_with_initialize_copy, "broken subprocess logic in setup"
exclude :test_check_inheritable, "needs investigation"
exclude :test_extend_object, "needs investigation"
exclude :test_invalid_jump_from_class_definition, "needs investigation"
exclude :test_method_redefinition, "needs investigation"
exclude :test_redefine_private_class, "needs investigation"
1 change: 0 additions & 1 deletion test/mri/excludes/TestM17N.rb
Original file line number Diff line number Diff line change
@@ -2,4 +2,3 @@
exclude :test_nonascii_method_name, "lexer is not pulling mbc characters off the wire correctly"
exclude :test_split, "our impl has diverged and does not appear to handle encoded null char properly"
exclude :test_symbol, "management of differently-encoded symbols is not right"
exclude :test_symbol_op, "some symbols are created early and do not have UTF-8 encoding; management of differently-encoded symbols is not right"
1 change: 0 additions & 1 deletion test/mri/excludes/TestStringchar.rb

This file was deleted.

2 changes: 0 additions & 2 deletions test/mri/excludes/TestSymbol.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
exclude :test_casecmp?, "missing 2.4 case-folding logic (#4731)"
exclude :test_ascii_incomat_inspect, "needs investigation"
exclude :test_inspect, "needs investigation"
exclude :test_to_proc_arg, "we have plans to do different caching here, see 69662ab8cd1616a2ee076488226a473648fc6267"
exclude :test_to_proc_binding, "needs investigation #4303"

0 comments on commit 9cb25df

Please sign in to comment.