comparison graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/CoreMethodNodeManager.java @ 13514:0fbee3eb71f0

Ruby: import project.
author Chris Seaton <chris.seaton@oracle.com>
date Mon, 06 Jan 2014 17:12:09 +0000
parents
children 497fada09efb
comparison
equal deleted inserted replaced
13513:64a23ce736a0 13514:0fbee3eb71f0
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.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.*;
20 import com.oracle.truffle.ruby.nodes.debug.*;
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) {
34 for (MethodDetails methodDetails : getMethods()) {
35 if (Arrays.asList(methodDetails.getMethodAnnotation().versions()).contains(rubyObjectClass.getContext().getConfiguration().getRubyVersion())) {
36 addMethod(rubyObjectClass, methodDetails);
37 }
38 }
39 }
40
41 /**
42 * Collect up all the core method nodes. Abstracted to allow the SVM to implement at compile
43 * type.
44 */
45 public static List<MethodDetails> getMethods() {
46 final List<MethodDetails> methods = new ArrayList<>();
47 getMethods(methods, ArrayNodesFactory.getFactories());
48 getMethods(methods, BasicObjectNodesFactory.getFactories());
49 getMethods(methods, BignumNodesFactory.getFactories());
50 getMethods(methods, ClassNodesFactory.getFactories());
51 getMethods(methods, ContinuationNodesFactory.getFactories());
52 getMethods(methods, ComparableNodesFactory.getFactories());
53 getMethods(methods, DebugNodesFactory.getFactories());
54 getMethods(methods, DirNodesFactory.getFactories());
55 getMethods(methods, ExceptionNodesFactory.getFactories());
56 getMethods(methods, FalseClassNodesFactory.getFactories());
57 getMethods(methods, FiberNodesFactory.getFactories());
58 getMethods(methods, FileNodesFactory.getFactories());
59 getMethods(methods, FixnumNodesFactory.getFactories());
60 getMethods(methods, FloatNodesFactory.getFactories());
61 getMethods(methods, HashNodesFactory.getFactories());
62 getMethods(methods, KernelNodesFactory.getFactories());
63 getMethods(methods, MainNodesFactory.getFactories());
64 getMethods(methods, MatchDataNodesFactory.getFactories());
65 getMethods(methods, MathNodesFactory.getFactories());
66 getMethods(methods, ModuleNodesFactory.getFactories());
67 getMethods(methods, NilClassNodesFactory.getFactories());
68 getMethods(methods, ObjectNodesFactory.getFactories());
69 getMethods(methods, ObjectSpaceNodesFactory.getFactories());
70 getMethods(methods, ProcessNodesFactory.getFactories());
71 getMethods(methods, ProcNodesFactory.getFactories());
72 getMethods(methods, RangeNodesFactory.getFactories());
73 getMethods(methods, RegexpNodesFactory.getFactories());
74 getMethods(methods, SignalNodesFactory.getFactories());
75 getMethods(methods, StringNodesFactory.getFactories());
76 getMethods(methods, StructNodesFactory.getFactories());
77 getMethods(methods, SymbolNodesFactory.getFactories());
78 getMethods(methods, ThreadNodesFactory.getFactories());
79 getMethods(methods, TimeNodesFactory.getFactories());
80 getMethods(methods, TrueClassNodesFactory.getFactories());
81 return methods;
82 }
83
84 /**
85 * Collect up the core methods created by a factory.
86 */
87 private static void getMethods(List<MethodDetails> methods, List<? extends NodeFactory<? extends CoreMethodNode>> nodeFactories) {
88 for (NodeFactory<? extends RubyNode> nodeFactory : nodeFactories) {
89 final GeneratedBy generatedBy = nodeFactory.getClass().getAnnotation(GeneratedBy.class);
90 final Class<?> nodeClass = generatedBy.value();
91 final CoreClass classAnnotation = nodeClass.getEnclosingClass().getAnnotation(CoreClass.class);
92 final CoreMethod methodAnnotation = nodeClass.getAnnotation(CoreMethod.class);
93 methods.add(new MethodDetails(classAnnotation, methodAnnotation, nodeFactory));
94 }
95 }
96
97 /**
98 * Take a core method node factory, the annotations for the class and method, and add it as a
99 * method on the correct class.
100 */
101 private static void addMethod(RubyClass rubyObjectClass, MethodDetails methodDetails) {
102 assert rubyObjectClass != null;
103 assert methodDetails != null;
104
105 final RubyContext context = rubyObjectClass.getContext();
106
107 RubyModule module;
108
109 if (methodDetails.getClassAnnotation().name().equals("main")) {
110 module = context.getCoreLibrary().getMainObject().getSingletonClass();
111 } else {
112 module = (RubyModule) rubyObjectClass.lookupConstant(methodDetails.getClassAnnotation().name());
113 }
114
115 assert module != null : methodDetails.getClassAnnotation().name();
116
117 final List<String> names = Arrays.asList(methodDetails.getMethodAnnotation().names());
118 assert names.size() >= 1;
119
120 final String canonicalName = names.get(0);
121 final List<String> aliases = names.subList(1, names.size());
122
123 final UniqueMethodIdentifier uniqueIdentifier = new UniqueMethodIdentifier();
124 final Visibility visibility = Visibility.PUBLIC;
125
126 final RubyRootNode pristineRootNode = makeGenericMethod(context, methodDetails);
127 final CallTarget callTarget = Truffle.getRuntime().createCallTarget(NodeUtil.cloneNode(pristineRootNode));
128
129 final String intrinsicName = methodDetails.getClassAnnotation().name() + "#" + canonicalName;
130
131 final InlinableMethodImplementation methodImplementation = new InlinableMethodImplementation(callTarget, null, new FrameDescriptor(), pristineRootNode, true,
132 methodDetails.getMethodAnnotation().appendCallNode());
133 final RubyMethod method = new RubyMethod(pristineRootNode.getSourceSection(), module, uniqueIdentifier, intrinsicName, canonicalName, visibility, false, methodImplementation);
134
135 module.addMethod(method);
136
137 if (methodDetails.getMethodAnnotation().isModuleMethod()) {
138 module.getSingletonClass().addMethod(method);
139 }
140
141 for (String alias : aliases) {
142 final RubyMethod withAlias = method.withNewName(alias);
143
144 module.addMethod(withAlias);
145
146 if (methodDetails.getMethodAnnotation().isModuleMethod()) {
147 module.getSingletonClass().addMethod(withAlias);
148 }
149 }
150 }
151
152 private static RubyRootNode makeGenericMethod(RubyContext context, MethodDetails methodDetails) {
153 final SourceSection sourceSection = new CoreSourceSection(methodDetails.getClassAnnotation().name() + "#" + methodDetails.getMethodAnnotation().names()[0]);
154
155 final Arity arity = new Arity(methodDetails.getMethodAnnotation().minArgs(), methodDetails.getMethodAnnotation().maxArgs());
156
157 final List<RubyNode> argumentsNodes = new ArrayList<>();
158
159 if (methodDetails.getMethodAnnotation().needsSelf()) {
160 argumentsNodes.add(new SelfNode(context, sourceSection));
161 }
162
163 if (methodDetails.getMethodAnnotation().isSplatted()) {
164 argumentsNodes.add(new ReadAllArgumentsNode(context, sourceSection));
165 } else {
166 assert arity.getMaximum() != Arity.NO_MAXIMUM;
167
168 for (int n = 0; n < arity.getMaximum(); n++) {
169 argumentsNodes.add(new ReadPreArgumentNode(context, sourceSection, n, true));
170 }
171 }
172
173 if (methodDetails.getMethodAnnotation().needsBlock()) {
174 argumentsNodes.add(new ReadBlockArgumentNode(context, sourceSection, true));
175 }
176
177 final RubyNode methodNode = methodDetails.getNodeFactory().createNode(context, sourceSection, argumentsNodes.toArray(new RubyNode[argumentsNodes.size()]));
178 final CheckArityNode checkArity = new CheckArityNode(context, sourceSection, arity);
179 final SequenceNode block = new SequenceNode(context, sourceSection, checkArity, methodNode);
180
181 return new RubyRootNode(sourceSection, methodDetails.getClassAnnotation().name() + "#" + methodDetails.getMethodAnnotation().names()[0] + "(core)", block);
182 }
183
184 public static class MethodDetails {
185
186 private final CoreClass classAnnotation;
187 private final CoreMethod methodAnnotation;
188 private final NodeFactory<? extends RubyNode> nodeFactory;
189
190 public MethodDetails(CoreClass classAnnotation, CoreMethod methodAnnotation, NodeFactory<? extends RubyNode> nodeFactory) {
191 assert classAnnotation != null;
192 assert methodAnnotation != null;
193 assert nodeFactory != null;
194 this.classAnnotation = classAnnotation;
195 this.methodAnnotation = methodAnnotation;
196 this.nodeFactory = nodeFactory;
197 }
198
199 public CoreClass getClassAnnotation() {
200 return classAnnotation;
201 }
202
203 public CoreMethod getMethodAnnotation() {
204 return methodAnnotation;
205 }
206
207 public NodeFactory<? extends RubyNode> getNodeFactory() {
208 return nodeFactory;
209 }
210
211 }
212
213 }