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.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.methods.*;
|
|
19
|
|
20 /**
|
|
21 * An unboxed node in the dispatch chain that dispatches if the node is a boolean. In normal unboxed
|
|
22 * dispatch we look at the Java class of the receiver. However, in Ruby true and false are two
|
|
23 * separate classes, so in this situation we have to dispatch on the value, as well as the Java
|
|
24 * class when we are dealing with booleans.
|
|
25 * <p>
|
|
26 * TODO(CS): it would be nice if we could {@link RubyNode#executeBoolean} the receiver, but by the
|
|
27 * time we get to this dispatch node the receiver is already executed.
|
|
28 */
|
|
29 public class BooleanDispatchNode extends UnboxedDispatchNode {
|
|
30
|
|
31 private final Assumption falseUnmodifiedAssumption;
|
|
32 private final RubyMethod falseMethod;
|
|
33
|
|
34 private final Assumption trueUnmodifiedAssumption;
|
|
35 private final RubyMethod trueMethod;
|
|
36
|
|
37 @Child protected UnboxedDispatchNode next;
|
|
38
|
|
39 public BooleanDispatchNode(RubyContext context, SourceSection sourceSection, Assumption falseUnmodifiedAssumption, RubyMethod falseMethod, Assumption trueUnmodifiedAssumption,
|
|
40 RubyMethod trueMethod, UnboxedDispatchNode next) {
|
|
41 super(context, sourceSection);
|
|
42
|
|
43 assert falseUnmodifiedAssumption != null;
|
|
44 assert falseMethod != null;
|
|
45 assert trueUnmodifiedAssumption != null;
|
|
46 assert trueMethod != null;
|
|
47
|
|
48 this.falseUnmodifiedAssumption = falseUnmodifiedAssumption;
|
|
49 this.falseMethod = falseMethod;
|
|
50
|
|
51 this.trueUnmodifiedAssumption = trueUnmodifiedAssumption;
|
|
52 this.trueMethod = trueMethod;
|
|
53
|
|
54 this.next = adoptChild(next);
|
|
55 }
|
|
56
|
|
57 @Override
|
|
58 public Object dispatch(VirtualFrame frame, Object receiverObject, RubyProc blockObject, Object[] argumentsObjects) {
|
|
59 // Check it's a boolean
|
|
60
|
|
61 if (!(receiverObject instanceof Boolean)) {
|
|
62 return next.dispatch(frame, receiverObject, blockObject, argumentsObjects);
|
|
63 }
|
|
64
|
|
65 // Check the value
|
|
66
|
|
67 Assumption unmodifiedAssumption;
|
|
68 RubyMethod method;
|
|
69
|
|
70 if ((boolean) receiverObject) {
|
|
71 unmodifiedAssumption = trueUnmodifiedAssumption;
|
|
72 method = trueMethod;
|
|
73 } else {
|
|
74 unmodifiedAssumption = falseUnmodifiedAssumption;
|
|
75 method = falseMethod;
|
|
76 }
|
|
77
|
|
78 // Check the class has not been modified
|
|
79
|
|
80 try {
|
|
81 unmodifiedAssumption.check();
|
|
82 } catch (InvalidAssumptionException e) {
|
|
83 return respecialize("class modified", frame, receiverObject, blockObject, argumentsObjects);
|
|
84 }
|
|
85
|
|
86 // Call the method
|
|
87
|
|
88 return method.call(frame.pack(), receiverObject, blockObject, argumentsObjects);
|
|
89 }
|
|
90
|
|
91 @Override
|
|
92 public void setNext(UnboxedDispatchNode next) {
|
|
93 this.next = adoptChild(next);
|
|
94 }
|
|
95
|
|
96 }
|