Mercurial > hg > graal-jvmci-8
annotate graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/CallNode.java @ 13568:f29a358cf3da
Ruby: minor tweaks to implementation nodes for debugging access
author | Michael Van De Vanter <michael.van.de.vanter@oracle.com> |
---|---|
date | Wed, 08 Jan 2014 14:00:21 -0800 |
parents | 0fbee3eb71f0 |
children | d7af2296cebb |
rev | line source |
---|---|
13514 | 1 /* |
13568
f29a358cf3da
Ruby: minor tweaks to implementation nodes for debugging access
Michael Van De Vanter <michael.van.de.vanter@oracle.com>
parents:
13514
diff
changeset
|
2 * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This |
13514 | 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.core.array.*; | |
19 import com.oracle.truffle.ruby.runtime.methods.*; | |
20 import com.oracle.truffle.ruby.runtime.objects.*; | |
21 | |
22 /** | |
23 * A call node that has a chain of dispatch nodes. | |
24 * <p> | |
25 * The dispatch chain starts as {@link CallNode} -> {@link DispatchHeadNode} -> | |
26 * {@link UninitializedBoxingDispatchNode} -> {@link UninitializedDispatchNode}. | |
27 * <p> | |
28 * When the {@link UninitializedDispatchNode} is reached a new node is inserted into the chain. If | |
29 * the node dispatches based on some unboxed value (unboxed as in it's not a Ruby object, just a | |
30 * Java object) such as {@link Integer}, then that node is inserted before the | |
31 * {@link UninitializedBoxingDispatchNode}, otherwise if it dispatches based on some Ruby | |
32 * BasicObject, it is inserted afterwards. | |
33 * <p> | |
34 * The {@link UninitializedBoxingDispatchNode} becomes a {@link BoxingDispatchNode} when we find | |
35 * that the boxing has to be done on the fast path - when there is some boxed dispatch node. | |
36 * <p> | |
37 * So the general format is {@link CallNode} -> {@link DispatchHeadNode} -> zero or more | |
38 * unboxed dispatches -> {@link UninitializedBoxingDispatchNode} | {@link BoxingDispatchNode} | |
39 * -> zero or more boxed dispatches -> {@link UninitializedDispatchNode}. | |
40 * <p> | |
41 * There are several special cases of unboxed and boxed dispatch nodes based on the types and | |
42 * methods involved. | |
43 * <p> | |
44 * If we have too many dispatch nodes we replace the whole chain with {@link DispatchHeadNode} -> | |
45 * {@link BoxingDispatchNode} -> {@link GeneralBoxedDispatchNode}. | |
46 * <p> | |
47 * This system allows us to dispatch based purely on Java class, before we have to turn the object | |
48 * into a full {@link RubyBasicObject} and consider the full Ruby lookup process, and something such | |
49 * as a math call which may work on Fixnum or Float to work as just a couple of applications of | |
50 * {@code instanceof} and assumption checks. | |
51 */ | |
52 public class CallNode extends RubyNode { | |
53 | |
54 @Child protected RubyNode receiver; | |
55 @Child protected ProcOrNullNode block; | |
56 @Children protected final RubyNode[] arguments; | |
57 | |
58 private final String name; | |
59 private final boolean isSplatted; | |
60 | |
61 @Child protected DispatchHeadNode dispatchHead; | |
62 | |
63 public CallNode(RubyContext context, SourceSection section, String name, RubyNode receiver, RubyNode block, boolean isSplatted, RubyNode[] arguments) { | |
64 super(context, section); | |
65 | |
66 assert receiver != null; | |
67 assert arguments != null; | |
68 assert name != null; | |
69 | |
70 this.receiver = adoptChild(receiver); | |
71 | |
72 if (block == null) { | |
73 this.block = null; | |
74 } else { | |
75 this.block = adoptChild(ProcOrNullNodeFactory.create(context, section, block)); | |
76 } | |
77 | |
78 this.arguments = adoptChildren(arguments); | |
79 this.name = name; | |
80 this.isSplatted = isSplatted; | |
81 | |
82 dispatchHead = adoptChild(adoptChild(new DispatchHeadNode(context, section, name, isSplatted))); | |
83 } | |
84 | |
85 @Override | |
86 public Object execute(VirtualFrame frame) { | |
87 final Object receiverObject = receiver.execute(frame); | |
88 final Object[] argumentsObjects = executeArguments(frame); | |
89 final RubyProc blockObject = executeBlock(frame); | |
90 | |
91 return dispatchHead.dispatch(frame, receiverObject, blockObject, argumentsObjects); | |
92 } | |
93 | |
94 private RubyProc executeBlock(VirtualFrame frame) { | |
95 if (block != null) { | |
96 return block.executeRubyProc(frame); | |
97 } else { | |
98 return null; | |
99 } | |
100 } | |
101 | |
102 @ExplodeLoop | |
103 private Object[] executeArguments(VirtualFrame frame) { | |
104 final Object[] argumentsObjects = new Object[arguments.length]; | |
105 | |
106 for (int i = 0; i < arguments.length; i++) { | |
107 argumentsObjects[i] = arguments[i].execute(frame); | |
108 assert RubyContext.shouldObjectBeVisible(argumentsObjects[i]) : argumentsObjects[i].getClass(); | |
109 } | |
110 | |
111 if (isSplatted) { | |
112 assert argumentsObjects[0] instanceof RubyArray; | |
113 return ((RubyArray) argumentsObjects[0]).toObjectArray(); | |
114 } else { | |
115 return argumentsObjects; | |
116 } | |
117 } | |
118 | |
119 @Override | |
120 public Object isDefined(VirtualFrame frame) { | |
121 final RubyContext context = getContext(); | |
122 | |
123 Object receiverObject; | |
124 | |
125 try { | |
126 /* | |
127 * TODO(CS): Getting a node via an accessor like this doesn't work with Truffle at the | |
128 * moment and will cause frame escape errors, so we don't use it in compilation mode. | |
129 */ | |
130 | |
131 CompilerAsserts.neverPartOfCompilation(); | |
132 | |
133 receiverObject = receiver.execute(frame); | |
134 } catch (Exception e) { | |
135 return NilPlaceholder.INSTANCE; | |
136 } | |
137 | |
138 final RubyBasicObject receiverBasicObject = context.getCoreLibrary().box(receiverObject); | |
139 | |
140 final RubyMethod method = receiverBasicObject.getLookupNode().lookupMethod(name); | |
141 | |
142 final RubyBasicObject self = context.getCoreLibrary().box(frame.getArguments(RubyArguments.class).getSelf()); | |
143 | |
144 if (method == null || method.isUndefined()) { | |
145 return NilPlaceholder.INSTANCE; | |
146 } | |
147 | |
148 if (!method.isVisibleTo(self)) { | |
149 return NilPlaceholder.INSTANCE; | |
150 } | |
151 | |
152 return context.makeString("method"); | |
153 } | |
154 | |
13568
f29a358cf3da
Ruby: minor tweaks to implementation nodes for debugging access
Michael Van De Vanter <michael.van.de.vanter@oracle.com>
parents:
13514
diff
changeset
|
155 public String getName() { |
f29a358cf3da
Ruby: minor tweaks to implementation nodes for debugging access
Michael Van De Vanter <michael.van.de.vanter@oracle.com>
parents:
13514
diff
changeset
|
156 return name; |
f29a358cf3da
Ruby: minor tweaks to implementation nodes for debugging access
Michael Van De Vanter <michael.van.de.vanter@oracle.com>
parents:
13514
diff
changeset
|
157 } |
13514 | 158 } |