19
19
#include < util/prefix.h>
20
20
#include < util/std_expr.h>
21
21
#include < util/string_constant.h>
22
+ #include < util/optional.h>
22
23
23
24
#include " java_bytecode_parse_tree.h"
24
25
#include " java_types.h"
@@ -47,12 +48,10 @@ class java_bytecode_parsert:public parsert
47
48
typedef java_bytecode_parse_treet::instructiont instructiont;
48
49
typedef java_bytecode_parse_treet::annotationt annotationt;
49
50
typedef java_bytecode_parse_treet::annotationst annotationst;
50
- typedef java_bytecode_parse_treet::classt::lambda_method_handlet
51
- lambda_method_handlet;
52
51
typedef java_bytecode_parse_treet::classt::method_handle_typet
53
52
method_handle_typet;
54
- typedef java_bytecode_parse_treet::classt::lambda_method_handlest
55
- lambda_method_handlest ;
53
+ typedef java_bytecode_parse_treet::classt::lambda_method_handlet
54
+ lambda_method_handlet ;
56
55
typedef java_bytecode_parse_treet::classt::lambda_method_handle_mapt
57
56
lambda_method_handle_mapt;
58
57
@@ -134,7 +133,7 @@ class java_bytecode_parsert:public parsert
134
133
void get_class_refs ();
135
134
void get_class_refs_rec (const typet &);
136
135
void parse_local_variable_type_table (methodt &method);
137
- void parse_method_handle (const pool_entryt &, lambda_method_handlet &);
136
+ optionalt<lambda_method_handlet> parse_method_handle (const pool_entryt &);
138
137
139
138
void skip_bytes (std::size_t bytes)
140
139
{
@@ -1417,6 +1416,8 @@ void java_bytecode_parsert::rclass_attribute(classt &parsed_class)
1417
1416
}
1418
1417
else if (attribute_name == " BootstrapMethods" )
1419
1418
{
1419
+ // for this attribute
1420
+ // cf. https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.23
1420
1421
INVARIANT (
1421
1422
!parsed_class.attribute_bootstrapmethods_read ,
1422
1423
" only one BootstrapMethods argument is allowed in a class file" );
@@ -1430,15 +1431,15 @@ void java_bytecode_parsert::rclass_attribute(classt &parsed_class)
1430
1431
const pool_entryt &entry = pool_entry (bootstrap_methodhandle_ref);
1431
1432
u2 num_bootstrap_arguments = read_u2 ();
1432
1433
1433
- lambda_method_handlet handle;
1434
+ optionalt< lambda_method_handlet> handle = parse_method_handle (entry) ;
1434
1435
debug () << " INFO: parse BootstrapMethod handle "
1435
- << num_bootstrap_arguments << " #args"
1436
- << eom;
1437
- parse_method_handle (entry, handle);
1436
+ << num_bootstrap_arguments << " #args" << eom;
1437
+
1438
1438
if (
1439
- handle.handle_type ==
1440
- method_handle_typet::BOOTSTRAP_METHOD_HANDLE_ALT ||
1441
- handle.handle_type == method_handle_typet::BOOTSTRAP_METHOD_HANDLE)
1439
+ handle.has_value () &&
1440
+ (handle->handle_type ==
1441
+ method_handle_typet::BOOTSTRAP_METHOD_HANDLE_ALT ||
1442
+ handle->handle_type == method_handle_typet::BOOTSTRAP_METHOD_HANDLE))
1442
1443
{
1443
1444
// try parsing bootstrap method handle
1444
1445
if (num_bootstrap_arguments >= 3 )
@@ -1485,8 +1486,7 @@ void java_bytecode_parsert::rclass_attribute(classt &parsed_class)
1485
1486
}
1486
1487
if (!recognized)
1487
1488
{
1488
- debug () << " format of BootstrapMethods entry not recognized"
1489
- << eom;
1489
+ debug () << " format of BootstrapMethods entry not recognized" << eom;
1490
1490
return ;
1491
1491
}
1492
1492
@@ -1496,39 +1496,40 @@ void java_bytecode_parsert::rclass_attribute(classt &parsed_class)
1496
1496
pool_entry (argument_index2);
1497
1497
const pool_entryt &method_type_argument = pool_entry (argument_index3);
1498
1498
1499
- if (!(interface_type_argument.tag == CONSTANT_MethodType &&
1500
- method_handle_argument.tag == CONSTANT_MethodHandle &&
1501
- method_type_argument.tag == CONSTANT_MethodType))
1499
+ if (
1500
+ !(interface_type_argument.tag == CONSTANT_MethodType &&
1501
+ method_handle_argument.tag == CONSTANT_MethodHandle &&
1502
+ method_type_argument.tag == CONSTANT_MethodType))
1502
1503
return ;
1503
1504
1504
- lambda_method_handlet lambda_method_handle;
1505
1505
debug () << " INFO: parse lambda handle" << eom;
1506
- parse_method_handle (method_handle_argument, lambda_method_handle);
1506
+ optionalt<lambda_method_handlet> lambda_method_handle =
1507
+ parse_method_handle (method_handle_argument);
1508
+
1507
1509
if (
1508
- lambda_method_handle.handle_type !=
1509
- method_handle_typet::LAMBDA_METHOD_HANDLE)
1510
+ lambda_method_handle.has_value () &&
1511
+ lambda_method_handle->handle_type !=
1512
+ method_handle_typet::LAMBDA_METHOD_HANDLE)
1510
1513
{
1511
- lambda_method_handlet empty_handle;
1512
- parsed_class.lambda_method_handle_map [parsed_class.name ].push_back (
1513
- empty_handle);
1514
1514
error () << " ERROR: could not parse lambda function method handle"
1515
1515
<< eom;
1516
1516
}
1517
1517
else
1518
1518
{
1519
- lambda_method_handle.interface_type = pool_entry (interface_type_argument.ref1 ).s ;
1520
- lambda_method_handle.method_type = pool_entry (method_type_argument.ref1 ).s ;
1521
- parsed_class.lambda_method_handle_map [parsed_class.name ].push_back (
1522
- lambda_method_handle);
1523
- debug ()
1524
- << " lambda function reference "
1525
- << id2string (lambda_method_handle.lambda_method_name ) << " in class \" "
1526
- << parsed_class.name << " \" "
1527
- << " \n interface type is "
1528
- << id2string (pool_entry (interface_type_argument.ref1 ).s )
1529
- << " \n method type is "
1530
- << id2string (pool_entry (method_type_argument.ref1 ).s )
1531
- << eom;
1519
+ lambda_method_handle->interface_type =
1520
+ pool_entry (interface_type_argument.ref1 ).s ;
1521
+ lambda_method_handle->method_type =
1522
+ pool_entry (method_type_argument.ref1 ).s ;
1523
+ debug () << " lambda function reference "
1524
+ << id2string (lambda_method_handle->lambda_method_name )
1525
+ << " in class \" " << parsed_class.name << " \" "
1526
+ << " \n interface type is "
1527
+ << id2string (pool_entry (interface_type_argument.ref1 ).s )
1528
+ << " \n method type is "
1529
+ << id2string (pool_entry (method_type_argument.ref1 ).s )
1530
+ << eom;
1531
+ parsed_class.lambda_method_handle_map [{parsed_class.name , i}] =
1532
+ *lambda_method_handle;
1532
1533
}
1533
1534
}
1534
1535
else
@@ -1541,9 +1542,6 @@ void java_bytecode_parsert::rclass_attribute(classt &parsed_class)
1541
1542
}
1542
1543
else
1543
1544
{
1544
- lambda_method_handlet empty_handle;
1545
- parsed_class.lambda_method_handle_map [parsed_class.name ].push_back (
1546
- empty_handle);
1547
1545
// skip bytes to align for next entry
1548
1546
for (size_t i = 0 ; i < num_bootstrap_arguments; i++)
1549
1547
read_u2 ();
@@ -1683,15 +1681,15 @@ void java_bytecode_parsert::parse_local_variable_type_table(methodt &method)
1683
1681
// / Read method handle pointed to from constant pool entry at index, return type
1684
1682
// / of method handle and name if lambda function is found.
1685
1683
// / \param entry: the constant pool entry of the methodhandle_info structure
1686
- // / \param[out] handle: the method_handle type of the methodhandle_structure,
1687
- // / either for a recognized bootstrap method, for a lambda function or unknown
1688
- void java_bytecode_parsert::parse_method_handle (
1689
- const pool_entryt &entry,
1690
- lambda_method_handlet &handle)
1684
+ // / \returns: the method_handle type of the methodhandle_structure,
1685
+ // / either for a recognized bootstrap method or for a lambda function
1686
+ optionalt<java_bytecode_parsert::lambda_method_handlet>
1687
+ java_bytecode_parsert::parse_method_handle (const pool_entryt &entry)
1691
1688
{
1692
1689
INVARIANT (
1693
1690
entry.tag == CONSTANT_MethodHandle,
1694
1691
" constant pool entry must be a MethodHandle" );
1692
+ lambda_method_handlet lambda_method_handle;
1695
1693
const auto &ref_entry = pool_entry (entry.ref2 );
1696
1694
INVARIANT (
1697
1695
(entry.ref1 > 0 && entry.ref1 < 10 ),
@@ -1701,30 +1699,43 @@ void java_bytecode_parsert::parse_method_handle(
1701
1699
const auto &nameandtype_entry = pool_entry (ref_entry.ref2 );
1702
1700
1703
1701
const std::string method_name =
1704
- id2string (pool_entry (class_entry.ref1 ).s ) + " ."
1705
- + id2string (pool_entry (nameandtype_entry.ref1 ).s )
1706
- + id2string (pool_entry (nameandtype_entry.ref2 ).s );
1702
+ id2string (pool_entry (class_entry.ref1 ).s ) + " ." +
1703
+ id2string (pool_entry (nameandtype_entry.ref1 ).s ) +
1704
+ id2string (pool_entry (nameandtype_entry.ref2 ).s );
1707
1705
1708
1706
if (
1709
1707
method_name ==
1710
1708
" java/lang/invoke/LambdaMetafactory.metafactory(Ljava/lang/invoke/"
1711
1709
" MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/"
1712
1710
" lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/"
1713
1711
" MethodType;)Ljava/lang/invoke/CallSite;" )
1714
- handle.handle_type = method_handle_typet::BOOTSTRAP_METHOD_HANDLE;
1715
- // names seem to be lambda$$POSTFIX$NUM
1716
- // where $POSTFIX is $FUN for a function name in which the lambda is define
1717
- // "static" when it is a static member of the class
1718
- // "new" when it is a class variable, instantiated in <init>
1719
- else if (has_prefix (id2string (pool_entry (nameandtype_entry.ref1 ).s ), " lambda$" ))
1720
1712
{
1721
- handle.lambda_method_name = pool_entry (nameandtype_entry.ref1 ).s ;
1722
- handle.handle_type = method_handle_typet::LAMBDA_METHOD_HANDLE;
1713
+ lambda_method_handle.handle_type =
1714
+ method_handle_typet::BOOTSTRAP_METHOD_HANDLE;
1715
+ }
1716
+ else if (
1717
+ has_prefix (id2string (pool_entry (nameandtype_entry.ref1 ).s ), " lambda$" ))
1718
+ {
1719
+ // names seem to be lambda$POSTFIX$NUM
1720
+ // where POSTFIX is FUN for a function name in which the lambda is define
1721
+ // "static" when it is a static member of the class
1722
+ // "new" when it is a class variable, instantiated in <init>
1723
+ lambda_method_handle.lambda_method_name =
1724
+ pool_entry (nameandtype_entry.ref1 ).s ;
1725
+ lambda_method_handle.handle_type =
1726
+ method_handle_typet::LAMBDA_METHOD_HANDLE;
1723
1727
}
1724
1728
else if (
1725
1729
method_name ==
1726
1730
" java/lang/invoke/LambdaMetafactory.altMetafactory(Ljava/lang/invoke/"
1727
1731
" MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/"
1728
1732
" MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;" )
1729
- handle.handle_type = method_handle_typet::BOOTSTRAP_METHOD_HANDLE_ALT;
1733
+ {
1734
+ lambda_method_handle.handle_type =
1735
+ method_handle_typet::BOOTSTRAP_METHOD_HANDLE_ALT;
1736
+ }
1737
+ else
1738
+ return {};
1739
+
1740
+ return lambda_method_handle;
1730
1741
}
0 commit comments