@@ -47,6 +47,14 @@ class java_bytecode_parsert:public parsert
47
47
typedef java_bytecode_parse_treet::instructiont instructiont;
48
48
typedef java_bytecode_parse_treet::annotationt annotationt;
49
49
typedef java_bytecode_parse_treet::annotationst annotationst;
50
+ typedef java_bytecode_parse_treet::classt::lambda_method_handlet
51
+ lambda_method_handlet;
52
+ typedef java_bytecode_parse_treet::classt::method_handle_typet
53
+ method_handle_typet;
54
+ typedef java_bytecode_parse_treet::classt::lambda_method_handlest
55
+ lambda_method_handlest;
56
+ typedef java_bytecode_parse_treet::classt::lambda_method_handlest
57
+ lambda_method_handle_mapt;
50
58
51
59
java_bytecode_parse_treet parse_tree;
52
60
@@ -126,6 +134,7 @@ class java_bytecode_parsert:public parsert
126
134
void get_class_refs ();
127
135
void get_class_refs_rec (const typet &);
128
136
void parse_local_variable_type_table (methodt &method);
137
+ void parse_methodhandle (const pool_entryt &, lambda_method_handlet &);
129
138
130
139
void skip_bytes (std::size_t bytes)
131
140
{
@@ -1406,6 +1415,124 @@ void java_bytecode_parsert::rclass_attribute(classt &parsed_class)
1406
1415
{
1407
1416
rRuntimeAnnotation_attribute (parsed_class.annotations );
1408
1417
}
1418
+ else if (attribute_name == " BootstrapMethods" )
1419
+ {
1420
+ INVARIANT (
1421
+ !parsed_class.read_attribute_bootstrapmethods ,
1422
+ " only one BootstrapMethods argument is allowed in a class file" );
1423
+
1424
+ // mark as read in parsed class
1425
+ parsed_class.read_attribute_bootstrapmethods = true ;
1426
+ u2 num_bootstrap_methods = read_u2 ();
1427
+ for (size_t i = 0 ; i < num_bootstrap_methods; i++)
1428
+ {
1429
+ u2 bootstrap_methodhandle_ref = read_u2 ();
1430
+ const pool_entryt &entry = pool_entry (bootstrap_methodhandle_ref);
1431
+ u2 num_bootstrap_arguments = read_u2 ();
1432
+
1433
+ lambda_method_handlet handle;
1434
+ status () << " INFO: parse BootstrapMethod handle "
1435
+ << num_bootstrap_arguments << " #args"
1436
+ << eom;
1437
+ parse_methodhandle (entry, handle);
1438
+ if (
1439
+ handle.handle_type ==
1440
+ method_handle_typet::BOOTSTRAP_METHOD_HANDLE_ALT ||
1441
+ handle.handle_type == method_handle_typet::BOOTSTRAP_METHOD_HANDLE)
1442
+ {
1443
+ // try parsing bootstrap method handle
1444
+ if (num_bootstrap_arguments >= 3 )
1445
+ {
1446
+ // each entry contains a MethodHandle structure
1447
+ // u2 tag
1448
+ // u2 reference kind which must be in the range from 1 to 9
1449
+ // u2 reference index into the constant pool
1450
+ //
1451
+ // reference kinds use the following
1452
+ // 1 to 4 must point to a CONSTANT_Fieldref structure
1453
+ // 5 or 8 must point to a CONSTANT_Methodref structure
1454
+ // 6 or 7 must point to a CONSTANT_Methodref or
1455
+ // CONSTANT_InterfaceMethodref structure, if the class file version
1456
+ // number is 52.0 or above, to a CONSTANT_Methodref only in the case
1457
+ // of less than 52.0
1458
+ // 9 must point to a CONSTANT_InterfaceMethodref structure
1459
+
1460
+ // the index must point to a CONSTANT_String
1461
+ // CONSTANT_Class
1462
+ // CONSTANT_Integer
1463
+ // CONSTANT_Long
1464
+ // CONSTANT_Float
1465
+ // CONSTANT_Double
1466
+ // CONSTANT_MethodHandle
1467
+ // CONSTANT_MethodType
1468
+ u2 arg_index1 = read_u2 ();
1469
+ u2 arg_index2 = read_u2 ();
1470
+ u2 arg_index3 = read_u2 ();
1471
+
1472
+ // skip rest
1473
+ for (size_t i = 3 ; i < num_bootstrap_arguments; i++)
1474
+ read_u2 ();
1475
+
1476
+ const pool_entryt &arg1 = pool_entry (arg_index1);
1477
+ const pool_entryt &arg2 = pool_entry (arg_index2);
1478
+ const pool_entryt &arg3 = pool_entry (arg_index3);
1479
+
1480
+ if (!(arg1.tag == CONSTANT_MethodType &&
1481
+ arg2.tag == CONSTANT_MethodHandle &&
1482
+ arg3.tag == CONSTANT_MethodType))
1483
+ return ;
1484
+
1485
+ lambda_method_handlet real_handle;
1486
+ status () << " INFO: parse lambda handle" << eom;
1487
+ const pool_entryt &lambda_entry = pool_entry (arg_index2);
1488
+ parse_methodhandle (lambda_entry, real_handle);
1489
+ if (
1490
+ real_handle.handle_type !=
1491
+ method_handle_typet::LAMBDA_METHOD_HANDLE)
1492
+ {
1493
+ lambda_method_handlet empty_handle;
1494
+ parsed_class.lambda_method_handle_map [parsed_class.name ].push_back (
1495
+ empty_handle);
1496
+ error () << " ERROR: could not parse lambda function method handle"
1497
+ << eom;
1498
+ }
1499
+ else
1500
+ {
1501
+ real_handle.interface_type = pool_entry (arg1.ref1 ).s ;
1502
+ real_handle.method_type = pool_entry (arg3.ref1 ).s ;
1503
+ parsed_class.lambda_method_handle_map [parsed_class.name ].push_back (
1504
+ real_handle);
1505
+ status ()
1506
+ << " lambda function reference "
1507
+ << id2string (real_handle.lambda_method_name ) << " in class \" "
1508
+ << parsed_class.name << " \" "
1509
+ << " \n interface type is "
1510
+ << id2string (real_handle.interface_type = pool_entry (arg1.ref1 ).s )
1511
+ << " \n method type is "
1512
+ << id2string (real_handle.interface_type = pool_entry (arg3.ref1 ).s )
1513
+ << eom;
1514
+ }
1515
+ }
1516
+ else
1517
+ {
1518
+ // skip arguments here
1519
+ for (size_t i = 0 ; i < num_bootstrap_arguments; i++)
1520
+ read_u2 ();
1521
+ error () << " ERROR: num_bootstrap_arguments must be 3" << eom;
1522
+ }
1523
+ }
1524
+ else
1525
+ {
1526
+ lambda_method_handlet empty_handle;
1527
+ parsed_class.lambda_method_handle_map [parsed_class.name ].push_back (
1528
+ empty_handle);
1529
+ // skip arguments here
1530
+ for (size_t i = 0 ; i < num_bootstrap_arguments; i++)
1531
+ read_u2 ();
1532
+ error () << " ERROR: could not parse BootstrapMethods entry" << eom;
1533
+ }
1534
+ }
1535
+ }
1409
1536
else
1410
1537
skip_bytes (attribute_length);
1411
1538
}
@@ -1534,3 +1661,54 @@ void java_bytecode_parsert::parse_local_variable_type_table(methodt &method)
1534
1661
" Entry in LocalVariableTypeTable must be present in LVT" );
1535
1662
}
1536
1663
}
1664
+
1665
+ // / Read method handle pointed to from constant pool entry at index, return type
1666
+ // / of method handle and name if lambda function is found.
1667
+ // / \param entry: the constant pool entry of the methodhandle_info structure
1668
+ // / \param[out]: the method_handle type of the methodhandle_structure, either
1669
+ // / for a recognized bootstrap method, for a lambda function or unknown
1670
+ void java_bytecode_parsert::parse_methodhandle (
1671
+ const pool_entryt &entry,
1672
+ lambda_method_handlet &handle)
1673
+ {
1674
+ INVARIANT (
1675
+ entry.tag == CONSTANT_MethodHandle,
1676
+ " constant pool entry must be a MethodHandle" );
1677
+ const auto &ref_entry = pool_entry (entry.ref2 );
1678
+ INVARIANT (
1679
+ (entry.ref1 > 0 && entry.ref1 < 10 ),
1680
+ " reference kind of Methodhandle must be in the range of 1 to 9" );
1681
+
1682
+ const auto &class_entry = pool_entry (ref_entry.ref1 );
1683
+ const auto &nameandtype_entry = pool_entry (ref_entry.ref2 );
1684
+
1685
+ const std::string method_name =
1686
+ id2string (pool_entry (class_entry.ref1 ).s ) + " ."
1687
+ + id2string (pool_entry (nameandtype_entry.ref1 ).s )
1688
+ + id2string (pool_entry (nameandtype_entry.ref2 ).s );
1689
+
1690
+ if (
1691
+ method_name ==
1692
+ " java/lang/invoke/LambdaMetafactory.metafactory(Ljava/lang/invoke/"
1693
+ " MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/"
1694
+ " lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/"
1695
+ " MethodType;)Ljava/lang/invoke/CallSite;" )
1696
+ handle.handle_type = method_handle_typet::BOOTSTRAP_METHOD_HANDLE;
1697
+
1698
+ // names seem to be lambda$$POSTFIX$NUM
1699
+ // where $POSTFIX is $FUN for a function name in which the lambda is define
1700
+ // "static" when it is a static member of the class
1701
+ // "new" when it is a class variable, instantiated in <init>
1702
+ if (has_prefix (id2string (pool_entry (nameandtype_entry.ref1 ).s ), " lambda$" ))
1703
+ {
1704
+ handle.lambda_method_name = pool_entry (nameandtype_entry.ref1 ).s ;
1705
+ handle.handle_type = method_handle_typet::LAMBDA_METHOD_HANDLE;
1706
+ }
1707
+
1708
+ else if (
1709
+ method_name ==
1710
+ " java/lang/invoke/LambdaMetafactory.altMetafactory(Ljava/lang/invoke/"
1711
+ " MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/"
1712
+ " MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;" )
1713
+ handle.handle_type = method_handle_typet::BOOTSTRAP_METHOD_HANDLE_ALT;
1714
+ }
0 commit comments