Skip to content

Commit 3204b58

Browse files
committed
efficient and type-specialized list creation in ListLiteralNode and ListNodes.CreateListFromIteratorNode
1 parent 1830b87 commit 3204b58

File tree

10 files changed

+364
-141
lines changed

10 files changed

+364
-141
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/builtins/ListNodes.java

Lines changed: 204 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@
4444
import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError;
4545
import static com.oracle.graal.python.runtime.exception.PythonErrorType.ValueError;
4646

47+
import java.lang.reflect.Array;
48+
import java.util.Arrays;
49+
4750
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
4851
import com.oracle.graal.python.builtins.modules.MathGuards;
4952
import com.oracle.graal.python.builtins.objects.PNone;
@@ -57,53 +60,237 @@
5760
import com.oracle.graal.python.nodes.SpecialMethodNames;
5861
import com.oracle.graal.python.nodes.attributes.LookupAttributeInMRONode;
5962
import com.oracle.graal.python.nodes.builtins.ListNodesFactory.ConstructListNodeGen;
60-
import com.oracle.graal.python.nodes.builtins.ListNodesFactory.CreateListFromIteratorNodeGen;
6163
import com.oracle.graal.python.nodes.builtins.ListNodesFactory.FastConstructListNodeGen;
6264
import com.oracle.graal.python.nodes.builtins.ListNodesFactory.IndexNodeGen;
6365
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode;
6466
import com.oracle.graal.python.nodes.control.GetIteratorNode;
6567
import com.oracle.graal.python.nodes.control.GetNextNode;
6668
import com.oracle.graal.python.nodes.object.GetClassNode;
6769
import com.oracle.graal.python.nodes.truffle.PythonArithmeticTypes;
70+
import com.oracle.graal.python.runtime.PythonOptions;
6871
import com.oracle.graal.python.runtime.exception.PException;
6972
import com.oracle.graal.python.runtime.exception.PythonErrorType;
7073
import com.oracle.graal.python.runtime.sequence.PSequence;
74+
import com.oracle.graal.python.runtime.sequence.storage.DoubleSequenceStorage;
75+
import com.oracle.graal.python.runtime.sequence.storage.IntSequenceStorage;
76+
import com.oracle.graal.python.runtime.sequence.storage.ListSequenceStorage;
77+
import com.oracle.graal.python.runtime.sequence.storage.LongSequenceStorage;
78+
import com.oracle.graal.python.runtime.sequence.storage.ObjectSequenceStorage;
7179
import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage;
80+
import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage.ListStorageType;
81+
import com.oracle.graal.python.runtime.sequence.storage.SequenceStorageFactory;
7282
import com.oracle.graal.python.runtime.sequence.storage.SequenceStoreException;
83+
import com.oracle.graal.python.runtime.sequence.storage.TupleSequenceStorage;
7384
import com.oracle.truffle.api.CompilerDirectives;
85+
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
7486
import com.oracle.truffle.api.dsl.Cached;
7587
import com.oracle.truffle.api.dsl.Fallback;
7688
import com.oracle.truffle.api.dsl.ImportStatic;
7789
import com.oracle.truffle.api.dsl.Specialization;
7890
import com.oracle.truffle.api.dsl.TypeSystemReference;
91+
import com.oracle.truffle.api.nodes.UnexpectedResultException;
7992
import com.oracle.truffle.api.profiles.ConditionProfile;
8093

8194
public abstract class ListNodes {
8295

83-
@ImportStatic({PGuards.class, SpecialMethodNames.class})
84-
public abstract static class CreateListFromIteratorNode extends PBaseNode {
96+
public final static class CreateListFromIteratorNode extends PBaseNode {
8597

86-
public abstract PList execute(PythonClass cls, Object iterable);
98+
private static final int START_SIZE = 2;
8799

88-
@Specialization
89-
public PList create(PythonClass cls, Object iterator,
90-
@Cached("create()") GetNextNode next,
91-
@Cached("createBinaryProfile()") ConditionProfile errorProfile) {
92-
PList list = factory().createList(cls);
100+
@Child private GetNextNode next = GetNextNode.create();
101+
102+
private final ConditionProfile errorProfile = ConditionProfile.createBinaryProfile();
103+
104+
@CompilationFinal private ListStorageType type;
105+
106+
public CreateListFromIteratorNode() {
107+
this.type = PythonOptions.getOption(getContext(), PythonOptions.UnboxSequenceStorage) ? ListStorageType.Uninitialized : ListStorageType.Generic;
108+
}
109+
110+
public static CreateListFromIteratorNode create() {
111+
return new CreateListFromIteratorNode();
112+
}
113+
114+
public PList execute(PythonClass cls, Object iterator) {
115+
SequenceStorage storage;
116+
if (type == ListStorageType.Uninitialized) {
117+
try {
118+
Object[] elements = new Object[START_SIZE];
119+
int i = 0;
120+
while (true) {
121+
try {
122+
Object value = next.execute(iterator);
123+
if (i >= elements.length) {
124+
elements = Arrays.copyOf(elements, elements.length * 2);
125+
}
126+
elements[i++] = value;
127+
} catch (PException e) {
128+
e.expectStopIteration(getCore(), errorProfile);
129+
break;
130+
}
131+
}
132+
storage = new SequenceStorageFactory().createStorage(Arrays.copyOf(elements, i));
133+
if (storage instanceof IntSequenceStorage) {
134+
type = ListStorageType.Int;
135+
} else if (storage instanceof LongSequenceStorage) {
136+
type = ListStorageType.Long;
137+
} else if (storage instanceof DoubleSequenceStorage) {
138+
type = ListStorageType.Double;
139+
} else if (storage instanceof ListSequenceStorage) {
140+
type = ListStorageType.List;
141+
} else if (storage instanceof TupleSequenceStorage) {
142+
type = ListStorageType.Tuple;
143+
} else {
144+
type = ListStorageType.Generic;
145+
}
146+
} catch (Throwable t) {
147+
type = ListStorageType.Generic;
148+
throw t;
149+
}
150+
} else {
151+
int i = 0;
152+
Object array = null;
153+
try {
154+
switch (type) {
155+
case Int: {
156+
int[] elements = new int[START_SIZE];
157+
array = elements;
158+
while (true) {
159+
try {
160+
int value = next.executeInt(iterator);
161+
if (i >= elements.length) {
162+
elements = Arrays.copyOf(elements, elements.length * 2);
163+
}
164+
elements[i++] = value;
165+
} catch (PException e) {
166+
e.expectStopIteration(getCore(), errorProfile);
167+
break;
168+
}
169+
}
170+
storage = new IntSequenceStorage(elements, i);
171+
break;
172+
}
173+
case Long: {
174+
long[] elements = new long[START_SIZE];
175+
array = elements;
176+
while (true) {
177+
try {
178+
long value = next.executeLong(iterator);
179+
if (i >= elements.length) {
180+
elements = Arrays.copyOf(elements, elements.length * 2);
181+
}
182+
elements[i++] = value;
183+
} catch (PException e) {
184+
e.expectStopIteration(getCore(), errorProfile);
185+
break;
186+
}
187+
}
188+
storage = new LongSequenceStorage(elements, i);
189+
break;
190+
}
191+
case Double: {
192+
double[] elements = new double[START_SIZE];
193+
array = elements;
194+
while (true) {
195+
try {
196+
double value = next.executeDouble(iterator);
197+
if (i >= elements.length) {
198+
elements = Arrays.copyOf(elements, elements.length * 2);
199+
}
200+
elements[i++] = value;
201+
} catch (PException e) {
202+
e.expectStopIteration(getCore(), errorProfile);
203+
break;
204+
}
205+
}
206+
storage = new DoubleSequenceStorage(elements, i);
207+
break;
208+
}
209+
case List: {
210+
PList[] elements = new PList[START_SIZE];
211+
array = elements;
212+
while (true) {
213+
try {
214+
Object value = next.execute(iterator);
215+
if (i >= elements.length) {
216+
elements = Arrays.copyOf(elements, elements.length * 2);
217+
}
218+
elements[i++] = PList.expect(value);
219+
} catch (PException e) {
220+
e.expectStopIteration(getCore(), errorProfile);
221+
break;
222+
}
223+
}
224+
storage = new ListSequenceStorage(elements, i);
225+
break;
226+
}
227+
case Tuple: {
228+
PTuple[] elements = new PTuple[START_SIZE];
229+
array = elements;
230+
while (true) {
231+
try {
232+
Object value = next.execute(iterator);
233+
if (i >= elements.length) {
234+
elements = Arrays.copyOf(elements, elements.length * 2);
235+
}
236+
elements[i++] = PTuple.expect(value);
237+
} catch (PException e) {
238+
e.expectStopIteration(getCore(), errorProfile);
239+
break;
240+
}
241+
}
242+
storage = new TupleSequenceStorage(elements, i);
243+
break;
244+
}
245+
case Generic: {
246+
Object[] elements = new Object[START_SIZE];
247+
array = elements;
248+
while (true) {
249+
try {
250+
Object value = next.execute(iterator);
251+
if (i >= elements.length) {
252+
elements = Arrays.copyOf(elements, elements.length * 2);
253+
}
254+
elements[i++] = value;
255+
} catch (PException e) {
256+
e.expectStopIteration(getCore(), errorProfile);
257+
break;
258+
}
259+
}
260+
storage = new ObjectSequenceStorage(elements, i);
261+
break;
262+
}
263+
default:
264+
throw new RuntimeException("unexpected state");
265+
}
266+
} catch (UnexpectedResultException e) {
267+
storage = genericFallback(iterator, array, i, e.getResult());
268+
}
269+
}
270+
return factory().createList(cls, storage);
271+
}
272+
273+
private SequenceStorage genericFallback(Object iterator, Object array, int count, Object result) {
274+
type = ListStorageType.Generic;
275+
Object[] elements = new Object[Array.getLength(array) * 2];
276+
int i = 0;
277+
for (; i < count; i++) {
278+
elements[i] = Array.get(array, i);
279+
}
280+
elements[i++] = result;
93281
while (true) {
94-
Object value;
95282
try {
96-
value = next.execute(iterator);
283+
Object value = next.execute(iterator);
284+
if (i >= elements.length) {
285+
elements = Arrays.copyOf(elements, elements.length * 2);
286+
}
287+
elements[i++] = value;
97288
} catch (PException e) {
98289
e.expectStopIteration(getCore(), errorProfile);
99-
return list;
290+
break;
100291
}
101-
list.append(value);
102292
}
103-
}
104-
105-
public static CreateListFromIteratorNode create() {
106-
return CreateListFromIteratorNodeGen.create();
293+
return new ObjectSequenceStorage(elements, i);
107294
}
108295
}
109296

0 commit comments

Comments
 (0)