25
25
*/
26
26
package com .oracle .graal .python .nodes .frame ;
27
27
28
- import static com .oracle .graal .python .builtins .objects .PNone .NO_VALUE ;
29
- import static com .oracle .graal .python .nodes .SpecialMethodNames .__GETITEM__ ;
30
- import static com .oracle .graal .python .runtime .exception .PythonErrorType .IndexError ;
31
28
import static com .oracle .graal .python .runtime .exception .PythonErrorType .ValueError ;
32
29
33
- import java .util .Arrays ;
34
-
35
30
import com .oracle .graal .python .PythonLanguage ;
36
- import com .oracle .graal .python .builtins .modules .BuiltinFunctions ;
37
- import com .oracle .graal .python .builtins .modules .BuiltinFunctionsFactory ;
31
+ import com .oracle .graal .python .builtins .PythonBuiltinClassType ;
32
+ import com .oracle .graal .python .builtins .objects .common .SequenceStorageNodes ;
33
+ import com .oracle .graal .python .builtins .objects .list .PList ;
34
+ import com .oracle .graal .python .builtins .objects .tuple .PTuple ;
38
35
import com .oracle .graal .python .nodes .PRaiseNode ;
39
- import com .oracle .graal .python .nodes .attributes .LookupInheritedAttributeNode ;
40
- import com .oracle .graal .python .nodes .builtins .ListNodes .CreateStorageFromIteratorNode ;
41
36
import com .oracle .graal .python .nodes .builtins .TupleNodes ;
42
- import com .oracle .graal .python .nodes .control .GetIteratorExpressionNode .GetIteratorNode ;
43
37
import com .oracle .graal .python .nodes .expression .ExpressionNode ;
44
38
import com .oracle .graal .python .nodes .object .IsBuiltinClassProfile ;
45
39
import com .oracle .graal .python .nodes .statement .StatementNode ;
46
- import com .oracle .graal .python .nodes .subscript .GetItemNode ;
47
- import com .oracle .graal .python .nodes .subscript .GetItemNodeGen ;
48
40
import com .oracle .graal .python .runtime .PythonContext ;
49
- import com .oracle .graal .python .runtime .exception . PException ;
41
+ import com .oracle .graal .python .runtime .PythonCore ;
50
42
import com .oracle .graal .python .runtime .object .PythonObjectFactory ;
43
+ import com .oracle .graal .python .runtime .sequence .storage .SequenceStorage ;
44
+ import com .oracle .truffle .api .CompilerAsserts ;
51
45
import com .oracle .truffle .api .CompilerDirectives ;
52
46
import com .oracle .truffle .api .CompilerDirectives .CompilationFinal ;
53
47
import com .oracle .truffle .api .TruffleLanguage .ContextReference ;
48
+ import com .oracle .truffle .api .dsl .Cached ;
49
+ import com .oracle .truffle .api .dsl .Specialization ;
54
50
import com .oracle .truffle .api .frame .VirtualFrame ;
55
51
import com .oracle .truffle .api .nodes .ExplodeLoop ;
56
- import com .oracle .truffle .api .profiles .BranchProfile ;
57
52
58
- public final class DestructuringAssignmentNode extends StatementNode implements WriteNode {
59
- @ Child private PythonObjectFactory factory = PythonObjectFactory . create ();
53
+ public abstract class DestructuringAssignmentNode extends StatementNode implements WriteNode {
54
+ /* Lazily initialized helpers, also acting as branch profiles */
60
55
@ Child private PRaiseNode raiseNode ;
56
+ @ Child private PythonObjectFactory factory ;
61
57
@ CompilationFinal private ContextReference <PythonContext > contextRef ;
62
58
59
+ /* Syntactic children */
63
60
@ Child private ExpressionNode rhs ;
64
61
@ Children private final WriteNode [] slots ;
65
62
@ Children private final StatementNode [] assignments ;
66
63
67
- @ Child private GetItemNode getItem = GetItemNodeGen .create ();
68
- @ Child private GetItemNode getNonExistingItem = GetItemNodeGen .create ();
69
- @ Child private BuiltinFunctions .LenNode lenNode ;
70
- @ Child private LookupInheritedAttributeNode lookupGetItemNode = LookupInheritedAttributeNode .create (__GETITEM__ );
71
- @ Child private TupleNodes .ConstructTupleNode constructTupleNode = TupleNodes .ConstructTupleNode .create ();
72
-
73
- @ Child private CreateStorageFromIteratorNode storageNode = CreateStorageFromIteratorNode .create ();
74
- @ Child private GetIteratorNode getIteratorNode = GetIteratorNode .create ();
75
-
76
- private final IsBuiltinClassProfile notEnoughValuesProfile = IsBuiltinClassProfile .create ();
77
- private final IsBuiltinClassProfile tooManyValuesErrorProfile = IsBuiltinClassProfile .create ();
78
- private final BranchProfile tooManyValuesProfile = BranchProfile .create ();
79
-
80
- private final IsBuiltinClassProfile errorProfile1 = IsBuiltinClassProfile .create ();
81
- private final IsBuiltinClassProfile errorProfile2 = IsBuiltinClassProfile .create ();
82
- private final int starredIndex ;
64
+ protected final int starredIndex ;
83
65
84
66
public DestructuringAssignmentNode (ExpressionNode rhs , ReadNode [] slots , int starredIndex , StatementNode [] assignments ) {
85
67
this .rhs = rhs ;
@@ -89,135 +71,157 @@ public DestructuringAssignmentNode(ExpressionNode rhs, ReadNode[] slots, int sta
89
71
for (int i = 0 ; i < slots .length ; i ++) {
90
72
this .slots [i ] = (WriteNode ) slots [i ].makeWriteNode (null );
91
73
}
92
- this .lenNode = starredIndex == -1 ? null : BuiltinFunctionsFactory .LenNodeFactory .create ();
93
74
}
94
75
95
76
public static DestructuringAssignmentNode create (ExpressionNode rhs , ReadNode [] slots , int starredIndex , StatementNode [] assignments ) {
96
- return new DestructuringAssignmentNode (rhs , slots , starredIndex , assignments );
77
+ return DestructuringAssignmentNodeGen . create (rhs , slots , starredIndex , assignments );
97
78
}
98
79
99
- @ ExplodeLoop
100
- private void fillSlots ( VirtualFrame frame , Object rhsValue , int stop ) {
101
- for ( int i = 0 ; i < stop ; i ++) {
102
- Object value = getItem . execute ( frame , rhsValue , i );
103
- slots [ i ]. doWrite (frame , value );
104
- }
80
+ public abstract void executeWith ( VirtualFrame frame , Object rhsValue );
81
+
82
+ @ Override
83
+ public final void executeVoid ( VirtualFrame frame ) {
84
+ Object rhsValue = rhs . execute (frame );
85
+ executeWith ( frame , rhsValue );
105
86
}
106
87
107
- @ ExplodeLoop
108
- private int fillRest (VirtualFrame frame , Object rhsValue , int pos ) {
109
- int current = pos ;
110
- for (int i = starredIndex + 1 ; i < slots .length ; i ++) {
111
- Object value = getItem .execute (frame , rhsValue , current ++);
112
- slots [i ].doWrite (frame , value );
113
- }
114
- return current ;
88
+ public final void doWrite (VirtualFrame frame , Object rhsValue ) {
89
+ executeWith (frame , rhsValue );
90
+ }
91
+
92
+ public ExpressionNode getRhs () {
93
+ return rhs ;
94
+ }
95
+
96
+ protected static boolean isBuiltinList (Object object , IsBuiltinClassProfile profile ) {
97
+ return object instanceof PList && profile .profileObject ((PList ) object , PythonBuiltinClassType .PList );
98
+ }
99
+
100
+ protected static boolean isBuiltinTuple (Object object , IsBuiltinClassProfile profile ) {
101
+ return object instanceof PTuple && profile .profileObject ((PTuple ) object , PythonBuiltinClassType .PTuple );
102
+ }
103
+
104
+ @ Specialization (guards = {"isBuiltinList(rhsVal, isBuiltinClass)" , "starredIndex < 0" })
105
+ public void writeList (VirtualFrame frame , PList rhsVal ,
106
+ @ Cached SequenceStorageNodes .LenNode lenNode ,
107
+ @ Cached SequenceStorageNodes .GetItemNode getItemNode ,
108
+ @ SuppressWarnings ("unused" ) @ Cached IsBuiltinClassProfile isBuiltinClass ) {
109
+ SequenceStorage sequenceStorage = rhsVal .getSequenceStorage ();
110
+ writeSequenceStorage (frame , sequenceStorage , lenNode , getItemNode );
111
+ performAssignments (frame );
112
+ }
113
+
114
+ @ Specialization (guards = {"isBuiltinTuple(rhsVal, isBuiltinClass)" , "starredIndex < 0" })
115
+ public void writeTuple (VirtualFrame frame , PTuple rhsVal ,
116
+ @ Cached SequenceStorageNodes .LenNode lenNode ,
117
+ @ Cached SequenceStorageNodes .GetItemNode getItemNode ,
118
+ @ SuppressWarnings ("unused" ) @ Cached IsBuiltinClassProfile isBuiltinClass ) {
119
+ SequenceStorage sequenceStorage = rhsVal .getSequenceStorage ();
120
+ writeSequenceStorage (frame , sequenceStorage , lenNode , getItemNode );
121
+ performAssignments (frame );
115
122
}
116
123
117
124
@ ExplodeLoop
118
- private int fillFromArray (VirtualFrame frame , Object [] array , int startIndex ) {
119
- int index = startIndex ;
120
- for (int i = starredIndex + 1 ; i < slots .length ; i ++) {
121
- slots [i ].doWrite (frame , array [index ++]);
125
+ private void writeSequenceStorage (VirtualFrame frame , SequenceStorage sequenceStorage , SequenceStorageNodes .LenNode lenNode , SequenceStorageNodes .GetItemNode getItemNode ) {
126
+ int len = lenNode .execute (sequenceStorage );
127
+ if (len > slots .length ) {
128
+ throw getCore ().raiseInvalidSyntax (getEncapsulatingSourceSection ().getSource (), getEncapsulatingSourceSection (), "too many values to unpack (expected %d)" , slots .length );
129
+ } else if (len < slots .length ) {
130
+ throw ensureRaiseNode ().raise (ValueError , "not enough values to unpack (expected %d, got %d)" , slots .length , len );
131
+ } else {
132
+ for (int i = 0 ; i < slots .length ; i ++) {
133
+ Object value = getItemNode .execute (sequenceStorage , i );
134
+ slots [i ].doWrite (frame , value );
135
+ }
122
136
}
123
- return index ;
124
137
}
125
138
126
- private int fillStarred (VirtualFrame frame , Object rhsValue ) {
127
- int pos = starredIndex ;
128
- try {
129
- // TODO(ls): proper cast to int
130
- // TODO(ls): the result of the len call doesn't seem to be used in Python
131
- int length = (int ) lenNode .executeWith (frame , rhsValue );
132
- int starredLength = length - (slots .length - 1 );
139
+ @ Specialization (guards = {"isBuiltinList(rhsVal, isBuiltinClass)" , "starredIndex >= 0" })
140
+ public void writeListStarred (VirtualFrame frame , PList rhsVal ,
141
+ @ Cached SequenceStorageNodes .LenNode lenNode ,
142
+ @ Cached SequenceStorageNodes .GetItemNode getItemNode ,
143
+ @ SuppressWarnings ("unused" ) @ Cached IsBuiltinClassProfile isBuiltinClass ) {
144
+ SequenceStorage sequenceStorage = rhsVal .getSequenceStorage ();
145
+ writeSequenceStorageStarred (frame , sequenceStorage , lenNode , getItemNode );
146
+ performAssignments (frame );
147
+ }
148
+
149
+ @ Specialization (guards = {"isBuiltinTuple(rhsVal, isBuiltinClass)" , "starredIndex >= 0" })
150
+ public void writeTupleStarred (VirtualFrame frame , PTuple rhsVal ,
151
+ @ Cached SequenceStorageNodes .LenNode lenNode ,
152
+ @ Cached SequenceStorageNodes .GetItemNode getItemNode ,
153
+ @ SuppressWarnings ("unused" ) @ Cached IsBuiltinClassProfile isBuiltinClass ) {
154
+ SequenceStorage sequenceStorage = rhsVal .getSequenceStorage ();
155
+ writeSequenceStorageStarred (frame , sequenceStorage , lenNode , getItemNode );
156
+ performAssignments (frame );
157
+ }
158
+
159
+ @ ExplodeLoop
160
+ private void writeSequenceStorageStarred (VirtualFrame frame , SequenceStorage sequenceStorage , SequenceStorageNodes .LenNode lenNode , SequenceStorageNodes .GetItemNode getItemNode ) {
161
+ int len = lenNode .execute (sequenceStorage );
162
+ if (len < slots .length - 1 ) {
163
+ throw ensureRaiseNode ().raise (ValueError , "not enough values to unpack (expected %d, got %d)" , slots .length , len );
164
+ } else {
165
+ for (int i = 0 ; i < starredIndex ; i ++) {
166
+ Object value = getItemNode .execute (sequenceStorage , i );
167
+ slots [i ].doWrite (frame , value );
168
+ }
169
+ final int starredLength = len - (slots .length - 1 );
133
170
Object [] array = new Object [starredLength ];
171
+ CompilerAsserts .partialEvaluationConstant (starredLength );
172
+ int pos = starredIndex ;
134
173
for (int i = 0 ; i < starredLength ; i ++) {
135
- array [i ] = getItem .execute (frame , rhsValue , pos ++);
174
+ array [i ] = getItemNode .execute (sequenceStorage , pos ++);
136
175
}
137
- slots [starredIndex ].doWrite (frame , factory .createList (array ));
138
- return fillRest (frame , rhsValue , pos );
139
- } catch (PException e ) {
140
- e .expectAttributeError (errorProfile1 );
141
- // __len__ is not implemented
142
- Object [] array = new Object [2 ];
143
- int length = 0 ;
144
- while (true ) {
145
- try {
146
- if (length + 1 > array .length ) {
147
- array = Arrays .copyOf (array , array .length << 1 );
148
- }
149
- array [length ] = getItem .execute (frame , rhsValue , pos );
150
- length ++;
151
- pos ++;
152
- } catch (PException e2 ) {
153
- e2 .expect (IndexError , errorProfile2 );
154
- // expected, fall through
155
- break ;
156
- }
176
+ slots [starredIndex ].doWrite (frame , factory ().createList (array ));
177
+ for (int i = starredIndex + 1 ; i < slots .length ; i ++) {
178
+ Object value = getItemNode .execute (sequenceStorage , pos ++);
179
+ slots [i ].doWrite (frame , value );
157
180
}
158
- int rest = slots .length - starredIndex - 1 ;
159
- fillFromArray (frame , array , length - rest );
160
- slots [starredIndex ].doWrite (frame , factory .createList (Arrays .copyOf (array , length - rest )));
161
181
}
162
- return pos ;
163
182
}
164
183
165
- @ Override
166
- public void executeVoid (VirtualFrame frame ) {
167
- Object rhsValue = rhs .execute (frame );
168
- Object getItemAttribute = lookupGetItemNode .execute (rhsValue );
169
- if (getItemAttribute == NO_VALUE ) {
170
- rhsValue = constructTupleNode .execute (frame , rhsValue );
184
+ @ ExplodeLoop
185
+ private void performAssignments (VirtualFrame frame ) {
186
+ for (int i = 0 ; i < assignments .length ; i ++) {
187
+ assignments [i ].executeVoid (frame );
171
188
}
172
- doWrite (frame , rhsValue );
173
189
}
174
190
175
- public ExpressionNode getRhs () {
176
- return rhs ;
191
+ @ Specialization (guards = {"!isBuiltinTuple(iterable, tupleProfile)" , "!isBuiltinList(iterable, listProfile)" , "starredIndex < 0" })
192
+ public void writeIterable (VirtualFrame frame , Object iterable ,
193
+ @ Cached TupleNodes .ConstructTupleNode constructTupleNode ,
194
+ @ Cached SequenceStorageNodes .LenNode lenNode ,
195
+ @ Cached SequenceStorageNodes .GetItemNode getItemNode ,
196
+ @ SuppressWarnings ("unused" ) @ Cached IsBuiltinClassProfile tupleProfile ,
197
+ @ SuppressWarnings ("unused" ) @ Cached IsBuiltinClassProfile listProfile ) {
198
+ PTuple rhsValue = constructTupleNode .execute (frame , iterable );
199
+ SequenceStorage sequenceStorage = rhsValue .getSequenceStorage ();
200
+ writeSequenceStorage (frame , sequenceStorage , lenNode , getItemNode );
201
+ performAssignments (frame );
177
202
}
178
203
179
- public void doWrite (VirtualFrame frame , Object rhsVal ) {
180
- Object rhsValue = factory .createList (storageNode .execute (frame , getIteratorNode .executeWith (frame , rhsVal )));
181
- int nonExistingItem ;
182
- try {
183
- if (starredIndex == -1 ) {
184
- fillSlots (frame , rhsValue , slots .length );
185
- nonExistingItem = slots .length ;
186
- } else {
187
- fillSlots (frame , rhsValue , starredIndex );
188
- nonExistingItem = fillStarred (frame , rhsValue );
189
- }
190
- } catch (PException e ) {
191
- if (notEnoughValuesProfile .profileException (e , IndexError )) {
192
- if (lenNode == null ) {
193
- CompilerDirectives .transferToInterpreterAndInvalidate ();
194
- lenNode = insert (BuiltinFunctionsFactory .LenNodeFactory .create ());
195
- }
196
- throw ensureRaiseNode ().raise (ValueError , "not enough values to unpack (expected %d, got %d)" , slots .length , lenNode .executeWith (frame , rhsValue ));
197
- } else {
198
- throw e ;
199
- }
200
- }
201
- try {
202
- getNonExistingItem .execute (frame , rhsValue , nonExistingItem );
203
- tooManyValuesProfile .enter ();
204
- if (contextRef == null ) {
205
- CompilerDirectives .transferToInterpreterAndInvalidate ();
206
- contextRef = PythonLanguage .getContextRef ();
207
- }
208
- throw contextRef .get ().getCore ().raiseInvalidSyntax (getEncapsulatingSourceSection ().getSource (), getEncapsulatingSourceSection (), "too many values to unpack (expected %d)" ,
209
- nonExistingItem );
210
- } catch (PException e ) {
211
- if (tooManyValuesErrorProfile .profileException (e , IndexError )) {
212
- // expected, fall through
213
- } else {
214
- throw e ;
215
- }
216
- }
217
-
204
+ @ Specialization (guards = {"!isBuiltinTuple(iterable, tupleProfile)" , "!isBuiltinList(iterable, listProfile)" , "starredIndex >= 0" })
205
+ public void writeIterableStarred (VirtualFrame frame , Object iterable ,
206
+ @ Cached TupleNodes .ConstructTupleNode constructTupleNode ,
207
+ @ Cached SequenceStorageNodes .LenNode lenNode ,
208
+ @ Cached SequenceStorageNodes .GetItemNode getItemNode ,
209
+ @ SuppressWarnings ("unused" ) @ Cached IsBuiltinClassProfile tupleProfile ,
210
+ @ SuppressWarnings ("unused" ) @ Cached IsBuiltinClassProfile listProfile ) {
211
+ PTuple rhsValue = constructTupleNode .execute (frame , iterable );
212
+ SequenceStorage sequenceStorage = rhsValue .getSequenceStorage ();
213
+ writeSequenceStorageStarred (frame , sequenceStorage , lenNode , getItemNode );
218
214
performAssignments (frame );
219
215
}
220
216
217
+ private PythonCore getCore () {
218
+ if (contextRef == null ) {
219
+ CompilerDirectives .transferToInterpreterAndInvalidate ();
220
+ contextRef = PythonLanguage .getContextRef ();
221
+ }
222
+ return contextRef .get ().getCore ();
223
+ }
224
+
221
225
private PRaiseNode ensureRaiseNode () {
222
226
if (raiseNode == null ) {
223
227
CompilerDirectives .transferToInterpreterAndInvalidate ();
@@ -226,10 +230,11 @@ private PRaiseNode ensureRaiseNode() {
226
230
return raiseNode ;
227
231
}
228
232
229
- @ ExplodeLoop
230
- private void performAssignments ( VirtualFrame frame ) {
231
- for ( int i = 0 ; i < assignments . length ; i ++) {
232
- assignments [ i ]. executeVoid ( frame );
233
+ private PythonObjectFactory factory () {
234
+ if ( factory == null ) {
235
+ CompilerDirectives . transferToInterpreterAndInvalidate ();
236
+ factory = insert ( PythonObjectFactory . create () );
233
237
}
238
+ return factory ;
234
239
}
235
240
}
0 commit comments