-
Notifications
You must be signed in to change notification settings - Fork 4
/
ReadTruffleStringPropertyNode.java
113 lines (104 loc) · 4.89 KB
/
ReadTruffleStringPropertyNode.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package com.endoflineblog.truffle.part_11.nodes.exprs.strings;
import com.endoflineblog.truffle.part_11.nodes.EasyScriptNode;
import com.endoflineblog.truffle.part_11.runtime.EasyScriptTruffleStrings;
import com.endoflineblog.truffle.part_11.runtime.FunctionObject;
import com.endoflineblog.truffle.part_11.runtime.Undefined;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.ImportStatic;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.strings.TruffleString;
/**
* An AST node that represents reading properties of strings.
* Since EasyScript uses the Truffle {@link TruffleString}
* type as its string representation,
* we don't want to wrap it in another {@code TruffleObject},
* like {@code ArrayObject}.
* For that reason, we need this dedicated Node type to read string properties.
* Note that this class does not extend {@code EasyScriptExprNode},
* similarly to how {@code FunctionDispatchNode} works,
* so it can define its own {@link #executeReadTruffleStringProperty execute*() method}.
*
* @see #executeReadTruffleStringProperty
* @see #readStringIndex
* @see #readLengthProperty
* @see #readCharAtPropertyCached
* @see #readCharAtPropertyUncached
* @see #readUnknownProperty
*/
@ImportStatic(EasyScriptTruffleStrings.class)
public abstract class ReadTruffleStringPropertyNode extends EasyScriptNode {
protected static final String LENGTH_PROP = "length";
protected static final String CHAR_AT_PROP = "charAt";
/** The abstract {@code execute*()} method for this node. */
public abstract Object executeReadTruffleStringProperty(TruffleString truffleString, Object property);
/**
* The specialization used when accessing an integer index of a string,
* in code like {@code "abc"[1]}.
*/
@Specialization
protected Object readStringIndex(
TruffleString truffleString,
int index,
@Cached TruffleString.CodePointLengthNode lengthNode,
@Cached TruffleString.SubstringNode substringNode) {
return index < 0 || index >= EasyScriptTruffleStrings.length(truffleString, lengthNode)
? Undefined.INSTANCE
: EasyScriptTruffleStrings.substring(truffleString, index, 1, substringNode);
}
/**
* The specialization used when accessing the {@code length}
* property of a string, in code like {@code "abc".length}
* or {@code "abc"['length']}.
*/
@Specialization(guards = "LENGTH_PROP.equals(propertyName)")
protected int readLengthProperty(
TruffleString truffleString,
@SuppressWarnings("unused") String propertyName,
@Cached TruffleString.CodePointLengthNode lengthNode) {
return EasyScriptTruffleStrings.length(truffleString, lengthNode);
}
/**
* The specialization used when accessing the {@code charAt}
* property of a string, in code like {@code "abc".charAt}
* or {@code "abc"['charAt']}.
* This is the "fast" version of the specialization,
* which caches the created {@link FunctionObject},
* instead of creating a new object each time the node is executed.
*/
@Specialization(guards = {
"CHAR_AT_PROP.equals(propertyName)",
"same(charAtMethod.methodTarget, truffleString)"
})
protected FunctionObject readCharAtPropertyCached(
@SuppressWarnings("unused") TruffleString truffleString,
@SuppressWarnings("unused") String propertyName,
@Cached("createCharAtMethodObject(truffleString)") FunctionObject charAtMethod) {
return charAtMethod;
}
/**
* The "slow" specialization version of reading the {@code charAt}
* property that we switch to when {@link #readCharAtPropertyCached}
* encounters more than 3 different string targets
* (3 is the default instantiation limit for specializations in Truffle).
* In that case, we no longer cache the {@link FunctionObject}
* representing a given method,
* but simply create a new object each time the node is executed.
*/
@Specialization(guards = "CHAR_AT_PROP.equals(propertyName)", replaces = "readCharAtPropertyCached")
protected FunctionObject readCharAtPropertyUncached(
TruffleString truffleString,
@SuppressWarnings("unused") String propertyName) {
return createCharAtMethodObject(truffleString);
}
protected FunctionObject createCharAtMethodObject(TruffleString truffleString) {
return new FunctionObject(currentLanguageContext().stringPrototype.charAtMethod, 2, truffleString);
}
/** Accessing any other string property should return 'undefined'. */
@Fallback
protected Undefined readUnknownProperty(
@SuppressWarnings("unused") TruffleString truffleString,
@SuppressWarnings("unused") Object property) {
return Undefined.INSTANCE;
}
}