Mercurial > hg > graal-compiler
diff graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/UninitializedDispatchNode.java @ 13529:856c2c294f84
Merge.
author | Christian Humer <christian.humer@gmail.com> |
---|---|
date | Tue, 07 Jan 2014 18:53:04 +0100 |
parents | 0fbee3eb71f0 |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/UninitializedDispatchNode.java Tue Jan 07 18:53:04 2014 +0100 @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This + * code is released under a tri EPL/GPL/LGPL license. You can use it, + * redistribute it and/or modify it under the terms of the: + * + * Eclipse Public License version 1.0 + * GNU General Public License version 2 + * GNU Lesser General Public License version 2.1 + */ +package com.oracle.truffle.ruby.nodes.call; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.ruby.nodes.*; +import com.oracle.truffle.ruby.runtime.*; +import com.oracle.truffle.ruby.runtime.core.*; +import com.oracle.truffle.ruby.runtime.methods.*; +import com.oracle.truffle.ruby.runtime.objects.*; + +/** + * The uninitialized dispatch node. Only reached when the method is not expected by any node in the + * dispatch chain, and only creates new nodes or modifies the existing chain. + */ +public class UninitializedDispatchNode extends BoxedDispatchNode { + + /* + * Node at depth 5 is 4 actual dispatches, the boxing dispatch and the final uninitalized + * dispatch. + */ + + private static final int MAX_DEPTH = 5; + + private final String name; + + public UninitializedDispatchNode(RubyContext context, SourceSection sourceSection, String name) { + super(context, sourceSection); + + assert name != null; + + this.name = name; + } + + @Override + public Object dispatch(VirtualFrame frame, RubyBasicObject receiverObject, RubyProc blockObject, Object[] argumentsObjects) { + CompilerDirectives.transferToInterpreter(); + + final RubyContext context = getContext(); + + final RubyMethod method = lookup(frame, receiverObject, name); + + final int depth = getDepth(); + + final DispatchHeadNode dispatchHead = (DispatchHeadNode) NodeUtil.getNthParent(this, depth); + + if (depth == MAX_DEPTH) { + /* + * Replace the chain with DispatchHeadNode -> ExpectBoxedDispatchNode -> + * GeneralDispatchNode. + */ + + context.implementationMessage("resorting to a general call node at %s", getSourceSection()); + NodeUtil.printTree(System.err, dispatchHead); + + final GeneralBoxedDispatchNode newGeneralDispatch = new GeneralBoxedDispatchNode(getContext(), getSourceSection(), name); + final BoxingDispatchNode newBoxing = new BoxingDispatchNode(getContext(), getSourceSection(), newGeneralDispatch); + + dispatchHead.getDispatch().replace(newBoxing); + return newBoxing.dispatch(frame, receiverObject, blockObject, argumentsObjects); + } else if (receiverObject instanceof Unboxable) { + /* + * Unboxed dispatch nodes are prepended to the chain of dispatch nodes, so they're + * before the point where receivers will definitely be boxed. + */ + + final Object receiverUnboxed = ((Unboxable) receiverObject).unbox(); + + final UnboxedDispatchNode firstDispatch = dispatchHead.getDispatch(); + + if (receiverObject instanceof RubyTrueClass || receiverObject instanceof RubyFalseClass) { + final Assumption falseUnmodifiedAssumption = context.getCoreLibrary().getFalseClass().getUnmodifiedAssumption(); + final RubyMethod falseMethod = lookup(frame, context.getCoreLibrary().box(false), name); + final Assumption trueUnmodifiedAssumption = context.getCoreLibrary().getTrueClass().getUnmodifiedAssumption(); + final RubyMethod trueMethod = lookup(frame, context.getCoreLibrary().box(true), name); + + final BooleanDispatchNode newDispatch = new BooleanDispatchNode(getContext(), getSourceSection(), falseUnmodifiedAssumption, falseMethod, trueUnmodifiedAssumption, trueMethod, null); + firstDispatch.replace(newDispatch, "prepending new unboxed dispatch node to chain"); + newDispatch.setNext(firstDispatch); + return newDispatch.dispatch(frame, receiverUnboxed, blockObject, argumentsObjects); + } else { + UnboxedDispatchNode newDispatch; + + if (method.getImplementation() instanceof InlinableMethodImplementation && InlineHeuristic.shouldInline((InlinableMethodImplementation) method.getImplementation())) { + newDispatch = new InlinedUnboxedDispatchNode(getContext(), getSourceSection(), receiverUnboxed.getClass(), receiverObject.getRubyClass().getUnmodifiedAssumption(), + (InlinableMethodImplementation) method.getImplementation(), null); + } else { + newDispatch = new CachedUnboxedDispatchNode(getContext(), getSourceSection(), receiverUnboxed.getClass(), receiverObject.getRubyClass().getUnmodifiedAssumption(), method, null); + } + + firstDispatch.replace(newDispatch, "prepending new unboxed dispatch node to chain"); + newDispatch.setNext(firstDispatch); + + return newDispatch.dispatch(frame, receiverUnboxed, blockObject, argumentsObjects); + } + } else { + /* + * Boxed dispatch nodes are appended to the chain of dispatch nodes, so they're after + * the point where receivers are guaranteed to be boxed. + */ + + final UninitializedDispatchNode newUninitializedDispatch = new UninitializedDispatchNode(getContext(), getSourceSection(), name); + + BoxedDispatchNode newDispatch; + + if (method.getImplementation() instanceof InlinableMethodImplementation && InlineHeuristic.shouldInline((InlinableMethodImplementation) method.getImplementation())) { + newDispatch = new InlinedBoxedDispatchNode(getContext(), getSourceSection(), receiverObject.getLookupNode(), (InlinableMethodImplementation) method.getImplementation(), + newUninitializedDispatch); + } else { + newDispatch = new CachedBoxedDispatchNode(getContext(), getSourceSection(), receiverObject.getLookupNode(), method, newUninitializedDispatch); + } + + replace(newDispatch, "appending new boxed dispatch node to chain"); + + return newDispatch.dispatch(frame, receiverObject, blockObject, argumentsObjects); + } + } +}