Skip to content

Commit

Permalink
Fix buggy if (a || b) in rich comparison by storing boolean
Browse files Browse the repository at this point in the history
  • Loading branch information
cflee committed Mar 6, 2017
1 parent 53dd947 commit 2a084ed
Showing 1 changed file with 113 additions and 137 deletions.
250 changes: 113 additions & 137 deletions voc/python/ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -1750,15 +1750,7 @@ def visit_Compare(self, node):
ASTORE_name('#compare-x'),
)

# result variable
self.context.add_opcodes(
JavaOpcodes.GETSTATIC(
'org/python/types/NotImplementedType',
'NOT_IMPLEMENTED',
'Lorg/python/Object;'
),
)

# do rhs checks first
self.context.add_opcodes(
# first round of checks, x.getClass() == y.getClass()?
ALOAD_name('#compare-x'),
Expand Down Expand Up @@ -1791,20 +1783,20 @@ def visit_Compare(self, node):
'isInstance',
'(Ljava/lang/Object;)Z'
),
),
)
self.context.add_opcodes(
IF([], JavaOpcodes.IFEQ),
)
self.context.add_opcodes(
# result = y.__reflect_oper__(x)
JavaOpcodes.POP(),
ALOAD_name('#compare-y'),
ALOAD_name('#compare-x'),
JavaOpcodes.INVOKEINTERFACE(
'org/python/Object',
reflect_oper,
'(Lorg/python/Object;)Lorg/python/Object;'
),
JavaOpcodes.ICONST_1(),
ISTORE_name('#compare-rhs'),
)
self.context.add_opcodes(
ELSE(),
)
self.context.add_opcodes(
JavaOpcodes.ICONST_0(),
ISTORE_name('#compare-rhs'),
)
self.context.add_opcodes(
END_IF(),
Expand All @@ -1813,6 +1805,37 @@ def visit_Compare(self, node):
END_IF(),
)

# result variable
self.context.add_opcodes(
JavaOpcodes.GETSTATIC(
'org/python/types/NotImplementedType',
'NOT_IMPLEMENTED',
'Lorg/python/Object;'
),
)

# if rhs, then do reflected op first
self.context.add_opcodes(
ILOAD_name('#compare-rhs'),
)
self.context.add_opcodes(
IF([], JavaOpcodes.IFEQ),
)
self.context.add_opcodes(
# result = y.__reflect_oper__(x)
JavaOpcodes.POP(),
ALOAD_name('#compare-y'),
ALOAD_name('#compare-x'),
JavaOpcodes.INVOKEINTERFACE(
'org/python/Object',
reflect_oper,
'(Lorg/python/Object;)Lorg/python/Object;'
),
)
self.context.add_opcodes(
END_IF(),
)

# second round, result == NOT_IMPLEMENTED?
self.context.add_opcodes(
JavaOpcodes.DUP(),
Expand Down Expand Up @@ -1850,183 +1873,136 @@ def visit_Compare(self, node):
IF([], JavaOpcodes.IF_ACMPNE),
)
self.context.add_opcodes(
ALOAD_name('#compare-x'),
JavaOpcodes.INVOKEVIRTUAL(
'java/lang/Object',
'getClass',
'()Ljava/lang/Class;'
),
ALOAD_name('#compare-y'),
JavaOpcodes.INVOKEVIRTUAL(
'java/lang/Object',
'getClass',
'()Ljava/lang/Class;'
),
ILOAD_name('#compare-rhs'),
)
self.context.add_opcodes(
# later we will modify the target of this if jump
IF([], JavaOpcodes.IF_ACMPEQ),
IF([], JavaOpcodes.IFNE),
)
self.context.add_opcodes(
# y.getClass().isInstance(x)?
# result = y.__reflect_oper__(x)
JavaOpcodes.POP(),
ALOAD_name('#compare-y'),
JavaOpcodes.INVOKEVIRTUAL(
'java/lang/Object',
'getClass',
'()Ljava/lang/Class;'
),
ALOAD_name('#compare-x'),
JavaOpcodes.INVOKEVIRTUAL(
'java/lang/Class',
'isInstance',
'(Ljava/lang/Object;)Z'
JavaOpcodes.INVOKEINTERFACE(
'org/python/Object',
reflect_oper,
'(Lorg/python/Object;)Lorg/python/Object;'
),
)
self.context.add_opcodes(
IF([], JavaOpcodes.IFNE),
)
# assign this to a variable to set as jump target later
pop_landing = JavaOpcodes.POP()
self.context.next_resolve_list.append((pop_landing, OpcodePosition.START))
self.context.add_opcodes(
# result = y.__reflect_oper__(x)
# we want the if jump to land here instead
pop_landing,
ALOAD_name('#compare-y'),
ALOAD_name('#compare-x'),
JavaOpcodes.INVOKEINTERFACE(
'org/python/Object',
reflect_oper,
'(Lorg/python/Object;)Lorg/python/Object;'
),
)
self.context.add_opcodes(
END_IF(),
END_IF(),
)
self.context.add_opcodes(
# fourth round, check again
JavaOpcodes.DUP(),
JavaOpcodes.GETSTATIC(
'org/python/types/NotImplementedType',
'NOT_IMPLEMENTED',
'Lorg/python/Object;'
),
# fourth round, check again
JavaOpcodes.DUP(),
JavaOpcodes.GETSTATIC(
'org/python/types/NotImplementedType',
'NOT_IMPLEMENTED',
'Lorg/python/Object;'
),
)
self.context.add_opcodes(
IF([], JavaOpcodes.IF_ACMPNE),
IF([], JavaOpcodes.IF_ACMPNE),
)
if isinstance(node.ops[0], (ast.Eq, ast.NotEq)):
# for == and !=, default to false and true respectively
# instead of throwing TypeError
if isinstance(node.ops[0], ast.Eq):
self.context.add_opcodes(
JavaOpcodes.POP(),
java.New('org/python/types/Bool'),
JavaOpcodes.ICONST_0(),
java.Init('org/python/types/Bool', 'Z'),
JavaOpcodes.POP(),
java.New('org/python/types/Bool'),
JavaOpcodes.ICONST_0(),
java.Init('org/python/types/Bool', 'Z'),
)
else:
self.context.add_opcodes(
JavaOpcodes.POP(),
java.New('org/python/types/Bool'),
JavaOpcodes.ICONST_1(),
java.Init('org/python/types/Bool', 'Z'),
JavaOpcodes.POP(),
java.New('org/python/types/Bool'),
JavaOpcodes.ICONST_1(),
java.Init('org/python/types/Bool', 'Z'),
)
else:
self.context.add_opcodes(
# still cannot, make TypeError
JavaOpcodes.NEW('org/python/exceptions/TypeError'),
JavaOpcodes.DUP(),
# still cannot, make TypeError
JavaOpcodes.NEW('org/python/exceptions/TypeError'),
JavaOpcodes.DUP(),
)
# different message
if sys.hexversion < 0x3060000:
self.context.add_opcodes(
JavaOpcodes.LDC_W('unorderable types: %s() %s %s()'),
JavaOpcodes.LDC_W('unorderable types: %s() %s %s()'),
)
else:
self.context.add_opcodes(
JavaOpcodes.LDC_W(
"'%s' not supported between instances of '%s' and '%s'"
),
JavaOpcodes.LDC_W(
"'%s' not supported between instances of '%s' and '%s'"
),
)
self.context.add_opcodes(
JavaOpcodes.ICONST_3(),
JavaOpcodes.ANEWARRAY('java/lang/Object'),
JavaOpcodes.DUP(),
JavaOpcodes.ICONST_3(),
JavaOpcodes.ANEWARRAY('java/lang/Object'),
JavaOpcodes.DUP(),
)
# different order of params for different message
if sys.hexversion < 0x3060000:
self.context.add_opcodes(
JavaOpcodes.ICONST_0(),
JavaOpcodes.ICONST_0(),
)
else:
self.context.add_opcodes(
JavaOpcodes.ICONST_1(),
JavaOpcodes.ICONST_1(),
)
self.context.add_opcodes(
ALOAD_name('#compare-x'),
JavaOpcodes.INVOKEINTERFACE(
'org/python/Object',
'typeName',
'()Ljava/lang/String;'
),
JavaOpcodes.AASTORE(),
JavaOpcodes.DUP(),
ALOAD_name('#compare-x'),
JavaOpcodes.INVOKEINTERFACE(
'org/python/Object',
'typeName',
'()Ljava/lang/String;'
),
JavaOpcodes.AASTORE(),
JavaOpcodes.DUP(),
)
# different order of params for different message
if sys.hexversion < 0x3060000:
self.context.add_opcodes(
JavaOpcodes.ICONST_1(),
JavaOpcodes.ICONST_1(),
)
else:
self.context.add_opcodes(
JavaOpcodes.ICONST_0(),
JavaOpcodes.ICONST_0(),
)
self.context.add_opcodes(
JavaOpcodes.LDC_W(oper_symbol),
JavaOpcodes.AASTORE(),
JavaOpcodes.DUP(),
JavaOpcodes.ICONST_2(),
ALOAD_name('#compare-y'),
JavaOpcodes.INVOKEINTERFACE(
'org/python/Object',
'typeName',
'()Ljava/lang/String;'
),
JavaOpcodes.AASTORE(),
JavaOpcodes.INVOKESTATIC(
'java/lang/String',
'format',
'(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;'
),
JavaOpcodes.INVOKESPECIAL(
'org/python/exceptions/TypeError',
'<init>',
'(Ljava/lang/String;)V'
),
JavaOpcodes.ATHROW(),
JavaOpcodes.LDC_W(oper_symbol),
JavaOpcodes.AASTORE(),
JavaOpcodes.DUP(),
JavaOpcodes.ICONST_2(),
ALOAD_name('#compare-y'),
JavaOpcodes.INVOKEINTERFACE(
'org/python/Object',
'typeName',
'()Ljava/lang/String;'
),
JavaOpcodes.AASTORE(),
JavaOpcodes.INVOKESTATIC(
'java/lang/String',
'format',
'(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;'
),
JavaOpcodes.INVOKESPECIAL(
'org/python/exceptions/TypeError',
'<init>',
'(Ljava/lang/String;)V'
),
JavaOpcodes.ATHROW(),
)
self.context.add_opcodes(
END_IF(),
)
self.context.add_opcodes(
# END_IF(),
)
# do some magic to implement
# if (x.getClass() == y.getClass() || !y.getClass().isInstance(x))
# for the third-last if block (context.blocks[-3]),
# set the jump target (when ==) to the POP before y.__reflect_oper__(x)
block_outer = self.context.blocks[-3]
print("MODIFYING %s 0x%x" % (block_outer.if_op, id(block_outer.if_op)))
jump(block_outer.if_op, self.context, pop_landing, OpcodePosition.START)
self.context.add_opcodes(
END_IF(),
)
self.context.add_opcodes(
END_IF(), # third round's result == NOT_IMPLEMENTED
END_IF(),
)
self.context.add_opcodes(
END_IF(), # second round's result == NOT_IMPLEMENTED
END_IF(),
)
else:
raise NotImplementedError("Don't know how to resolve multiple operators")
Expand Down

0 comments on commit 2a084ed

Please sign in to comment.