|
38 | 38 | */ |
39 | 39 | package com.oracle.graal.python.runtime.interop; |
40 | 40 |
|
| 41 | +import static com.oracle.graal.python.nodes.SpecialMethodNames.__GETITEM__; |
| 42 | + |
41 | 43 | import java.util.Arrays; |
42 | 44 |
|
43 | 45 | import com.oracle.graal.python.builtins.modules.BuiltinFunctions; |
44 | 46 | import com.oracle.graal.python.builtins.modules.BuiltinFunctionsFactory; |
45 | 47 | import com.oracle.graal.python.builtins.objects.PNone; |
46 | 48 | import com.oracle.graal.python.builtins.objects.PythonAbstractObject; |
47 | 49 | import com.oracle.graal.python.builtins.objects.cext.PythonNativeObject; |
| 50 | +import com.oracle.graal.python.builtins.objects.common.PHashingCollection; |
48 | 51 | import com.oracle.graal.python.builtins.objects.function.PKeyword; |
49 | 52 | import com.oracle.graal.python.builtins.objects.list.PList; |
50 | 53 | import com.oracle.graal.python.builtins.objects.object.PythonBuiltinObject; |
|
60 | 63 | import com.oracle.graal.python.nodes.attributes.LookupInheritedAttributeNode; |
61 | 64 | import com.oracle.graal.python.nodes.attributes.SetAttributeNode; |
62 | 65 | import com.oracle.graal.python.nodes.call.CallDispatchNode; |
| 66 | +import com.oracle.graal.python.nodes.call.special.LookupAndCallBinaryNode; |
63 | 67 | import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode; |
64 | 68 | import com.oracle.graal.python.nodes.datamodel.IsCallableNode; |
65 | 69 | import com.oracle.graal.python.nodes.datamodel.IsMappingNode; |
@@ -444,19 +448,90 @@ public Object access(Object object) { |
444 | 448 |
|
445 | 449 | @Resolve(message = "HAS_SIZE") |
446 | 450 | abstract static class PForeignHasSizeNode extends Node { |
| 451 | + @Child private IsSequenceNode isSequenceNode; |
| 452 | + @Child private IsMappingNode isMappingNode; |
| 453 | + @Child private BuiltinFunctions.LenNode lenNode; |
| 454 | + @Child private PTypeUnboxNode unboxNode; |
| 455 | + @Child private LookupAndCallBinaryNode callGetItemNode; |
| 456 | + |
| 457 | + private final ValueProfile profile = ValueProfile.createClassProfile(); |
| 458 | + |
447 | 459 | public Object access(Object object) { |
448 | | - return object instanceof PSequence; |
| 460 | + Object profiled = profile.profile(object); |
| 461 | + // A sequence object always has a size even if there is no '__len__' attribute. This is, |
| 462 | + // e.g., the case for 'array'. |
| 463 | + if (profiled instanceof PSequence) { |
| 464 | + return true; |
| 465 | + } |
| 466 | + if (profiled instanceof PHashingCollection) { |
| 467 | + return false; |
| 468 | + } |
| 469 | + if (getIsSequenceNode().execute(profiled) && !getIsMappingNode().execute(profiled)) { |
| 470 | + // also try to access using an integer index |
| 471 | + int len = (int) getUnboxNode().execute(getLenNode().executeWith(profiled)); |
| 472 | + if (len > 0) { |
| 473 | + try { |
| 474 | + getCallGetItemNode().executeObject(profiled, 0); |
| 475 | + return true; |
| 476 | + } catch (PException e) { |
| 477 | + return false; |
| 478 | + } |
| 479 | + } |
| 480 | + return true; |
| 481 | + } |
| 482 | + return false; |
| 483 | + } |
| 484 | + |
| 485 | + private BuiltinFunctions.LenNode getLenNode() { |
| 486 | + if (lenNode == null) { |
| 487 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 488 | + lenNode = insert(BuiltinFunctionsFactory.LenNodeFactory.create()); |
| 489 | + } |
| 490 | + return lenNode; |
| 491 | + } |
| 492 | + |
| 493 | + private PTypeUnboxNode getUnboxNode() { |
| 494 | + if (unboxNode == null) { |
| 495 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 496 | + unboxNode = insert(PTypeUnboxNode.create()); |
| 497 | + } |
| 498 | + return unboxNode; |
| 499 | + } |
| 500 | + |
| 501 | + private LookupAndCallBinaryNode getCallGetItemNode() { |
| 502 | + if (callGetItemNode == null) { |
| 503 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 504 | + callGetItemNode = insert(LookupAndCallBinaryNode.create(__GETITEM__)); |
| 505 | + } |
| 506 | + return callGetItemNode; |
| 507 | + } |
| 508 | + |
| 509 | + private IsSequenceNode getIsSequenceNode() { |
| 510 | + if (isSequenceNode == null) { |
| 511 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 512 | + isSequenceNode = insert(IsSequenceNode.create()); |
| 513 | + } |
| 514 | + return isSequenceNode; |
| 515 | + } |
| 516 | + |
| 517 | + private IsMappingNode getIsMappingNode() { |
| 518 | + if (isMappingNode == null) { |
| 519 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 520 | + isMappingNode = insert(IsMappingNode.create()); |
| 521 | + } |
| 522 | + return isMappingNode; |
449 | 523 | } |
450 | 524 | } |
451 | 525 |
|
452 | 526 | @Resolve(message = "GET_SIZE") |
453 | 527 | abstract static class PForeignGetSizeNode extends Node { |
454 | 528 | @Child IsSequenceNode isSeq = IsSequenceNode.create(); |
455 | 529 | @Child private BuiltinFunctions.LenNode lenNode = BuiltinFunctionsFactory.LenNodeFactory.create(); |
| 530 | + @Child private PTypeUnboxNode unboxNode = PTypeUnboxNode.create(); |
456 | 531 |
|
457 | 532 | public Object access(Object object) { |
458 | 533 | if (isSeq.execute(object)) { |
459 | | - return lenNode.executeWith(object); |
| 534 | + return unboxNode.execute(lenNode.executeWith(object)); |
460 | 535 | } |
461 | 536 | throw UnsupportedMessageException.raise(Message.GET_SIZE); |
462 | 537 | } |
|
0 commit comments