Skip to content

Commit c47de21

Browse files
committed
[GR-10422] GraalPython in RC2 is slow.
PullRequest: graalpython/146
2 parents 8b6009f + 5db2b87 commit c47de21

File tree

8 files changed

+419
-17
lines changed

8 files changed

+419
-17
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ImpModuleBuiltins.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
import com.oracle.graal.python.builtins.objects.function.PArguments;
6464
import com.oracle.graal.python.builtins.objects.module.PythonModule;
6565
import com.oracle.graal.python.builtins.objects.object.PythonObject;
66+
import com.oracle.graal.python.builtins.objects.str.PString;
6667
import com.oracle.graal.python.nodes.attributes.ReadAttributeFromObjectNode;
6768
import com.oracle.graal.python.nodes.call.special.CallUnaryMethodNode;
6869
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
@@ -343,6 +344,11 @@ public Object run(String path, String modulename) {
343344
return run(path, getCore().lookupBuiltinModule(modulename));
344345
}
345346

347+
@Specialization
348+
public Object run(PString path, String modulename) {
349+
return run(path.getValue(), getCore().lookupBuiltinModule(modulename));
350+
}
351+
346352
@Specialization
347353
@TruffleBoundary
348354
public Object run(String path, PythonModule mod) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SREModuleBuiltins.java

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
5959
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
6060
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
61+
import com.oracle.graal.python.nodes.truffle.PythonArithmeticTypes;
6162
import com.oracle.graal.python.runtime.exception.PythonErrorType;
6263
import com.oracle.truffle.api.CompilerAsserts;
6364
import com.oracle.truffle.api.CompilerDirectives;
@@ -68,6 +69,7 @@
6869
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
6970
import com.oracle.truffle.api.dsl.NodeFactory;
7071
import com.oracle.truffle.api.dsl.Specialization;
72+
import com.oracle.truffle.api.dsl.TypeSystemReference;
7173
import com.oracle.truffle.api.interop.ArityException;
7274
import com.oracle.truffle.api.interop.ForeignAccess;
7375
import com.oracle.truffle.api.interop.Message;
@@ -253,16 +255,16 @@ Object run(Object o) {
253255

254256
}
255257

256-
@Builtin(name = "tregex_call_safe", minNumOfArguments = 1, takesVariableArguments = true)
258+
@Builtin(name = "tregex_call_safe", fixedNumOfArguments = 3)
259+
@TypeSystemReference(PythonArithmeticTypes.class)
257260
@GenerateNodeFactory
258261
abstract static class TRegexCallSafe extends PythonBuiltinNode {
259-
@Specialization(guards = "isForeignObject(callable)")
260-
Object call(TruffleObject callable, Object[] arguments,
261-
@Cached("create()") BranchProfile runtimeError,
262-
@Cached("create()") BranchProfile typeError,
263-
@Cached("createExecute()") Node invokeNode) {
262+
263+
private Object doIt(TruffleObject callable, String arg1, Object arg2,
264+
BranchProfile runtimeError,
265+
BranchProfile typeError, Node invokeNode) {
264266
try {
265-
return ForeignAccess.sendExecute(invokeNode, callable, arguments);
267+
return ForeignAccess.sendExecute(invokeNode, callable, new Object[]{arg1, arg2});
266268
} catch (ArityException | UnsupportedTypeException | UnsupportedMessageException e) {
267269
typeError.enter();
268270
throw raise(TypeError, "%s", e);
@@ -272,10 +274,24 @@ Object call(TruffleObject callable, Object[] arguments,
272274
}
273275
}
274276

277+
@Specialization(guards = "isForeignObject(callable)")
278+
Object call(TruffleObject callable, String arg1, String arg2,
279+
@Cached("create()") BranchProfile runtimeError,
280+
@Cached("create()") BranchProfile typeError,
281+
@Cached("createExecute()") Node invokeNode) {
282+
return doIt(callable, arg1, arg2, runtimeError, typeError, invokeNode);
283+
}
284+
285+
@Specialization(guards = "isForeignObject(callable)")
286+
Object call(TruffleObject callable, String arg1, int arg2,
287+
@Cached("create()") BranchProfile runtimeError,
288+
@Cached("create()") BranchProfile typeError,
289+
@Cached("createExecute()") Node invokeNode) {
290+
return doIt(callable, arg1, arg2, runtimeError, typeError, invokeNode);
291+
}
292+
275293
protected static Node createExecute() {
276294
return Message.EXECUTE.createNode();
277295
}
278-
279296
}
280-
281297
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/UnicodeDataModuleBuiltins.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import com.oracle.graal.python.builtins.Builtin;
4949
import com.oracle.graal.python.builtins.CoreFunctions;
5050
import com.oracle.graal.python.builtins.PythonBuiltins;
51+
import com.oracle.graal.python.builtins.objects.str.PString;
5152
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
5253
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
5354
import com.oracle.truffle.api.dsl.Cached;
@@ -85,5 +86,13 @@ public String normalize(@SuppressWarnings("unused") String form, String unistr,
8586
}
8687
return Normalizer.normalize(unistr, cachedNormForm);
8788
}
89+
90+
@Specialization(guards = {"form.equals(cachedForm)"}, limit = "4")
91+
public String normalize(String form, PString unistr,
92+
@Cached("form") String cachedForm,
93+
@Cached("getForm(cachedForm)") Normalizer.Form cachedNormForm) {
94+
return normalize(form, unistr.getValue(), cachedForm, cachedNormForm);
95+
}
96+
8897
}
8998
}
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
/*
2+
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.graal.python.builtins.objects.str;
42+
43+
import com.oracle.graal.python.nodes.PGuards;
44+
import com.oracle.graal.python.runtime.PythonOptions;
45+
import com.oracle.truffle.api.CompilerAsserts;
46+
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
47+
import com.oracle.truffle.api.profiles.ConditionProfile;
48+
49+
public class LazyString implements CharSequence {
50+
51+
protected static int MinLazyStringLength = PythonOptions.getMinLazyStringLength();
52+
protected static boolean UseLazyStrings = PythonOptions.useLazyString();
53+
54+
public static int length(CharSequence cs, ConditionProfile profile1, ConditionProfile profile2) {
55+
if (profile1.profile(cs instanceof String)) {
56+
return ((String) cs).length();
57+
} else if (profile2.profile(cs instanceof LazyString)) {
58+
return ((LazyString) cs).length();
59+
}
60+
return lengthIntl(cs);
61+
}
62+
63+
@TruffleBoundary
64+
private static int lengthIntl(CharSequence cs) {
65+
return cs.length();
66+
}
67+
68+
@TruffleBoundary
69+
public static CharSequence create(CharSequence left, CharSequence right) {
70+
assert PGuards.isString(left) || left instanceof LazyString;
71+
assert PGuards.isString(right) || right instanceof LazyString;
72+
if (UseLazyStrings) {
73+
if (left.length() == 0) {
74+
return right;
75+
} else if (right.length() == 0) {
76+
return left;
77+
}
78+
int resultLength = left.length() + right.length();
79+
if (resultLength < MinLazyStringLength) {
80+
return left.toString() + right.toString();
81+
}
82+
return new LazyString(left, right, resultLength);
83+
} else {
84+
return left.toString() + right.toString();
85+
}
86+
}
87+
88+
/**
89+
* Only use when invariants are checked already, e.g. from specializing nodes.
90+
*/
91+
@TruffleBoundary
92+
public static CharSequence createChecked(CharSequence left, CharSequence right, int length) {
93+
assert assertChecked(left, right, length);
94+
return new LazyString(left, right, length);
95+
}
96+
97+
private static boolean assertChecked(CharSequence left, CharSequence right, int length) {
98+
assert UseLazyStrings;
99+
assert (PGuards.isString(left) || left instanceof LazyString) && (PGuards.isString(right) || right instanceof LazyString);
100+
assert length == left.length() + right.length();
101+
assert left.length() > 0 && right.length() > 0;
102+
assert length >= MinLazyStringLength;
103+
return true;
104+
}
105+
106+
/**
107+
* Variant of {@link #createChecked} that tries to concatenate a very short string to an already
108+
* short root leaf up-front, e.g. when appending single characters.
109+
*/
110+
@TruffleBoundary
111+
public static CharSequence createCheckedShort(CharSequence left, CharSequence right, int length) {
112+
assertChecked(left, right, length);
113+
final int tinyLimit = 1;
114+
final int appendToLeafLimit = MinLazyStringLength / 2;
115+
if (left instanceof LazyString && right instanceof String && right.length() <= tinyLimit) {
116+
CharSequence ll = ((LazyString) left).left;
117+
CharSequence lr = ((LazyString) left).right;
118+
if (lr != null && lr instanceof String && lr.length() + right.length() <= appendToLeafLimit) {
119+
return new LazyString(ll, lr.toString() + right.toString(), length);
120+
}
121+
} else if (left instanceof String && left.length() <= tinyLimit && right instanceof LazyString) {
122+
CharSequence ll = ((LazyString) right).left;
123+
CharSequence lr = ((LazyString) right).right;
124+
if (lr != null && ll instanceof String && left.length() + ll.length() <= appendToLeafLimit) {
125+
return new LazyString(left.toString() + ll.toString(), lr, length);
126+
}
127+
}
128+
return new LazyString(left, right, length);
129+
}
130+
131+
private CharSequence left;
132+
private CharSequence right;
133+
private final int length;
134+
135+
private LazyString(CharSequence left, CharSequence right, int length) {
136+
assert left.length() > 0 && right.length() > 0 && length == left.length() + right.length();
137+
this.left = left;
138+
this.right = right;
139+
this.length = length;
140+
}
141+
142+
private LazyString(CharSequence left, CharSequence right) {
143+
this(left, right, left.length() + right.length());
144+
}
145+
146+
@Override
147+
public int length() {
148+
return length;
149+
}
150+
151+
@Override
152+
public String toString() {
153+
if (!isFlat()) {
154+
flatten();
155+
}
156+
return (String) left;
157+
}
158+
159+
private boolean isFlat() {
160+
return right == null;
161+
}
162+
163+
@TruffleBoundary
164+
private void flatten() {
165+
char[] dst = new char[length];
166+
flatten(this, 0, length, dst, 0);
167+
left = new String(dst);
168+
right = null;
169+
}
170+
171+
private static void flatten(CharSequence src, int srcBegin, int srcEnd, char[] dst, int dstBegin) {
172+
CompilerAsserts.neverPartOfCompilation();
173+
CharSequence str = src;
174+
int from = srcBegin;
175+
int to = srcEnd;
176+
int dstFrom = dstBegin;
177+
for (;;) {
178+
assert 0 <= from && from <= to && to <= str.length();
179+
if (str instanceof LazyString) {
180+
LazyString lazyString = (LazyString) str;
181+
CharSequence left = lazyString.left;
182+
CharSequence right = lazyString.right;
183+
int mid = left.length();
184+
185+
if (to - mid >= mid - from) {
186+
// right is longer, recurse left
187+
if (from < mid) {
188+
if (left instanceof String) {
189+
((String) left).getChars(from, mid, dst, dstFrom);
190+
} else {
191+
flatten(left, from, mid, dst, dstFrom);
192+
}
193+
dstFrom += mid - from;
194+
from = 0;
195+
} else {
196+
from -= mid;
197+
}
198+
to -= mid;
199+
str = right;
200+
} else {
201+
// left is longer, recurse right
202+
if (to > mid) {
203+
if (right instanceof String) {
204+
((String) right).getChars(0, to - mid, dst, dstFrom + mid - from);
205+
} else {
206+
flatten(right, 0, to - mid, dst, dstFrom + mid - from);
207+
}
208+
to = mid;
209+
}
210+
str = left;
211+
}
212+
} else if (str instanceof String) {
213+
((String) str).getChars(from, to, dst, dstFrom);
214+
return;
215+
}
216+
}
217+
}
218+
219+
@Override
220+
public char charAt(int index) {
221+
return toString().charAt(index);
222+
}
223+
224+
@Override
225+
public CharSequence subSequence(int start, int end) {
226+
return toString().subSequence(start, end);
227+
}
228+
229+
public boolean isEmpty() {
230+
return length == 0;
231+
}
232+
233+
// accessed via Java Interop, JDK-8062624.js
234+
@TruffleBoundary
235+
public boolean startsWith(String prefix) {
236+
return toString().startsWith(prefix);
237+
}
238+
239+
// accessed via Java Interop, JDK-8062624.js
240+
@TruffleBoundary
241+
public boolean endsWith(String prefix) {
242+
return toString().endsWith(prefix);
243+
}
244+
245+
// accessed via Java Interop, JDK-8062624.js
246+
@TruffleBoundary
247+
public byte[] getBytes() {
248+
return toString().getBytes();
249+
}
250+
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/PString.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,18 @@
3333

3434
public final class PString extends PImmutableSequence {
3535

36-
private final String value;
36+
private final CharSequence value;
3737

38-
public PString(PythonClass clazz, String value) {
38+
public PString(PythonClass clazz, CharSequence value) {
3939
super(clazz);
4040
this.value = value;
4141
}
4242

4343
public String getValue() {
44+
return value.toString();
45+
}
46+
47+
public CharSequence getCharSequence() {
4448
return value;
4549
}
4650

@@ -66,7 +70,7 @@ public boolean lessThan(PSequence sequence) {
6670

6771
@Override
6872
public String toString() {
69-
return value;
73+
return value.toString();
7074
}
7175

7276
@Override
@@ -82,6 +86,9 @@ public int index(Object value) {
8286

8387
@Override
8488
public int hashCode() {
89+
if (value instanceof LazyString) {
90+
return value.toString().hashCode();
91+
}
8592
return value.hashCode();
8693
}
8794

0 commit comments

Comments
 (0)