1 /***** BEGIN LICENSE BLOCK *****
2 * Version: CPL 1.0/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Common Public
5 * License Version 1.0 (the "License"); you may not use this file
6 * except in compliance with the License. You may obtain a copy of
7 * the License at http://www.eclipse.org/legal/cpl-v10.html
9 * Software distributed under the License is distributed on an "AS
10 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11 * implied. See the License for the specific language governing
12 * rights and limitations under the License.
14 * Copyright (C) 2007 Ola Bini <ola.bini@gmail.com>
16 * Alternatively, the contents of this file may be used under the terms of
17 * either of the GNU General Public License Version 2 or later (the "GPL"),
18 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
19 * in which case the provisions of the GPL or the LGPL are applicable instead
20 * of those above. If you wish to allow use of your version of this file only
21 * under the terms of either the GPL or the LGPL, and not to allow others to
22 * use your version of this file under the terms of the CPL, indicate your
23 * decision by deleting the provisions above and replace them with the notice
24 * and other provisions required by the GPL or the LGPL. If you do not delete
25 * the provisions above, a recipient may use your version of this file under
26 * the terms of any one of the CPL, the GPL or the LGPL.
27 ***** END LICENSE BLOCK *****/
28 package org
.jruby
.ast
.executable
;
30 import org
.jruby
.MetaClass
;
31 import org
.jruby
.Ruby
;
32 import org
.jruby
.RubyArray
;
33 import org
.jruby
.RubyFixnum
;
34 import org
.jruby
.RubyModule
;
35 import org
.jruby
.RubyString
;
36 import org
.jruby
.parser
.StaticScope
;
37 import org
.jruby
.parser
.LocalStaticScope
;
38 import org
.jruby
.runtime
.Block
;
39 import org
.jruby
.runtime
.CallType
;
40 import org
.jruby
.runtime
.MethodIndex
;
41 import org
.jruby
.runtime
.ThreadContext
;
42 import org
.jruby
.runtime
.Visibility
;
43 import org
.jruby
.runtime
.builtin
.IRubyObject
;
44 import org
.jruby
.internal
.runtime
.methods
.WrapperMethod
;
45 import org
.jruby
.internal
.runtime
.methods
.RubiniusMethod
;
46 import org
.jruby
.javasupport
.util
.RuntimeHelpers
;
49 * @author <a href="mailto:ola.bini@ki.se">Ola Bini</a>
51 public class RubiniusMachine
{
52 public final static RubiniusMachine INSTANCE
= new RubiniusMachine();
54 public final static int getInt(char[] bytecodes
, int ix
) {
56 val
+= (bytecodes
[ix
+0]<<24);
57 val
+= (bytecodes
[ix
+1]<<16);
58 val
+= (bytecodes
[ix
+2]<<8);
59 val
+= (bytecodes
[ix
+3]);
63 public IRubyObject
exec(ThreadContext context
, IRubyObject self
, char[] bytecodes
, IRubyObject
[] literals
, IRubyObject
[] args
) {
64 IRubyObject
[] stack
= new IRubyObject
[20];
66 stack
[stackTop
] = context
.getRuntime().getNil();
67 for(int i
=0;i
<args
.length
;i
++) {
68 stack
[++stackTop
] = args
[i
];
73 Ruby runtime
= context
.getRuntime();
77 loop
: while (ip
< bytecodes
.length
) {
79 int code
= bytecodes
[ip
++];
81 System.err.print(RubiniusInstructions.NAMES[code] + " (" + code + ") ");
82 if(RubiniusInstructions.ONE_INT[code]) {
83 System.err.print("[" + getInt(bytecodes, ip) + "] ");
84 } else if(RubiniusInstructions.TWO_INT[code]) {
85 System.err.print("[" + getInt(bytecodes, ip) + ", " + getInt(bytecodes, ip+4) + "] ");
87 System.err.println("{" + ix + "}");
89 for(int i=stackTop; i>=0; i--) {
90 System.err.println(" [" + i + "]=" + stack[i].callMethod(context, "inspect"));
93 case RubiniusInstructions
.NOOP
: {
96 case RubiniusInstructions
.ADD_METHOD
: {
97 int val
= getInt(bytecodes
, ip
);
99 String name
= literals
[val
].toString();
100 RubyModule clzz
= (RubyModule
)stack
[stackTop
--];
101 RubyArray method
= (RubyArray
)stack
[stackTop
--];
103 Visibility visibility
= context
.getCurrentVisibility();
104 if (name
== "initialize" || visibility
== Visibility
.MODULE_FUNCTION
) {
105 visibility
= Visibility
.PRIVATE
;
108 RubiniusCMethod cmethod
= new RubiniusCMethod(method
);
110 StaticScope staticScope
= new LocalStaticScope(context
.getCurrentScope().getStaticScope());
111 staticScope
.setVariables(new String
[cmethod
.locals
]);
112 staticScope
.determineModule();
114 RubiniusMethod newMethod
= new RubiniusMethod(clzz
, cmethod
, staticScope
, visibility
);
116 clzz
.addMethod(name
, newMethod
);
118 if (context
.getCurrentVisibility() == Visibility
.MODULE_FUNCTION
) {
119 clzz
.getSingletonClass().addMethod(
121 new WrapperMethod(clzz
.getSingletonClass(), newMethod
,
123 clzz
.callMethod(context
, "singleton_method_added", literals
[val
]);
126 if (clzz
.isSingleton()) {
127 ((MetaClass
) clzz
).getAttached().callMethod(
128 context
, "singleton_method_added", literals
[val
]);
130 clzz
.callMethod(context
, "method_added", literals
[val
]);
132 stack
[++stackTop
] = method
;
135 case RubiniusInstructions
.META_PUSH_NEG_1
: {
136 stack
[++stackTop
] = RubyFixnum
.minus_one(runtime
);
139 case RubiniusInstructions
.CHECK_ARGCOUNT
: {
140 int min
= getInt(bytecodes
, ip
);
142 int max
= getInt(bytecodes
, ip
);
145 if(args
.length
< min
) {
146 throw runtime
.newArgumentError("wrong # of arguments(" + args
.length
+ " for " + min
+ ")");
147 } else if(max
>0 && args
.length
>max
) {
148 throw runtime
.newArgumentError("wrong # of arguments(" + args
.length
+ " for " + max
+ ")");
152 case RubiniusInstructions
.META_PUSH_0
: {
153 stack
[++stackTop
] = RubyFixnum
.zero(runtime
);
156 case RubiniusInstructions
.META_PUSH_1
: {
157 stack
[++stackTop
] = RubyFixnum
.one(runtime
);
160 case RubiniusInstructions
.META_PUSH_2
: {
161 stack
[++stackTop
] = runtime
.newFixnum(2);
164 case RubiniusInstructions
.SET_LOCAL
: {
165 int local
= getInt(bytecodes
, ip
);
167 context
.getCurrentScope().setValue(local
,stack
[stackTop
],0);
170 case RubiniusInstructions
.PUSH_LOCAL
: {
171 int local
= getInt(bytecodes
, ip
);
173 stack
[++stackTop
] = context
.getCurrentScope().getValue(local
,0);
176 case RubiniusInstructions
.PUSH_NIL
: {
177 stack
[++stackTop
] = runtime
.getNil();
180 case RubiniusInstructions
.PUSH_TRUE
: {
181 stack
[++stackTop
] = runtime
.getTrue();
184 case RubiniusInstructions
.PUSH_FALSE
: {
185 stack
[++stackTop
] = runtime
.getFalse();
188 case RubiniusInstructions
.PUSH_SELF
: {
189 stack
[++stackTop
] = self
;
192 case RubiniusInstructions
.STRING_DUP
: {
193 stack
[stackTop
] = ((RubyString
)stack
[stackTop
]).strDup(context
.getRuntime());
196 case RubiniusInstructions
.PUSH_LITERAL
: {
197 int val
= getInt(bytecodes
, ip
);
199 stack
[++stackTop
] = literals
[val
];
202 case RubiniusInstructions
.META_SEND_OP_LT
: {
203 IRubyObject t1
= stack
[stackTop
--];
204 IRubyObject t2
= stack
[stackTop
--];
205 if((t1
instanceof RubyFixnum
) && (t1
instanceof RubyFixnum
)) {
206 stack
[++stackTop
] = (((RubyFixnum
)t1
).getLongValue() < ((RubyFixnum
)t2
).getLongValue()) ? runtime
.getTrue() : runtime
.getFalse();
208 stack
[++stackTop
] = t1
.callMethod(context
, MethodIndex
.OP_LT
, "<", t2
);
213 case RubiniusInstructions
.META_SEND_OP_GT
: {
214 IRubyObject t1
= stack
[stackTop
--];
215 IRubyObject t2
= stack
[stackTop
--];
216 if((t1
instanceof RubyFixnum
) && (t1
instanceof RubyFixnum
)) {
217 stack
[++stackTop
] = (((RubyFixnum
)t1
).getLongValue() > ((RubyFixnum
)t1
).getLongValue()) ? runtime
.getTrue() : runtime
.getFalse();
219 stack
[++stackTop
] = t1
.callMethod(context
, MethodIndex
.OP_GT
, ">", t2
);
224 case RubiniusInstructions
.META_SEND_OP_PLUS
: {
225 IRubyObject t1
= stack
[stackTop
--];
226 IRubyObject t2
= stack
[stackTop
--];
227 if((t1
instanceof RubyFixnum
) && (t2
instanceof RubyFixnum
)) {
228 stack
[++stackTop
] = ((RubyFixnum
)t1
).op_plus(context
, t2
);
230 stack
[++stackTop
] = t1
.callMethod(context
, MethodIndex
.OP_PLUS
, "+", t2
);
234 case RubiniusInstructions
.META_SEND_OP_MINUS
: {
236 IRubyObject t1
= stack
[stackTop
--];
237 IRubyObject t2
= stack
[stackTop
--];
238 if((t1
instanceof RubyFixnum
) && (t2
instanceof RubyFixnum
)) {
239 stack
[++stackTop
] = ((RubyFixnum
)t1
).op_minus(context
, t2
);
241 stack
[++stackTop
] = t1
.callMethod(context
, MethodIndex
.OP_MINUS
, "-", t2
);
245 case RubiniusInstructions
.POP
: {
249 case RubiniusInstructions
.SET_CALL_FLAGS
: {
250 int val
= getInt(bytecodes
, ip
);
255 case RubiniusInstructions
.SET_CACHE_INDEX
: {
256 int val
= getInt(bytecodes
, ip
);
261 case RubiniusInstructions
.SEND_STACK
: {
262 int index
= getInt(bytecodes
, ip
);
264 int num_args
= getInt(bytecodes
, ip
);
267 String name
= literals
[index
].toString();
268 int ixi
= MethodIndex
.getIndex(name
);
269 recv
= stack
[stackTop
--];
270 IRubyObject
[] argu
= new IRubyObject
[num_args
];
271 for(int i
=0;i
<num_args
;i
++) {
272 argu
[i
] = stack
[stackTop
--];
274 if((call_flags
& 0x01) == 0x01) { //Functional
275 stack
[++stackTop
] = RuntimeHelpers
.invoke(context
, recv
, name
, argu
, Block
.NULL_BLOCK
);
277 stack
[++stackTop
] = RuntimeHelpers
.invoke(context
, recv
, name
, argu
, CallType
.NORMAL
, Block
.NULL_BLOCK
);
281 case RubiniusInstructions
.GOTO_IF_FALSE
: {
282 int val
= getInt(bytecodes
, ip
);
284 if(!stack
[stackTop
--].isTrue()) {
289 case RubiniusInstructions
.GOTO_IF_TRUE
: {
290 int val
= getInt(bytecodes
, ip
);
292 if(stack
[stackTop
--].isTrue()) {
297 case RubiniusInstructions
.SWAP_STACK
: {
298 IRubyObject swap
= stack
[stackTop
];
299 stack
[stackTop
] = stack
[stackTop
-1];
300 stack
[stackTop
-1] = swap
;
303 case RubiniusInstructions
.DUP_TOP
: {
304 stack
[stackTop
+1] = stack
[stackTop
];
308 case RubiniusInstructions
.GOTO
: {
309 int val
= getInt(bytecodes
, ip
);
314 case RubiniusInstructions
.RET
: {
315 return stack
[stackTop
];
317 case RubiniusInstructions
.PUSH_INT
: {
318 int val
= getInt(bytecodes
, ip
);
320 stack
[++stackTop
] = runtime
.newFixnum(val
);
323 case RubiniusInstructions
.PUSH_CONST
: {
324 int index
= getInt(bytecodes
, ip
);
327 String name
= literals
[index
].toString();
328 stack
[++stackTop
] = context
.getConstant(name
);
332 System
.err
.println("--COULDN'T");
333 if(RubiniusInstructions
.ONE_INT
[code
]) {
335 } else if(RubiniusInstructions
.TWO_INT
[code
]) {