13514
|
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 }
|