Skip to content

Commit 410cffe

Browse files
committed
Use CastToJavaString nodes in FormatNodes
1 parent 4c7453f commit 410cffe

File tree

6 files changed

+208
-93
lines changed

6 files changed

+208
-93
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright (c) 2020, 2020, 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.common;
42+
43+
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError;
44+
import static com.oracle.graal.python.nodes.SpecialMethodNames.__STR__;
45+
46+
import com.oracle.graal.python.nodes.ErrorMessages;
47+
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode;
48+
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
49+
import com.oracle.graal.python.nodes.util.CannotCastException;
50+
import com.oracle.graal.python.nodes.util.CastToJavaStringNode;
51+
import com.oracle.truffle.api.CompilerDirectives;
52+
53+
public abstract class FormatNodeBase extends PythonBinaryBuiltinNode {
54+
@Child private LookupAndCallUnaryNode strCall;
55+
56+
protected LookupAndCallUnaryNode ensureStrCallNode() {
57+
if (strCall == null) {
58+
CompilerDirectives.transferToInterpreterAndInvalidate();
59+
strCall = insert(LookupAndCallUnaryNode.create(__STR__));
60+
}
61+
return strCall;
62+
}
63+
64+
protected String castFormatString(Object obj, CastToJavaStringNode castNode) {
65+
try {
66+
return castNode.execute(obj);
67+
} catch (CannotCastException ex) {
68+
throw raise(TypeError, ErrorMessages.ARG_D_MUST_BE_S_NOT_P, "format()", 2, "str", obj);
69+
}
70+
}
71+
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/complex/ComplexBuiltins.java

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -83,18 +83,19 @@
8383
import com.oracle.graal.python.builtins.PythonBuiltins;
8484
import com.oracle.graal.python.builtins.objects.PNone;
8585
import com.oracle.graal.python.builtins.objects.PNotImplemented;
86+
import com.oracle.graal.python.builtins.objects.common.FormatNodeBase;
8687
import com.oracle.graal.python.builtins.objects.floats.FloatBuiltins;
8788
import com.oracle.graal.python.builtins.objects.ints.PInt;
8889
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
8990
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
9091
import com.oracle.graal.python.nodes.ErrorMessages;
91-
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode;
9292
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
9393
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
9494
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
9595
import com.oracle.graal.python.nodes.function.builtins.PythonTernaryBuiltinNode;
9696
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
9797
import com.oracle.graal.python.nodes.truffle.PythonArithmeticTypes;
98+
import com.oracle.graal.python.nodes.util.CastToJavaStringNode;
9899
import com.oracle.graal.python.nodes.util.CoerceToComplexNode;
99100
import com.oracle.graal.python.runtime.PythonCore;
100101
import com.oracle.graal.python.runtime.exception.PythonErrorType;
@@ -734,29 +735,27 @@ abstract static class StrNode extends ReprNode {
734735
@Builtin(name = __FORMAT__, minNumOfPositionalArgs = 2)
735736
@GenerateNodeFactory
736737
@TypeSystemReference(PythonArithmeticTypes.class)
737-
abstract static class FormatNode extends PythonBinaryBuiltinNode {
738-
739-
@Specialization(guards = "formatString.isEmpty()")
740-
Object emptyFormat(VirtualFrame frame, Object self, @SuppressWarnings("unused") String formatString,
741-
@Cached("create(__STR__)") LookupAndCallUnaryNode strCall) {
742-
return strCall.executeObject(frame, self);
738+
abstract static class FormatNode extends FormatNodeBase {
739+
@Specialization
740+
Object format(VirtualFrame frame, PComplex self, Object formatStringObj,
741+
@Cached CastToJavaStringNode castToStringNode) {
742+
String formatString = castFormatString(formatStringObj, castToStringNode);
743+
if (formatString.isEmpty()) {
744+
return ensureStrCallNode().executeObject(frame, self);
745+
}
746+
PythonCore core = getCore();
747+
InternalFormat.Spec spec = InternalFormat.fromText(core, formatString, __FORMAT__);
748+
validateSpec(spec);
749+
return doFormat(self, spec, core);
743750
}
744751

745-
@Specialization(guards = "!formatString.isEmpty()")
746752
@TruffleBoundary
747-
String format(PComplex self, String formatString) {
748-
InternalFormat.Spec spec = InternalFormat.fromText(getCore(), formatString, __FORMAT__);
749-
validateSpec(spec);
750-
ComplexFormatter formatter = new ComplexFormatter(getCore(), validateAndPrepareForFloat(spec, getCore(), "complex"));
753+
private static Object doFormat(PComplex self, Spec spec, PythonCore core) {
754+
ComplexFormatter formatter = new ComplexFormatter(core, validateAndPrepareForFloat(spec, core, "complex"));
751755
formatter.format(self);
752756
return formatter.pad().getResult();
753757
}
754758

755-
@Fallback
756-
Object doOther(@SuppressWarnings("unused") Object self, Object format) {
757-
throw raise(TypeError, ErrorMessages.ARG_D_MUST_BE_S_NOT_P, "format()", 2, "str", format);
758-
}
759-
760759
private void validateSpec(Spec spec) {
761760
if (spec.getFill(' ') == '0') {
762761
throw raise(ValueError, ErrorMessages.ZERO_PADDING_NOT_ALLOWED_FOR_COMPLEX_FMT);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/floats/FloatBuiltins.java

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
package com.oracle.graal.python.builtins.objects.floats;
2727

2828
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.OverflowError;
29-
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError;
3029
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.ValueError;
3130
import static com.oracle.graal.python.nodes.SpecialMethodNames.__ABS__;
3231
import static com.oracle.graal.python.nodes.SpecialMethodNames.__ADD__;
@@ -81,13 +80,13 @@
8180
import com.oracle.graal.python.builtins.objects.PNotImplemented;
8281
import com.oracle.graal.python.builtins.objects.cext.CExtNodes.FromNativeSubclassNode;
8382
import com.oracle.graal.python.builtins.objects.cext.PythonNativeObject;
83+
import com.oracle.graal.python.builtins.objects.common.FormatNodeBase;
8484
import com.oracle.graal.python.builtins.objects.ints.PInt;
8585
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
8686
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
8787
import com.oracle.graal.python.nodes.ErrorMessages;
8888
import com.oracle.graal.python.nodes.SpecialMethodNames;
8989
import com.oracle.graal.python.nodes.call.special.LookupAndCallTernaryNode;
90-
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode;
9190
import com.oracle.graal.python.nodes.call.special.LookupAndCallVarargsNode;
9291
import com.oracle.graal.python.nodes.classes.IsSubtypeNode;
9392
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
@@ -97,7 +96,9 @@
9796
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
9897
import com.oracle.graal.python.nodes.object.GetClassNode;
9998
import com.oracle.graal.python.nodes.truffle.PythonArithmeticTypes;
99+
import com.oracle.graal.python.nodes.util.CastToJavaStringNode;
100100
import com.oracle.graal.python.runtime.PythonContext;
101+
import com.oracle.graal.python.runtime.PythonCore;
101102
import com.oracle.graal.python.runtime.exception.PythonErrorType;
102103
import com.oracle.graal.python.runtime.formatting.FloatFormatter;
103104
import com.oracle.graal.python.runtime.formatting.InternalFormat;
@@ -169,28 +170,34 @@ abstract static class ReprNode extends StrNode {
169170

170171
@Builtin(name = __FORMAT__, minNumOfPositionalArgs = 2)
171172
@GenerateNodeFactory
172-
@TypeSystemReference(PythonArithmeticTypes.class)
173-
abstract static class FormatNode extends PythonBinaryBuiltinNode {
173+
abstract static class FormatNode extends FormatNodeBase {
174+
@Specialization
175+
Object formatPF(VirtualFrame frame, PFloat self, Object formatStringObj,
176+
@Shared("cast") @Cached CastToJavaStringNode castToStringNode) {
177+
String formatString = castFormatString(formatStringObj, castToStringNode);
178+
if (formatString.isEmpty()) {
179+
return ensureStrCallNode().executeObject(frame, self);
180+
}
181+
return doFormat(self.getValue(), formatString, getCore());
182+
}
174183

175-
@Specialization(guards = "formatString.isEmpty()")
176-
Object emptyFormat(VirtualFrame frame, Object self, @SuppressWarnings("unused") String formatString,
177-
@Cached("create(__STR__)") LookupAndCallUnaryNode strCall) {
178-
return strCall.executeObject(frame, self);
184+
@Specialization
185+
Object formatD(VirtualFrame frame, double self, Object formatStringObj,
186+
@Shared("cast") @Cached CastToJavaStringNode castToStringNode) {
187+
String formatString = castFormatString(formatStringObj, castToStringNode);
188+
if (formatString.isEmpty()) {
189+
return ensureStrCallNode().executeObject(frame, self);
190+
}
191+
return doFormat(self, formatString, getCore());
179192
}
180193

181-
@Specialization(guards = "!formatString.isEmpty()")
182194
@TruffleBoundary
183-
String format(double self, String formatString) {
184-
InternalFormat.Spec spec = InternalFormat.fromText(getCore(), formatString, __FORMAT__);
185-
FloatFormatter formatter = new FloatFormatter(getCore(), validateAndPrepareForFloat(spec, getCore(), "float"));
195+
private String doFormat(double self, String formatString, PythonCore core) {
196+
InternalFormat.Spec spec = InternalFormat.fromText(core, formatString, __FORMAT__);
197+
FloatFormatter formatter = new FloatFormatter(core, validateAndPrepareForFloat(spec, getCore(), "float"));
186198
formatter.format(self);
187199
return formatter.pad().getResult();
188200
}
189-
190-
@Fallback
191-
String other(@SuppressWarnings("unused") Object self, Object formatString) {
192-
throw raise(TypeError, ErrorMessages.ARG_D_MUST_BE_S_NOT_P, "format()", 2, "str", formatString);
193-
}
194201
}
195202

196203
@Builtin(name = __ABS__, minNumOfPositionalArgs = 1)

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/IntBuiltins.java

Lines changed: 63 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
*/
4141
package com.oracle.graal.python.builtins.objects.ints;
4242

43-
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError;
4443
import static com.oracle.graal.python.nodes.SpecialMethodNames.__FORMAT__;
4544
import static com.oracle.graal.python.nodes.SpecialMethodNames.__LT__;
4645
import static com.oracle.graal.python.runtime.exception.PythonErrorType.OverflowError;
@@ -56,6 +55,8 @@
5655
import com.oracle.graal.python.builtins.CoreFunctions;
5756
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
5857
import com.oracle.graal.python.builtins.PythonBuiltins;
58+
import com.oracle.graal.python.builtins.modules.BuiltinConstructors;
59+
import com.oracle.graal.python.builtins.modules.BuiltinConstructorsFactory;
5960
import com.oracle.graal.python.builtins.modules.MathGuards;
6061
import com.oracle.graal.python.builtins.objects.PNone;
6162
import com.oracle.graal.python.builtins.objects.PNotImplemented;
@@ -68,6 +69,7 @@
6869
import com.oracle.graal.python.builtins.objects.cext.CExtNodes.FromNativeSubclassNode;
6970
import com.oracle.graal.python.builtins.objects.cext.PythonNativeObject;
7071
import com.oracle.graal.python.builtins.objects.cext.PythonNativeVoidPtr;
72+
import com.oracle.graal.python.builtins.objects.common.FormatNodeBase;
7173
import com.oracle.graal.python.builtins.objects.function.PArguments;
7274
import com.oracle.graal.python.builtins.objects.list.PList;
7375
import com.oracle.graal.python.builtins.objects.memoryview.PMemoryView;
@@ -90,6 +92,7 @@
9092
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
9193
import com.oracle.graal.python.nodes.object.GetClassNode;
9294
import com.oracle.graal.python.nodes.truffle.PythonArithmeticTypes;
95+
import com.oracle.graal.python.nodes.util.CastToJavaStringNode;
9396
import com.oracle.graal.python.runtime.PythonContext;
9497
import com.oracle.graal.python.runtime.PythonCore;
9598
import com.oracle.graal.python.runtime.exception.PythonErrorType;
@@ -2560,53 +2563,70 @@ abstract static class ReprNode extends StrNode {
25602563

25612564
@Builtin(name = __FORMAT__, minNumOfPositionalArgs = 2)
25622565
@GenerateNodeFactory
2563-
@TypeSystemReference(PythonArithmeticTypes.class)
2564-
abstract static class FormatNode extends PythonBinaryBuiltinNode {
2566+
abstract static class FormatNode extends FormatNodeBase {
2567+
@Child private BuiltinConstructors.FloatNode floatNode;
25652568

2566-
@Specialization(guards = "formatString.isEmpty()")
2567-
Object emptyFormat(VirtualFrame frame, Object self, @SuppressWarnings("unused") String formatString,
2568-
@Cached("create(__STR__)") LookupAndCallUnaryNode strCall) {
2569-
return strCall.executeObject(frame, self);
2569+
// We cannot use PythonArithmeticTypes, because for empty format string we need to call the
2570+
// boolean's __str__ and not int's __str__
2571+
@Specialization
2572+
Object formatB(VirtualFrame frame, boolean self, Object formatStringObj,
2573+
@Shared("cast") @Cached CastToJavaStringNode castToStringNode) {
2574+
String formatString = castFormatString(formatStringObj, castToStringNode);
2575+
if (formatString.isEmpty()) {
2576+
return ensureStrCallNode().executeObject(frame, self);
2577+
}
2578+
return doFormatInt(self ? 1 : 0, formatString);
25702579
}
25712580

2572-
@Specialization(guards = "!formatString.isEmpty()")
2573-
@TruffleBoundary
2574-
String formatI(int self, String formatString) {
2581+
@Specialization
2582+
Object formatI(VirtualFrame frame, int self, Object formatStringObj,
2583+
@Shared("cast") @Cached CastToJavaStringNode castToStringNode) {
2584+
String formatString = castFormatString(formatStringObj, castToStringNode);
2585+
if (formatString.isEmpty()) {
2586+
return ensureStrCallNode().executeObject(frame, self);
2587+
}
2588+
return doFormatInt(self, formatString);
2589+
}
2590+
2591+
private String doFormatInt(int self, String formatString) {
25752592
PythonCore core = getCore();
25762593
Spec spec = getSpec(formatString, core);
25772594
if (isDoubleSpec(spec)) {
25782595
return formatDouble(core, spec, self);
25792596
}
25802597
validateIntegerSpec(core, spec);
2581-
IntegerFormatter formatter = new IntegerFormatter(core, spec);
2582-
formatter.format(self);
2583-
return formatter.pad().getResult();
2598+
return formatInt(self, core, spec);
25842599
}
25852600

2586-
@Specialization(guards = "!formatString.isEmpty()")
2587-
String formatL(long self, String formatString) {
2588-
return formatPI(factory().createInt(self), formatString);
2601+
@Specialization
2602+
Object formatL(VirtualFrame frame, long self, Object formatString,
2603+
@Shared("cast") @Cached CastToJavaStringNode castToStringNode) {
2604+
return formatPI(frame, factory().createInt(self), formatString, castToStringNode);
25892605
}
25902606

2591-
@Specialization(guards = "!formatString.isEmpty()")
2592-
@TruffleBoundary
2593-
String formatPI(PInt self, String formatString) {
2607+
@Specialization
2608+
Object formatPI(VirtualFrame frame, PInt self, Object formatStringObj,
2609+
@Shared("cast") @Cached CastToJavaStringNode castToStringNode) {
2610+
String formatString = castFormatString(formatStringObj, castToStringNode);
2611+
if (formatString.isEmpty()) {
2612+
return ensureStrCallNode().executeObject(frame, self);
2613+
}
25942614
PythonCore core = getCore();
25952615
Spec spec = getSpec(formatString, core);
25962616
if (isDoubleSpec(spec)) {
2597-
// Note: this should really call PyNumber_Float
2598-
double doubleVal = PythonObjectLibrary.getUncached().asJavaDouble(self);
2599-
return formatDouble(core, spec, doubleVal);
2617+
return formatDouble(core, spec, asDouble(frame, self));
26002618
}
26012619
validateIntegerSpec(core, spec);
2602-
IntegerFormatter formatter = new IntegerFormatter(core, spec);
2603-
formatter.format(self.getValue());
2604-
return formatter.pad().getResult();
2620+
return formatPInt(self, core, spec);
26052621
}
26062622

2607-
@Fallback
2608-
Object doOther(@SuppressWarnings("unused") Object self, Object format) {
2609-
throw raise(TypeError, ErrorMessages.ARG_D_MUST_BE_S_NOT_P, "format()", 2, "str", format);
2623+
private double asDouble(VirtualFrame frame, Object self) {
2624+
if (floatNode == null) {
2625+
CompilerDirectives.transferToInterpreterAndInvalidate();
2626+
floatNode = insert(BuiltinConstructorsFactory.FloatNodeFactory.create());
2627+
}
2628+
// We cannot use asJavaDouble, because this should have the semantics of PyNumber_Float
2629+
return (double) floatNode.executeWith(frame, PythonBuiltinClassType.PFloat, self);
26102630
}
26112631

26122632
private static Spec getSpec(String formatString, PythonCore core) {
@@ -2620,12 +2640,27 @@ private static boolean isDoubleSpec(Spec spec) {
26202640
spec.type == 'G' || spec.type == '%';
26212641
}
26222642

2643+
@TruffleBoundary
26232644
private static String formatDouble(PythonCore core, Spec spec, double value) {
26242645
FloatFormatter formatter = new FloatFormatter(core, spec);
26252646
formatter.format(value);
26262647
return formatter.pad().getResult();
26272648
}
26282649

2650+
@TruffleBoundary
2651+
private static String formatInt(int self, PythonCore core, Spec spec) {
2652+
IntegerFormatter formatter = new IntegerFormatter(core, spec);
2653+
formatter.format(self);
2654+
return formatter.pad().getResult();
2655+
}
2656+
2657+
@TruffleBoundary
2658+
private static String formatPInt(PInt self, PythonCore core, Spec spec) {
2659+
IntegerFormatter formatter = new IntegerFormatter(core, spec);
2660+
formatter.format(self.getValue());
2661+
return formatter.pad().getResult();
2662+
}
2663+
26292664
private static void validateIntegerSpec(PythonCore core, Spec spec) {
26302665
if (Spec.specified(spec.precision)) {
26312666
throw core.raise(ValueError, ErrorMessages.PRECISION_NOT_ALLOWED_FOR_INT);

0 commit comments

Comments
 (0)