Skip to content

Commit

Permalink
Showing 241 changed files with 837 additions and 622 deletions.
23 changes: 23 additions & 0 deletions core/src/main/java/org/jruby/Ruby.java
Original file line number Diff line number Diff line change
@@ -4807,6 +4807,24 @@ public Object constant() {
return constant;
}

/**
* Set the base Class#new method.
*
* @param baseNewMethod
*/
public void setBaseNewMethod(DynamicMethod baseNewMethod) {
this.baseNewMethod = baseNewMethod;
}

/**
* Get the base Class#new method.
*
* @return the base Class#new method
*/
public DynamicMethod getBaseNewMethod() {
return baseNewMethod;
}

@Deprecated
public int getSafeLevel() {
return 0;
@@ -5160,4 +5178,9 @@ public void addToObjectSpace(boolean useObjectSpace, IRubyObject object) {
* accesses.
*/
private final Object constant;

/**
* The built-in Class#new method, so we can bind more directly to allocate and initialize.
*/
private DynamicMethod baseNewMethod;
}
2 changes: 2 additions & 0 deletions core/src/main/java/org/jruby/RubyClass.java
Original file line number Diff line number Diff line change
@@ -113,6 +113,8 @@ public static void createClassClass(Ruby runtime, RubyClass classClass) {
classClass.undefineMethod("extend_object");

classClass.defineAnnotatedMethods(RubyClass.class);

runtime.setBaseNewMethod(classClass.searchMethod("new"));
}

public static final ObjectAllocator CLASS_ALLOCATOR = new ObjectAllocator() {
240 changes: 116 additions & 124 deletions core/src/main/java/org/jruby/ir/targets/Bootstrap.java
Original file line number Diff line number Diff line change
@@ -12,7 +12,6 @@
import org.jruby.internal.runtime.methods.*;
import org.jruby.ir.IRScope;
import org.jruby.ir.JIT;
import org.jruby.ir.operands.UndefinedValue;
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.Binding;
@@ -137,22 +136,6 @@ public static CallSite ivar(Lookup lookup, String name, MethodType type) throws
return site;
}

public static CallSite searchConst(Lookup lookup, String name, MethodType type, int noPrivateConsts) {
MutableCallSite site = new MutableCallSite(type);
String[] bits = name.split(":");
String constName = bits[1];

MethodHandle handle = Binder
.from(lookup, type)
.append(site, constName.intern())
.append(noPrivateConsts == 0 ? false : true)
.invokeStaticQuiet(LOOKUP, Bootstrap.class, bits[0]);

site.setTarget(handle);

return site;
}

public static Handle string() {
return new Handle(Opcodes.H_INVOKESTATIC, p(Bootstrap.class), "string", sig(CallSite.class, Lookup.class, String.class, MethodType.class, String.class, String.class, int.class));
}
@@ -181,10 +164,6 @@ public static Handle ivar() {
return new Handle(Opcodes.H_INVOKESTATIC, p(Bootstrap.class), "ivar", sig(CallSite.class, Lookup.class, String.class, MethodType.class));
}

public static Handle searchConst() {
return new Handle(Opcodes.H_INVOKESTATIC, p(Bootstrap.class), "searchConst", sig(CallSite.class, Lookup.class, String.class, MethodType.class, int.class));
}

public static Handle global() {
return new Handle(Opcodes.H_INVOKESTATIC, p(Bootstrap.class), "globalBootstrap", sig(CallSite.class, Lookup.class, String.class, MethodType.class));
}
@@ -373,6 +352,112 @@ static MethodHandle buildGenericHandle(InvokeSite site, DynamicMethod method, Ru
return binder.invokeVirtualQuiet(LOOKUP, "call").handle();
}

static MethodHandle buildAttrHandle(InvokeSite site, DynamicMethod method, IRubyObject self, RubyClass dispatchClass) {
if (method instanceof AttrReaderMethod) {
AttrReaderMethod attrReader = (AttrReaderMethod) method;
String varName = attrReader.getVariableName();

// we getVariableAccessorForWrite here so it is eagerly created and we don't cache the DUMMY
VariableAccessor accessor = dispatchClass.getRealClass().getVariableAccessorForWrite(varName);

// Ruby to attr reader
if (Options.INVOKEDYNAMIC_LOG_BINDING.load()) {
// if (accessor instanceof FieldVariableAccessor) {
// LOG.info(site.name() + "\tbound as field attr reader " + logMethod(method) + ":" + ((AttrReaderMethod)method).getVariableName());
// } else {
// LOG.info(site.name() + "\tbound as attr reader " + logMethod(method) + ":" + ((AttrReaderMethod)method).getVariableName());
// }
}

return createAttrReaderHandle(site, self, dispatchClass.getRealClass(), accessor);
} else if (method instanceof AttrWriterMethod) {
AttrWriterMethod attrReader = (AttrWriterMethod)method;
String varName = attrReader.getVariableName();

// we getVariableAccessorForWrite here so it is eagerly created and we don't cache the DUMMY
VariableAccessor accessor = dispatchClass.getRealClass().getVariableAccessorForWrite(varName);

// Ruby to attr reader
// if (Options.INVOKEDYNAMIC_LOG_BINDING.load()) {
// if (accessor instanceof FieldVariableAccessor) {
// LOG.info(site.name() + "\tbound as field attr writer " + logMethod(method) + ":" + ((AttrWriterMethod) method).getVariableName());
// } else {
// LOG.info(site.name() + "\tbound as attr writer " + logMethod(method) + ":" + ((AttrWriterMethod) method).getVariableName());
// }
// }

return createAttrWriterHandle(site, self, dispatchClass.getRealClass(), accessor);
}

return null;
}

private static MethodHandle createAttrReaderHandle(InvokeSite site, IRubyObject self, RubyClass cls, VariableAccessor accessor) {
MethodHandle nativeTarget;

MethodHandle filter = Binder
.from(IRubyObject.class, IRubyObject.class)
.insert(1, cls.getRuntime().getNil())
.cast(IRubyObject.class, IRubyObject.class, IRubyObject.class)
.invokeStaticQuiet(lookup(), Bootstrap.class, "valueOrNil");

MethodHandle getValue;

// FIXME: Duplicated from ivar get
if (accessor instanceof FieldVariableAccessor) {
int offset = ((FieldVariableAccessor)accessor).getOffset();
getValue = Binder.from(site.type())
.drop(0, 2)
.filterReturn(filter)
.cast(methodType(Object.class, self.getClass()))
.getFieldQuiet(LOOKUP, "var" + offset);
} else {
getValue = Binder.from(site.type())
.drop(0, 2)
.filterReturn(filter)
.cast(methodType(Object.class, RubyBasicObject.class))
.append(accessor.getIndex())
.invokeVirtualQuiet(LOOKUP, "getVariable");
}

// NOTE: Must not cache the fully-bound handle in the method, since it's specific to this class

return getValue;
}

public static IRubyObject valueOrNil(IRubyObject value, IRubyObject nil) {
return value == null ? nil : value;
}

private static MethodHandle createAttrWriterHandle(InvokeSite site, IRubyObject self, RubyClass cls, VariableAccessor accessor) {
MethodHandle nativeTarget;

MethodHandle filter = Binder
.from(IRubyObject.class, Object.class)
.drop(0)
.constant(cls.getRuntime().getNil());

MethodHandle setValue;

if (accessor instanceof FieldVariableAccessor) {
int offset = ((FieldVariableAccessor)accessor).getOffset();
setValue = Binder.from(site.type())
.drop(0, 2)
.filterReturn(filter)
.cast(methodType(void.class, self.getClass(), Object.class))
.invokeVirtualQuiet(LOOKUP, "setVariable" + offset);
} else {
setValue = Binder.from(site.type())
.drop(0, 2)
.filterReturn(filter)
.cast(methodType(void.class, RubyBasicObject.class, Object.class))
.insert(1, accessor.getIndex())
.invokeVirtualQuiet(LOOKUP, "setVariable");
}

return setValue;
}

static MethodHandle buildJittedHandle(InvokeSite site, DynamicMethod method, boolean blockGiven) {
MethodHandle mh = null;
SmartBinder binder;
@@ -708,113 +793,21 @@ public static boolean testType(RubyClass original, IRubyObject self) {
///////////////////////////////////////////////////////////////////////////
// constant lookup

public static IRubyObject searchConst(ThreadContext context, StaticScope staticScope, MutableCallSite site, String constName, boolean noPrivateConsts) throws Throwable {

// Lexical lookup
Ruby runtime = context.getRuntime();
RubyModule object = runtime.getObject();
IRubyObject constant = (staticScope == null) ? object.getConstant(constName) : staticScope.getConstantInner(constName);

// Inheritance lookup
RubyModule module = null;
if (constant == null) {
// SSS FIXME: Is this null check case correct?
module = staticScope == null ? object : staticScope.getModule();
constant = noPrivateConsts ? module.getConstantFromNoConstMissing(constName, false) : module.getConstantNoConstMissing(constName);
}

// Call const_missing or cache
if (constant == null) {
return module.callMethod(context, "const_missing", context.runtime.fastNewSymbol(constName));
}

SwitchPoint switchPoint = (SwitchPoint)runtime.getConstantInvalidator(constName).getData();

// bind constant until invalidated
MethodHandle target = Binder.from(site.type())
.drop(0, 2)
.constant(constant);
MethodHandle fallback = Binder.from(site.type())
.append(site, constName)
.append(noPrivateConsts)
.invokeStatic(LOOKUP, Bootstrap.class, "searchConst");

site.setTarget(switchPoint.guardWithTest(target, fallback));

return constant;
}

public static IRubyObject inheritanceSearchConst(ThreadContext context, IRubyObject cmVal, MutableCallSite site, String constName, boolean noPrivateConsts) throws Throwable {
Ruby runtime = context.runtime;
RubyModule module;

if (cmVal instanceof RubyModule) {
module = (RubyModule) cmVal;
} else {
throw runtime.newTypeError(cmVal + " is not a type/class");
}

IRubyObject constant = noPrivateConsts ? module.getConstantFromNoConstMissing(constName, false) : module.getConstantNoConstMissing(constName);

if (constant == null) {
constant = UndefinedValue.UNDEFINED;
}

// This caching does not take into consideration sites that have many different module targets.
//
if (true) {
return constant;
}

SwitchPoint switchPoint = (SwitchPoint)runtime.getConstantInvalidator(constName).getData();

// bind constant until invalidated
MethodHandle target = Binder.from(site.type())
.drop(0, 2)
.constant(constant);
MethodHandle fallback = Binder.from(site.type())
.append(site, constName)
.append(noPrivateConsts)
.invokeStatic(LOOKUP, Bootstrap.class, "inheritanceSearchConst");

// test that module is same as before
MethodHandle test = Binder.from(site.type().changeReturnType(boolean.class))
.drop(0, 1)
.insert(1, module.id)
.invokeStaticQuiet(LOOKUP, Bootstrap.class, "testArg0ModuleMatch");
target = guardWithTest(test, target, fallback);
site.setTarget(switchPoint.guardWithTest(target, fallback));

if (Options.INVOKEDYNAMIC_LOG_CONSTANTS.load()) {
LOG.info(constName + "\tretrieved and cached from type " + cmVal.getMetaClass());// + " added to PIC" + extractSourceInfo(site));
}

return constant;
public static Handle searchConst() {
return new Handle(Opcodes.H_INVOKESTATIC, p(Bootstrap.class), "searchConst", sig(CallSite.class, Lookup.class, String.class, MethodType.class, String.class, int.class));
}

public static IRubyObject lexicalSearchConst(ThreadContext context, StaticScope scope, MutableCallSite site, String constName, boolean noPrivateConsts) throws Throwable {
Ruby runtime = context.runtime;

IRubyObject constant = scope.getConstantInner(constName);

if (constant == null) {
constant = UndefinedValue.UNDEFINED;
}

SwitchPoint switchPoint = (SwitchPoint)runtime.getConstantInvalidator(constName).getData();
public static CallSite searchConst(Lookup lookup, String searchType, MethodType type, String constName, int publicOnly) {
ConstantLookupSite site = new ConstantLookupSite(type, constName, publicOnly == 0 ? false : true);

// bind constant until invalidated
MethodHandle target = Binder.from(site.type())
.drop(0, 2)
.constant(constant);
MethodHandle fallback = Binder.from(site.type())
.append(site, constName)
.append(noPrivateConsts)
.invokeStatic(LOOKUP, Bootstrap.class, "lexicalSearchConst");
MethodHandle handle = Binder
.from(lookup, type)
.insert(0, site)
.invokeVirtualQuiet(LOOKUP, searchType);

site.setTarget(switchPoint.guardWithTest(target, fallback));
site.setTarget(handle);

return constant;
return site;
}

///////////////////////////////////////////////////////////////////////////
@@ -832,7 +825,6 @@ public static IRubyObject instVarNullToNil(IRubyObject value, IRubyObject nil, S
}

public static boolean testArg0ModuleMatch(IRubyObject arg0, int id) {
System.out.println("testing " + arg0 + " for match (id = " + ((RubyModule)arg0).id + "): " + (arg0 instanceof RubyModule && ((RubyModule)arg0).id == id));
return arg0 instanceof RubyModule && ((RubyModule)arg0).id == id;
}

Loading

0 comments on commit 4578c7b

Please sign in to comment.