|
228 | 228 | import com.oracle.graal.python.nodes.classes.IsSubtypeNodeGen;
|
229 | 229 | import com.oracle.graal.python.nodes.expression.BinaryArithmetic;
|
230 | 230 | import com.oracle.graal.python.nodes.expression.BinaryComparisonNode;
|
| 231 | +import com.oracle.graal.python.nodes.expression.InplaceArithmetic; |
| 232 | +import com.oracle.graal.python.nodes.expression.LookupAndCallInplaceNode; |
231 | 233 | import com.oracle.graal.python.nodes.frame.GetCurrentFrameRef;
|
232 | 234 | import com.oracle.graal.python.nodes.function.FunctionRootNode;
|
233 | 235 | import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
|
@@ -4131,7 +4133,7 @@ static Object doObject(VirtualFrame frame, Object left, Object right, @SuppressW
|
4131 | 4133 | return toSulongNode.execute(result);
|
4132 | 4134 | }
|
4133 | 4135 |
|
4134 |
| - private static Object extract(PrimitiveNativeWrapper wrapper) { |
| 4136 | + static Object extract(PrimitiveNativeWrapper wrapper) { |
4135 | 4137 | if (wrapper.isIntLike()) {
|
4136 | 4138 | return wrapper.getLong();
|
4137 | 4139 | }
|
@@ -4183,4 +4185,100 @@ private static BinaryArithmetic getBinaryArithmetic(int op) {
|
4183 | 4185 | }
|
4184 | 4186 |
|
4185 | 4187 | }
|
| 4188 | + |
| 4189 | + @Builtin(name = "PyNumber_InPlaceBinOp", minNumOfPositionalArgs = 3) |
| 4190 | + @GenerateNodeFactory |
| 4191 | + abstract static class PyNumberInPlaceBinOp extends PythonTernaryBuiltinNode { |
| 4192 | + static int MAX_CACHE_SIZE = InplaceArithmetic.values().length; |
| 4193 | + |
| 4194 | + @Specialization(guards = {"cachedOp == op", "left.isIntLike()", "right.isIntLike()"}, limit = "MAX_CACHE_SIZE") |
| 4195 | + static Object doIntLikePrimitiveWrapper(VirtualFrame frame, PrimitiveNativeWrapper left, PrimitiveNativeWrapper right, @SuppressWarnings("unused") int op, |
| 4196 | + @Cached("op") @SuppressWarnings("unused") int cachedOp, |
| 4197 | + @Cached("createCallNode(op)") LookupAndCallInplaceNode callNode, |
| 4198 | + @Cached ToNewRefNode toSulongNode, |
| 4199 | + @Cached TransformExceptionToNativeNode transformExceptionToNativeNode, |
| 4200 | + @Cached GetNativeNullNode getNativeNullNode) { |
| 4201 | + try { |
| 4202 | + return toSulongNode.execute(callNode.execute(frame, left.getLong(), right.getLong())); |
| 4203 | + } catch (PException e) { |
| 4204 | + transformExceptionToNativeNode.execute(e); |
| 4205 | + return toSulongNode.execute(getNativeNullNode.execute()); |
| 4206 | + } |
| 4207 | + } |
| 4208 | + |
| 4209 | + @Specialization(guards = "cachedOp == op", limit = "MAX_CACHE_SIZE", replaces = "doIntLikePrimitiveWrapper") |
| 4210 | + static Object doObject(VirtualFrame frame, Object left, Object right, @SuppressWarnings("unused") int op, |
| 4211 | + @Cached AsPythonObjectNode leftToJava, |
| 4212 | + @Cached AsPythonObjectNode rightToJava, |
| 4213 | + @Cached("op") @SuppressWarnings("unused") int cachedOp, |
| 4214 | + @Cached("createCallNode(op)") LookupAndCallInplaceNode callNode, |
| 4215 | + @Cached ToNewRefNode toSulongNode, |
| 4216 | + @Cached TransformExceptionToNativeNode transformExceptionToNativeNode, |
| 4217 | + @Cached GetNativeNullNode getNativeNullNode) { |
| 4218 | + // still try to avoid expensive materialization of primitives |
| 4219 | + Object result; |
| 4220 | + try { |
| 4221 | + if (left instanceof PrimitiveNativeWrapper || right instanceof PrimitiveNativeWrapper) { |
| 4222 | + Object leftValue; |
| 4223 | + Object rightValue; |
| 4224 | + if (left instanceof PrimitiveNativeWrapper) { |
| 4225 | + leftValue = PyNumberBinOp.extract((PrimitiveNativeWrapper) left); |
| 4226 | + } else { |
| 4227 | + leftValue = leftToJava.execute(left); |
| 4228 | + } |
| 4229 | + if (right instanceof PrimitiveNativeWrapper) { |
| 4230 | + rightValue = PyNumberBinOp.extract((PrimitiveNativeWrapper) right); |
| 4231 | + } else { |
| 4232 | + rightValue = rightToJava.execute(right); |
| 4233 | + } |
| 4234 | + result = callNode.execute(frame, leftValue, rightValue); |
| 4235 | + } else { |
| 4236 | + result = callNode.execute(frame, leftToJava.execute(left), rightToJava.execute(right)); |
| 4237 | + } |
| 4238 | + } catch (PException e) { |
| 4239 | + transformExceptionToNativeNode.execute(e); |
| 4240 | + result = getNativeNullNode.execute(); |
| 4241 | + } |
| 4242 | + return toSulongNode.execute(result); |
| 4243 | + } |
| 4244 | + |
| 4245 | + /** |
| 4246 | + * This needs to stay in sync with {@code abstract.c: enum e_binop}. |
| 4247 | + */ |
| 4248 | + static LookupAndCallInplaceNode createCallNode(int op) { |
| 4249 | + return getInplaceArithmetic(op).create(); |
| 4250 | + } |
| 4251 | + |
| 4252 | + private static InplaceArithmetic getInplaceArithmetic(int op) { |
| 4253 | + switch (op) { |
| 4254 | + case 0: |
| 4255 | + return InplaceArithmetic.IAdd; |
| 4256 | + case 1: |
| 4257 | + return InplaceArithmetic.ISub; |
| 4258 | + case 2: |
| 4259 | + return InplaceArithmetic.IMul; |
| 4260 | + case 3: |
| 4261 | + return InplaceArithmetic.ITrueDiv; |
| 4262 | + case 4: |
| 4263 | + return InplaceArithmetic.ILShift; |
| 4264 | + case 5: |
| 4265 | + return InplaceArithmetic.IRShift; |
| 4266 | + case 6: |
| 4267 | + return InplaceArithmetic.IOr; |
| 4268 | + case 7: |
| 4269 | + return InplaceArithmetic.IAnd; |
| 4270 | + case 8: |
| 4271 | + return InplaceArithmetic.IXor; |
| 4272 | + case 9: |
| 4273 | + return InplaceArithmetic.IFloorDiv; |
| 4274 | + case 10: |
| 4275 | + return InplaceArithmetic.IMod; |
| 4276 | + case 12: |
| 4277 | + return InplaceArithmetic.IMatMul; |
| 4278 | + default: |
| 4279 | + throw CompilerDirectives.shouldNotReachHere("invalid binary operator"); |
| 4280 | + } |
| 4281 | + } |
| 4282 | + |
| 4283 | + } |
4186 | 4284 | }
|
0 commit comments