Mercurial > hg > graal-compiler
annotate graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/CoreMethodNodeManager.java @ 13942:1ee27cd07ed0
Make code extensible
author | Christian Wimmer <christian.wimmer@oracle.com> |
---|---|
date | Wed, 12 Feb 2014 10:25:29 -0800 |
parents | 22bf5a8ba9eb |
children |
rev | line source |
---|---|
13514 | 1 /* |
13732
fbf448929260
Ruby: remove some prototyping code no longer needed
Michael Van De Vanter <michael.van.de.vanter@oracle.com>
parents:
13645
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.core; | |
11 | |
12 import java.util.*; | |
13 | |
14 import com.oracle.truffle.api.*; | |
15 import com.oracle.truffle.api.dsl.*; | |
16 import com.oracle.truffle.api.frame.*; | |
17 import com.oracle.truffle.api.nodes.*; | |
18 import com.oracle.truffle.ruby.nodes.*; | |
19 import com.oracle.truffle.ruby.nodes.control.*; | |
13918
22bf5a8ba9eb
Ruby: restore prototype debugger.
Chris Seaton <chris.seaton@oracle.com>
parents:
13736
diff
changeset
|
20 import com.oracle.truffle.ruby.nodes.debug.*; |
13514 | 21 import com.oracle.truffle.ruby.nodes.methods.arguments.*; |
22 import com.oracle.truffle.ruby.nodes.objects.*; | |
23 import com.oracle.truffle.ruby.runtime.*; | |
24 import com.oracle.truffle.ruby.runtime.core.*; | |
25 import com.oracle.truffle.ruby.runtime.methods.*; | |
26 | |
27 public abstract class CoreMethodNodeManager { | |
28 | |
29 /** | |
30 * Register all the nodes that represent core methods as methods with their respective classes, | |
31 * given the Object class object, which should already be initialized with all the core classes. | |
32 */ | |
33 public static void addMethods(RubyClass rubyObjectClass) { | |
13942
1ee27cd07ed0
Make code extensible
Christian Wimmer <christian.wimmer@oracle.com>
parents:
13918
diff
changeset
|
34 addMethods(rubyObjectClass, getMethods()); |
1ee27cd07ed0
Make code extensible
Christian Wimmer <christian.wimmer@oracle.com>
parents:
13918
diff
changeset
|
35 } |
1ee27cd07ed0
Make code extensible
Christian Wimmer <christian.wimmer@oracle.com>
parents:
13918
diff
changeset
|
36 |
1ee27cd07ed0
Make code extensible
Christian Wimmer <christian.wimmer@oracle.com>
parents:
13918
diff
changeset
|
37 public static void addMethods(RubyClass rubyObjectClass, List<MethodDetails> methods) { |
1ee27cd07ed0
Make code extensible
Christian Wimmer <christian.wimmer@oracle.com>
parents:
13918
diff
changeset
|
38 // Same as above, but allows passing of a specific list of core methods. |
1ee27cd07ed0
Make code extensible
Christian Wimmer <christian.wimmer@oracle.com>
parents:
13918
diff
changeset
|
39 // This allows extending Truffle-Ruby with non-standard Core Method. |
1ee27cd07ed0
Make code extensible
Christian Wimmer <christian.wimmer@oracle.com>
parents:
13918
diff
changeset
|
40 for (MethodDetails methodDetails : methods) { |
13645
497fada09efb
Ruby: remove versioning.
Chris Seaton <chris.seaton@oracle.com>
parents:
13514
diff
changeset
|
41 addMethod(rubyObjectClass, methodDetails); |
13514 | 42 } |
43 } | |
44 | |
45 /** | |
46 * Collect up all the core method nodes. Abstracted to allow the SVM to implement at compile | |
47 * type. | |
48 */ | |
49 public static List<MethodDetails> getMethods() { | |
50 final List<MethodDetails> methods = new ArrayList<>(); | |
51 getMethods(methods, ArrayNodesFactory.getFactories()); | |
52 getMethods(methods, BasicObjectNodesFactory.getFactories()); | |
53 getMethods(methods, BignumNodesFactory.getFactories()); | |
54 getMethods(methods, ClassNodesFactory.getFactories()); | |
55 getMethods(methods, ContinuationNodesFactory.getFactories()); | |
56 getMethods(methods, ComparableNodesFactory.getFactories()); | |
57 getMethods(methods, DirNodesFactory.getFactories()); | |
58 getMethods(methods, ExceptionNodesFactory.getFactories()); | |
59 getMethods(methods, FalseClassNodesFactory.getFactories()); | |
60 getMethods(methods, FiberNodesFactory.getFactories()); | |
61 getMethods(methods, FileNodesFactory.getFactories()); | |
62 getMethods(methods, FixnumNodesFactory.getFactories()); | |
63 getMethods(methods, FloatNodesFactory.getFactories()); | |
64 getMethods(methods, HashNodesFactory.getFactories()); | |
65 getMethods(methods, KernelNodesFactory.getFactories()); | |
66 getMethods(methods, MainNodesFactory.getFactories()); | |
67 getMethods(methods, MatchDataNodesFactory.getFactories()); | |
68 getMethods(methods, MathNodesFactory.getFactories()); | |
69 getMethods(methods, ModuleNodesFactory.getFactories()); | |
70 getMethods(methods, NilClassNodesFactory.getFactories()); | |
71 getMethods(methods, ObjectNodesFactory.getFactories()); | |
72 getMethods(methods, ObjectSpaceNodesFactory.getFactories()); | |
73 getMethods(methods, ProcessNodesFactory.getFactories()); | |
74 getMethods(methods, ProcNodesFactory.getFactories()); | |
75 getMethods(methods, RangeNodesFactory.getFactories()); | |
76 getMethods(methods, RegexpNodesFactory.getFactories()); | |
77 getMethods(methods, SignalNodesFactory.getFactories()); | |
78 getMethods(methods, StringNodesFactory.getFactories()); | |
79 getMethods(methods, StructNodesFactory.getFactories()); | |
80 getMethods(methods, SymbolNodesFactory.getFactories()); | |
81 getMethods(methods, ThreadNodesFactory.getFactories()); | |
82 getMethods(methods, TimeNodesFactory.getFactories()); | |
83 getMethods(methods, TrueClassNodesFactory.getFactories()); | |
13918
22bf5a8ba9eb
Ruby: restore prototype debugger.
Chris Seaton <chris.seaton@oracle.com>
parents:
13736
diff
changeset
|
84 getMethods(methods, DebugNodesFactory.getFactories()); |
13514 | 85 return methods; |
86 } | |
87 | |
88 /** | |
89 * Collect up the core methods created by a factory. | |
90 */ | |
13942
1ee27cd07ed0
Make code extensible
Christian Wimmer <christian.wimmer@oracle.com>
parents:
13918
diff
changeset
|
91 public static void getMethods(List<MethodDetails> methods, List<? extends NodeFactory<? extends CoreMethodNode>> nodeFactories) { |
13514 | 92 for (NodeFactory<? extends RubyNode> nodeFactory : nodeFactories) { |
93 final GeneratedBy generatedBy = nodeFactory.getClass().getAnnotation(GeneratedBy.class); | |
94 final Class<?> nodeClass = generatedBy.value(); | |
95 final CoreClass classAnnotation = nodeClass.getEnclosingClass().getAnnotation(CoreClass.class); | |
96 final CoreMethod methodAnnotation = nodeClass.getAnnotation(CoreMethod.class); | |
97 methods.add(new MethodDetails(classAnnotation, methodAnnotation, nodeFactory)); | |
98 } | |
99 } | |
100 | |
101 /** | |
102 * Take a core method node factory, the annotations for the class and method, and add it as a | |
103 * method on the correct class. | |
104 */ | |
105 private static void addMethod(RubyClass rubyObjectClass, MethodDetails methodDetails) { | |
106 assert rubyObjectClass != null; | |
107 assert methodDetails != null; | |
108 | |
109 final RubyContext context = rubyObjectClass.getContext(); | |
110 | |
111 RubyModule module; | |
112 | |
113 if (methodDetails.getClassAnnotation().name().equals("main")) { | |
114 module = context.getCoreLibrary().getMainObject().getSingletonClass(); | |
115 } else { | |
116 module = (RubyModule) rubyObjectClass.lookupConstant(methodDetails.getClassAnnotation().name()); | |
117 } | |
118 | |
119 assert module != null : methodDetails.getClassAnnotation().name(); | |
120 | |
121 final List<String> names = Arrays.asList(methodDetails.getMethodAnnotation().names()); | |
122 assert names.size() >= 1; | |
123 | |
124 final String canonicalName = names.get(0); | |
125 final List<String> aliases = names.subList(1, names.size()); | |
126 | |
127 final UniqueMethodIdentifier uniqueIdentifier = new UniqueMethodIdentifier(); | |
128 final Visibility visibility = Visibility.PUBLIC; | |
129 | |
130 final RubyRootNode pristineRootNode = makeGenericMethod(context, methodDetails); | |
131 final CallTarget callTarget = Truffle.getRuntime().createCallTarget(NodeUtil.cloneNode(pristineRootNode)); | |
132 | |
133 final String intrinsicName = methodDetails.getClassAnnotation().name() + "#" + canonicalName; | |
134 | |
135 final InlinableMethodImplementation methodImplementation = new InlinableMethodImplementation(callTarget, null, new FrameDescriptor(), pristineRootNode, true, | |
136 methodDetails.getMethodAnnotation().appendCallNode()); | |
137 final RubyMethod method = new RubyMethod(pristineRootNode.getSourceSection(), module, uniqueIdentifier, intrinsicName, canonicalName, visibility, false, methodImplementation); | |
138 | |
139 module.addMethod(method); | |
140 | |
141 if (methodDetails.getMethodAnnotation().isModuleMethod()) { | |
142 module.getSingletonClass().addMethod(method); | |
143 } | |
144 | |
145 for (String alias : aliases) { | |
146 final RubyMethod withAlias = method.withNewName(alias); | |
147 | |
148 module.addMethod(withAlias); | |
149 | |
150 if (methodDetails.getMethodAnnotation().isModuleMethod()) { | |
151 module.getSingletonClass().addMethod(withAlias); | |
152 } | |
153 } | |
154 } | |
155 | |
156 private static RubyRootNode makeGenericMethod(RubyContext context, MethodDetails methodDetails) { | |
157 final SourceSection sourceSection = new CoreSourceSection(methodDetails.getClassAnnotation().name() + "#" + methodDetails.getMethodAnnotation().names()[0]); | |
158 | |
159 final Arity arity = new Arity(methodDetails.getMethodAnnotation().minArgs(), methodDetails.getMethodAnnotation().maxArgs()); | |
160 | |
161 final List<RubyNode> argumentsNodes = new ArrayList<>(); | |
162 | |
163 if (methodDetails.getMethodAnnotation().needsSelf()) { | |
164 argumentsNodes.add(new SelfNode(context, sourceSection)); | |
165 } | |
166 | |
167 if (methodDetails.getMethodAnnotation().isSplatted()) { | |
168 argumentsNodes.add(new ReadAllArgumentsNode(context, sourceSection)); | |
169 } else { | |
170 assert arity.getMaximum() != Arity.NO_MAXIMUM; | |
171 | |
172 for (int n = 0; n < arity.getMaximum(); n++) { | |
173 argumentsNodes.add(new ReadPreArgumentNode(context, sourceSection, n, true)); | |
174 } | |
175 } | |
176 | |
177 if (methodDetails.getMethodAnnotation().needsBlock()) { | |
178 argumentsNodes.add(new ReadBlockArgumentNode(context, sourceSection, true)); | |
179 } | |
180 | |
181 final RubyNode methodNode = methodDetails.getNodeFactory().createNode(context, sourceSection, argumentsNodes.toArray(new RubyNode[argumentsNodes.size()])); | |
182 final CheckArityNode checkArity = new CheckArityNode(context, sourceSection, arity); | |
183 final SequenceNode block = new SequenceNode(context, sourceSection, checkArity, methodNode); | |
184 | |
13706
232eb6708943
Ruby: required fixes for moving FrameDescriptor to the RootNode.
Christian Humer <christian.humer@gmail.com>
parents:
13645
diff
changeset
|
185 return new RubyRootNode(sourceSection, null, methodDetails.getClassAnnotation().name() + "#" + methodDetails.getMethodAnnotation().names()[0] + "(core)", block); |
13514 | 186 } |
187 | |
188 public static class MethodDetails { | |
189 | |
190 private final CoreClass classAnnotation; | |
191 private final CoreMethod methodAnnotation; | |
192 private final NodeFactory<? extends RubyNode> nodeFactory; | |
193 | |
194 public MethodDetails(CoreClass classAnnotation, CoreMethod methodAnnotation, NodeFactory<? extends RubyNode> nodeFactory) { | |
195 assert classAnnotation != null; | |
196 assert methodAnnotation != null; | |
197 assert nodeFactory != null; | |
198 this.classAnnotation = classAnnotation; | |
199 this.methodAnnotation = methodAnnotation; | |
200 this.nodeFactory = nodeFactory; | |
201 } | |
202 | |
203 public CoreClass getClassAnnotation() { | |
204 return classAnnotation; | |
205 } | |
206 | |
207 public CoreMethod getMethodAnnotation() { | |
208 return methodAnnotation; | |
209 } | |
210 | |
211 public NodeFactory<? extends RubyNode> getNodeFactory() { | |
212 return nodeFactory; | |
213 } | |
214 | |
215 } | |
216 | |
217 } |