comparison 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
comparison
equal deleted inserted replaced
13528:5a0c694ef735 13529:856c2c294f84
1 /*
2 * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
3 * code is released under a tri EPL/GPL/LGPL license. You can use it,
4 * redistribute it and/or modify it under the terms of the:
5 *
6 * Eclipse Public License version 1.0
7 * GNU General Public License version 2
8 * GNU Lesser General Public License version 2.1
9 */
10 package com.oracle.truffle.ruby.nodes.call;
11
12 import com.oracle.truffle.api.*;
13 import com.oracle.truffle.api.frame.*;
14 import com.oracle.truffle.api.nodes.*;
15 import com.oracle.truffle.ruby.nodes.*;
16 import com.oracle.truffle.ruby.runtime.*;
17 import com.oracle.truffle.ruby.runtime.core.*;
18 import com.oracle.truffle.ruby.runtime.methods.*;
19 import com.oracle.truffle.ruby.runtime.objects.*;
20
21 /**
22 * The uninitialized dispatch node. Only reached when the method is not expected by any node in the
23 * dispatch chain, and only creates new nodes or modifies the existing chain.
24 */
25 public class UninitializedDispatchNode extends BoxedDispatchNode {
26
27 /*
28 * Node at depth 5 is 4 actual dispatches, the boxing dispatch and the final uninitalized
29 * dispatch.
30 */
31
32 private static final int MAX_DEPTH = 5;
33
34 private final String name;
35
36 public UninitializedDispatchNode(RubyContext context, SourceSection sourceSection, String name) {
37 super(context, sourceSection);
38
39 assert name != null;
40
41 this.name = name;
42 }
43
44 @Override
45 public Object dispatch(VirtualFrame frame, RubyBasicObject receiverObject, RubyProc blockObject, Object[] argumentsObjects) {
46 CompilerDirectives.transferToInterpreter();
47
48 final RubyContext context = getContext();
49
50 final RubyMethod method = lookup(frame, receiverObject, name);
51
52 final int depth = getDepth();
53
54 final DispatchHeadNode dispatchHead = (DispatchHeadNode) NodeUtil.getNthParent(this, depth);
55
56 if (depth == MAX_DEPTH) {
57 /*
58 * Replace the chain with DispatchHeadNode -> ExpectBoxedDispatchNode ->
59 * GeneralDispatchNode.
60 */
61
62 context.implementationMessage("resorting to a general call node at %s", getSourceSection());
63 NodeUtil.printTree(System.err, dispatchHead);
64
65 final GeneralBoxedDispatchNode newGeneralDispatch = new GeneralBoxedDispatchNode(getContext(), getSourceSection(), name);
66 final BoxingDispatchNode newBoxing = new BoxingDispatchNode(getContext(), getSourceSection(), newGeneralDispatch);
67
68 dispatchHead.getDispatch().replace(newBoxing);
69 return newBoxing.dispatch(frame, receiverObject, blockObject, argumentsObjects);
70 } else if (receiverObject instanceof Unboxable) {
71 /*
72 * Unboxed dispatch nodes are prepended to the chain of dispatch nodes, so they're
73 * before the point where receivers will definitely be boxed.
74 */
75
76 final Object receiverUnboxed = ((Unboxable) receiverObject).unbox();
77
78 final UnboxedDispatchNode firstDispatch = dispatchHead.getDispatch();
79
80 if (receiverObject instanceof RubyTrueClass || receiverObject instanceof RubyFalseClass) {
81 final Assumption falseUnmodifiedAssumption = context.getCoreLibrary().getFalseClass().getUnmodifiedAssumption();
82 final RubyMethod falseMethod = lookup(frame, context.getCoreLibrary().box(false), name);
83 final Assumption trueUnmodifiedAssumption = context.getCoreLibrary().getTrueClass().getUnmodifiedAssumption();
84 final RubyMethod trueMethod = lookup(frame, context.getCoreLibrary().box(true), name);
85
86 final BooleanDispatchNode newDispatch = new BooleanDispatchNode(getContext(), getSourceSection(), falseUnmodifiedAssumption, falseMethod, trueUnmodifiedAssumption, trueMethod, null);
87 firstDispatch.replace(newDispatch, "prepending new unboxed dispatch node to chain");
88 newDispatch.setNext(firstDispatch);
89 return newDispatch.dispatch(frame, receiverUnboxed, blockObject, argumentsObjects);
90 } else {
91 UnboxedDispatchNode newDispatch;
92
93 if (method.getImplementation() instanceof InlinableMethodImplementation && InlineHeuristic.shouldInline((InlinableMethodImplementation) method.getImplementation())) {
94 newDispatch = new InlinedUnboxedDispatchNode(getContext(), getSourceSection(), receiverUnboxed.getClass(), receiverObject.getRubyClass().getUnmodifiedAssumption(),
95 (InlinableMethodImplementation) method.getImplementation(), null);
96 } else {
97 newDispatch = new CachedUnboxedDispatchNode(getContext(), getSourceSection(), receiverUnboxed.getClass(), receiverObject.getRubyClass().getUnmodifiedAssumption(), method, null);
98 }
99
100 firstDispatch.replace(newDispatch, "prepending new unboxed dispatch node to chain");
101 newDispatch.setNext(firstDispatch);
102
103 return newDispatch.dispatch(frame, receiverUnboxed, blockObject, argumentsObjects);
104 }
105 } else {
106 /*
107 * Boxed dispatch nodes are appended to the chain of dispatch nodes, so they're after
108 * the point where receivers are guaranteed to be boxed.
109 */
110
111 final UninitializedDispatchNode newUninitializedDispatch = new UninitializedDispatchNode(getContext(), getSourceSection(), name);
112
113 BoxedDispatchNode newDispatch;
114
115 if (method.getImplementation() instanceof InlinableMethodImplementation && InlineHeuristic.shouldInline((InlinableMethodImplementation) method.getImplementation())) {
116 newDispatch = new InlinedBoxedDispatchNode(getContext(), getSourceSection(), receiverObject.getLookupNode(), (InlinableMethodImplementation) method.getImplementation(),
117 newUninitializedDispatch);
118 } else {
119 newDispatch = new CachedBoxedDispatchNode(getContext(), getSourceSection(), receiverObject.getLookupNode(), method, newUninitializedDispatch);
120 }
121
122 replace(newDispatch, "appending new boxed dispatch node to chain");
123
124 return newDispatch.dispatch(frame, receiverObject, blockObject, argumentsObjects);
125 }
126 }
127 }