/src/tools/compiler/asm/marshall/liberty_asm_reader.e
Specman e | 718 lines | 649 code | 54 blank | 15 comment | 71 complexity | ec39e1be7eb212a8542fb74a8c1edcd3 MD5 | raw file
1-- This file is part of Liberty Eiffel. 2-- 3-- Liberty Eiffel is free software: you can redistribute it and/or modify 4-- it under the terms of the GNU General Public License as published by 5-- the Free Software Foundation, version 3 of the License. 6-- 7-- Liberty Eiffel is distributed in the hope that it will be useful, 8-- but WITHOUT ANY WARRANTY; without even the implied warranty of 9-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10-- GNU General Public License for more details. 11-- 12-- You should have received a copy of the GNU General Public License 13-- along with Liberty Eiffel. If not, see <http://www.gnu.org/licenses/>. 14-- 15class LIBERTY_ASM_READER 16 17inherit 18 LIBERTY_ASM_INSTRUCTION_VISITOR 19 LIBERTY_ASM_PROXY_VISITOR 20 21insert 22 LIBERTY_ASM_CODES 23 STRING_HANDLER 24 25create {LIBERTY_ASM_MARSHALLER} 26 read 27 28feature {LIBERTY_ASM_MARSHALLER} 29 system: LIBERTY_ASM_SYSTEM 30 error: STRING 31 32feature {} 33 types_map: DICTIONARY[LIBERTY_ASM_TYPE, INTEGER] 34 35 read (a_stream: INPUT_STREAM) is 36 require 37 a_stream /= Void 38 local 39 marker, method_id, type_id: INTEGER 40 do 41 marker := read_data(a_stream) 42 if error = Void then 43 if marker /= system_marker then 44 set_bad_format("read: invalid system marker") 45 else 46 method_id := read_data(a_stream) 47 if error = Void then 48 type_id := read_data(a_stream) 49 if error = Void then 50 from 51 create {HASHED_DICTIONARY[LIBERTY_ASM_TYPE, INTEGER]} types_map.make 52 until 53 a_stream.end_of_input or else error /= Void 54 loop 55 read_type(a_stream) 56 end 57 if error = Void then 58 resolve_all(a_stream, method_id, type_id) 59 end 60 if error /= Void then 61 types_map := Void 62 end 63 end 64 end 65 end 66 end 67 end 68 69 read_type (a_stream: INPUT_STREAM) is 70 require 71 error = Void 72 a_stream /= Void 73 local 74 marker, id, attributes_count, methods_count: INTEGER 75 type: LIBERTY_ASM_TYPE 76 do 77 marker := read_data_eof(a_stream) 78 if not a_stream.end_of_input then 79 if marker /= type_marker then 80 set_bad_format("read_type: invalid type marker") 81 else 82 id := read_data(a_stream) 83 if error = Void then 84 if types_map.has(id) then 85 set_bad_format("read_type: duplicate type id " + id.out) 86 else 87 attributes_count := read_data(a_stream) 88 if error = Void then 89 if attributes_count < 0 then 90 set_bad_format("read_type: invalid negative attributes_count") 91 else 92 methods_count := read_data(a_stream) 93 if error = Void then 94 if methods_count < 0 then 95 set_bad_format("read_type: invalid negative methods_count") 96 else 97 create type.make(id, attributes_count) 98 types_map.add(type, id) 99 (1 |..| methods_count).do_all(agent read_method(a_stream, type)) 100 end 101 end 102 end 103 end 104 end 105 end 106 end 107 end 108 end 109 110 read_method (a_stream: INPUT_STREAM; a_type: LIBERTY_ASM_TYPE) is 111 require 112 a_stream /= Void 113 a_type /= Void 114 local 115 marker, id, parameters_count: INTEGER 116 flags: INTEGER_8 117 do 118 if error = Void then 119 marker := read_data(a_stream) 120 if marker /= method_marker then 121 set_bad_format("read_method: invalid method marker") 122 else 123 id := read_data(a_stream) 124 if error = Void then 125 parameters_count := read_data(a_stream) 126 if error = Void then 127 if parameters_count < 0 then 128 set_bad_format("read_method: invalid negative parameters_count") 129 else 130 flags := read_code(a_stream) 131 if error = Void then 132 create_method(a_stream, a_type, parameters_count, flags) 133 end 134 end 135 end 136 end 137 end 138 end 139 end 140 141 create_method (a_stream: INPUT_STREAM; a_type: LIBERTY_ASM_TYPE; parameters_count: INTEGER; flags: INTEGER_8) is 142 require 143 error = Void 144 a_stream /= Void 145 a_type /= Void 146 parameters_count >= 0 147 local 148 method: LIBERTY_ASM_METHOD 149 code: LIBERTY_ASM_INSTRUCTION 150 do 151 code := read_instructions(a_stream) 152 if error = Void then 153 create method.make(a_type, code, create_parameters(parameters_count)) 154 if flags & flag_retry /= 0 and then error = Void then 155 code := read_instructions(a_stream) 156 if error = Void then 157 method.set_retry(code) 158 end 159 end 160 if flags & flag_precondition /= 0 and then error = Void then 161 code := read_instructions(a_stream) 162 if error = Void then 163 method.set_precondition(code) 164 end 165 end 166 if flags & flag_postcondition /= 0 and then error = Void then 167 code := read_instructions(a_stream) 168 if error = Void then 169 method.set_postcondition(code) 170 end 171 end 172 end 173 end 174 175 create_parameters (count: INTEGER): COLLECTION[LIBERTY_ASM_PARAMETER] is 176 require 177 error = Void 178 count >= 0 179 local 180 i: INTEGER 181 do 182 create {FAST_ARRAY[LIBERTY_ASM_PARAMETER]} Result.with_capacity(count) 183 from 184 i := 1 185 until 186 i > count 187 loop 188 Result.add_last(create {LIBERTY_ASM_PARAMETER}.make) 189 i := i + 1 190 end 191 end 192 193 read_instructions (a_stream: INPUT_STREAM): LIBERTY_ASM_INSTRUCTION is 194 require 195 error = Void 196 a_stream /= Void 197 local 198 size: INTEGER 199 do 200 size := read_data(a_stream) 201 if error = Void then 202 if size < 0 then 203 set_bad_format("read_instructions: invalid negative size") 204 else 205 Result := read_instructions_until(a_stream, size) 206 end 207 end 208 end 209 210 read_instructions_until (a_stream: INPUT_STREAM; size: INTEGER): LIBERTY_ASM_INSTRUCTION is 211 require 212 error = Void 213 a_stream /= Void 214 size >= 0 215 local 216 code: INTEGER_8; next: LIBERTY_ASM_INSTRUCTION 217 do 218 if size > 0 then 219 code := read_code(a_stream) 220 if error = Void then 221 Result := create_instruction(a_stream, code) 222 if error = Void then 223 next := read_instructions_until(a_stream, size - positions.sizeof(Result)) 224 if error = Void and then next /= Void then 225 Result.set_next(next) 226 end 227 end 228 end 229 end 230 end 231 232 create_instruction (a_stream: INPUT_STREAM; code: INTEGER_8): LIBERTY_ASM_INSTRUCTION is 233 require 234 error = Void 235 a_stream /= Void 236 do 237 inspect 238 code 239 when asm_new then 240 Result := create_new(a_stream) 241 when asm_jump then 242 Result := create_jump(a_stream) 243 when asm_invoke then 244 Result := create_invoke(a_stream) 245 when asm_return then 246 create {LIBERTY_ASM_RETURN} Result.make 247 when asm_call_native then 248 Result := create_call_native(a_stream) 249 when asm_not then 250 create {LIBERTY_ASM_NOT} Result.make 251 when asm_and then 252 create {LIBERTY_ASM_AND} Result.make 253 when asm_or then 254 create {LIBERTY_ASM_OR} Result.make 255 when asm_load_int then 256 Result := create_load_int(a_stream) 257 when asm_add_int then 258 create {LIBERTY_ASM_ADD_INT} Result.make 259 when asm_sub_int then 260 create {LIBERTY_ASM_SUB_INT} Result.make 261 when asm_mul_int then 262 create {LIBERTY_ASM_MUL_INT} Result.make 263 when asm_div_int then 264 create {LIBERTY_ASM_DIV_INT} Result.make 265 when asm_rem_int then 266 create {LIBERTY_ASM_REM_INT} Result.make 267 else 268 set_bad_format("create_instruction: invalid code 0x" + code.to_hexadecimal) 269 end 270 ensure 271 Result = Void implies error /= Void 272 Result /= Void implies Result.next = Void 273 end 274 275 create_new (a_stream: INPUT_STREAM): LIBERTY_ASM_INSTRUCTION_PROXY is 276 require 277 a_stream /= Void 278 local 279 type_id: INTEGER 280 do 281 type_id := read_data(a_stream) 282 if error = Void then 283 create Result.new(type_id) 284 end 285 ensure 286 (Result = Void) /= (error = Void) 287 end 288 289 create_invoke (a_stream: INPUT_STREAM): LIBERTY_ASM_INSTRUCTION_PROXY is 290 require 291 a_stream /= Void 292 local 293 type_id, method_id: INTEGER 294 do 295 type_id := read_data(a_stream) 296 if error = Void then 297 method_id := read_data(a_stream) 298 if error = Void then 299 create Result.invoke(method_id, type_id) 300 end 301 end 302 ensure 303 (Result = Void) /= (error = Void) 304 end 305 306 create_call_native (a_stream: INPUT_STREAM): LIBERTY_ASM_CALL_NATIVE is 307 require 308 a_stream /= Void 309 local 310 symbol: FIXED_STRING 311 arguments_count: INTEGER 312 arguments: FAST_ARRAY[LIBERTY_ASM_NATIVE_VALUE] 313 return: LIBERTY_ASM_NATIVE_VALUE 314 do 315 return := read_native(a_stream) 316 if error = Void then 317 symbol := read_string(a_stream) 318 if error = Void then 319 arguments_count := read_data(a_stream) 320 if error = Void then 321 if arguments_count < 0 then 322 set_bad_format("create_call_native: invalid negative arguments_count") 323 else 324 create arguments.with_capacity(arguments_count) 325 (1 |..| arguments_count).do_all(agent put_native(a_stream, arguments)) 326 if error = Void then 327 create Result.make(symbol, arguments, return) 328 end 329 end 330 end 331 end 332 end 333 ensure 334 (Result = Void) /= (error = Void) 335 end 336 337 create_load_int (a_stream: INPUT_STREAM): LIBERTY_ASM_LOAD_INT is 338 require 339 a_stream /= Void 340 local 341 value: INTEGER 342 do 343 value := read_data(a_stream) 344 if error = Void then 345 create Result.make(value) 346 end 347 end 348 349 put_native (a_stream: INPUT_STREAM; arguments: FAST_ARRAY[LIBERTY_ASM_NATIVE_VALUE]) is 350 require 351 a_stream /= Void 352 arguments /= Void 353 local 354 argument: LIBERTY_ASM_NATIVE_VALUE 355 do 356 if error = Void then 357 argument := read_native(a_stream) 358 if error = Void then 359 if argument = Void then 360 set_bad_format("put_native: invalid void argument") 361 else 362 arguments.add_last(argument) 363 end 364 end 365 end 366 end 367 368 read_string (a_stream: INPUT_STREAM): FIXED_STRING is 369 require 370 a_stream /= Void 371 local 372 count, i: INTEGER; char: INTEGER_8; string: STRING 373 do 374 count := read_data(a_stream) 375 if error = Void then 376 if count < 0 then 377 set_bad_format("read_string: invalid negative count") 378 else 379 string := once "" 380 string.clear_count 381 string.ensure_capacity(count) 382 from 383 i := 1 384 until 385 error /= Void or else i > count 386 loop 387 char := read_code(a_stream) 388 if error = Void then 389 string.add_last(char.to_character) 390 end 391 i := i + 1 392 end 393 if error = Void then 394 Result := string.intern 395 end 396 end 397 end 398 ensure 399 (error = Void) /= (Result = Void) 400 end 401 402 read_native (a_stream: INPUT_STREAM): LIBERTY_ASM_NATIVE_VALUE is 403 require 404 a_stream /= Void 405 local 406 native_code: INTEGER_8 407 do 408 native_code := read_code(a_stream) 409 if error = Void then 410 inspect 411 native_code 412 when native_void then 413 check 414 Result = Void 415 end 416 when native_integer then 417 create Result.integer 418 when native_pointer then 419 create Result.pointer 420 else 421 set_bad_format("read_native: invalid native_code 0x" + native_code.to_hexadecimal) 422 end 423 end 424 ensure 425 error /= Void implies Result = Void 426 end 427 428 create_jump (a_stream: INPUT_STREAM): LIBERTY_ASM_INSTRUCTION_PROXY is 429 require 430 a_stream /= Void 431 local 432 position: INTEGER 433 do 434 position := read_data(a_stream) 435 if error = Void then 436 create Result.jump(position) 437 end 438 ensure 439 (Result = Void) /= (error = Void) 440 end 441 442 read_code (a_stream: INPUT_STREAM): INTEGER_8 is 443 require 444 a_stream /= Void 445 error = Void 446 do 447 Result := do_read_code(a_stream, False) 448 end 449 450 do_read_code (a_stream: INPUT_STREAM; allow_eof: BOOLEAN): INTEGER_8 is 451 require 452 a_stream /= Void 453 error = Void 454 do 455 a_stream.read_character 456 if a_stream.end_of_input then 457 if not allow_eof then 458 set_bad_format("read_code: unexpected end of input") 459 end 460 else 461 Result := a_stream.last_character.to_integer_8 462 end 463 end 464 465 read_data (a_stream: INPUT_STREAM): INTEGER is 466 require 467 a_stream /= Void 468 error = Void 469 do 470 Result := do_read_data(a_stream, False) 471 end 472 473 read_data_eof (a_stream: INPUT_STREAM): INTEGER is 474 require 475 a_stream /= Void 476 error = Void 477 do 478 Result := do_read_data(a_stream, True) 479 end 480 481 do_read_data (a_stream: INPUT_STREAM; allow_eof: BOOLEAN): INTEGER is 482 require 483 a_stream /= Void 484 error = Void 485 local 486 a, b, c, d: INTEGER_8 487 do 488 a := do_read_code(a_stream, allow_eof) 489 if error = Void and then not a_stream.end_of_input then 490 b := read_code(a_stream) 491 if error = Void then 492 c := read_code(a_stream) 493 if error = Void then 494 d := read_code(a_stream) 495 if error = Void then 496 Result := (a.to_integer_32 & 0x000000ff) | ((b.to_integer_32 & 0x000000ff) |<< 8) | ((c.to_integer_32 & 0x000000ff) |<< 16) | ((d.to_integer_32 & 0x000000ff) |<< 24) 497 end 498 end 499 end 500 end 501 end 502 503feature {} 504 resolve_all (a_stream: INPUT_STREAM; method_id, type_id: INTEGER) is 505 local 506 types_list: FAST_ARRAY[LIBERTY_ASM_TYPE] 507 main_type: LIBERTY_ASM_TYPE 508 main_method: LIBERTY_ASM_METHOD 509 do 510 create types_list.with_capacity(types_map.count) 511 types_map.item_map_in(types_list) 512 positions.set_positions(types_list) 513 types_list.do_all(agent do_resolve_type) 514 main_type := types_map.reference_at(type_id) 515 if main_type = Void then 516 set_bad_format("resolve_all: unknown main type") 517 else 518 main_method := main_type.resolve_method(method_id) 519 if main_method = Void then 520 set_bad_format("resolve_all: unknown main method") 521 else 522 create system.make(types_list, main_method) 523 end 524 end 525 end 526 527 do_resolve_type (a_type: LIBERTY_ASM_TYPE) is 528 require 529 a_type /= Void 530 do 531 a_type.do_all_methods(agent do_resolve_method) 532 end 533 534 do_resolve_method (a_method: LIBERTY_ASM_METHOD) is 535 require 536 a_method /= Void 537 do 538 a_method.set_code(resolve_code(a_method.code)) 539 a_method.set_retry(resolve_code(a_method.retry_code)) 540 a_method.set_precondition(resolve_code(a_method.precondition)) 541 a_method.set_postcondition(resolve_code(a_method.postcondition)) 542 end 543 544 resolve_code (a_instruction: LIBERTY_ASM_INSTRUCTION): LIBERTY_ASM_INSTRUCTION is 545 do 546 if a_instruction /= Void then 547 current_code := a_instruction 548 Result := do_resolve_code(a_instruction) 549 end 550 end 551 552 do_resolve_code (a_instruction: LIBERTY_ASM_INSTRUCTION): LIBERTY_ASM_INSTRUCTION is 553 require 554 a_instruction /= Void 555 do 556 current_instruction := a_instruction 557 a_instruction.accept(Current) 558 Result := resolved_instruction 559 if a_instruction.next /= Void then 560 Result.set_next(do_resolve_code(a_instruction.next)) 561 end 562 end 563 564 current_code: LIBERTY_ASM_INSTRUCTION 565 current_instruction: LIBERTY_ASM_INSTRUCTION 566 resolved_instruction: LIBERTY_ASM_INSTRUCTION 567 568 resolve_target (position: INTEGER): LIBERTY_ASM_INSTRUCTION is 569 do 570 from 571 if position >= current_instruction.position then 572 Result := current_instruction 573 else 574 Result := current_code 575 end 576 until 577 Result = Void or else Result.position >= position 578 loop 579 Result := Result.next 580 end 581 if Result = Void or else Result.position > position then 582 set_bad_format("resolve_target: invalid position") 583 else 584 -- if the resolved target is itself a proxy, it must be resolved too 585 Result.accept(Current) 586 Result := resolved_instruction 587 end 588 ensure 589 (error = Void) /= (Result = Void) 590 end 591 592feature {LIBERTY_ASM_INSTRUCTION} 593 visit_and (a_instruction: LIBERTY_ASM_AND) is 594 do 595 resolved_instruction := a_instruction 596 end 597 598 visit_invoke (a_instruction: LIBERTY_ASM_INVOKE) is 599 do 600 resolved_instruction := a_instruction 601 end 602 603 visit_jump (a_instruction: LIBERTY_ASM_JUMP) is 604 do 605 resolved_instruction := a_instruction 606 end 607 608 visit_new (a_instruction: LIBERTY_ASM_NEW) is 609 do 610 resolved_instruction := a_instruction 611 end 612 613 visit_not (a_instruction: LIBERTY_ASM_NOT) is 614 do 615 resolved_instruction := a_instruction 616 end 617 618 visit_or (a_instruction: LIBERTY_ASM_OR) is 619 do 620 resolved_instruction := a_instruction 621 end 622 623 visit_return (a_instruction: LIBERTY_ASM_RETURN) is 624 do 625 resolved_instruction := a_instruction 626 end 627 628 visit_load_int (a_instruction: LIBERTY_ASM_LOAD_INT) is 629 do 630 resolved_instruction := a_instruction 631 end 632 633 visit_add_int (a_instruction: LIBERTY_ASM_ADD_INT) is 634 do 635 resolved_instruction := a_instruction 636 end 637 638 visit_sub_int (a_instruction: LIBERTY_ASM_SUB_INT) is 639 do 640 resolved_instruction := a_instruction 641 end 642 643 visit_mul_int (a_instruction: LIBERTY_ASM_MUL_INT) is 644 do 645 resolved_instruction := a_instruction 646 end 647 648 visit_div_int (a_instruction: LIBERTY_ASM_DIV_INT) is 649 do 650 resolved_instruction := a_instruction 651 end 652 653 visit_rem_int (a_instruction: LIBERTY_ASM_REM_INT) is 654 do 655 resolved_instruction := a_instruction 656 end 657 658 visit_call_native (a_instruction: LIBERTY_ASM_CALL_NATIVE) is 659 do 660 resolved_instruction := a_instruction 661 end 662 663feature {LIBERTY_ASM_INSTRUCTION_PROXY} 664 visit_proxy_new (a_instruction: LIBERTY_ASM_INSTRUCTION_PROXY; type_id: INTEGER) is 665 local 666 type: LIBERTY_ASM_TYPE 667 do 668 type := types_map.reference_at(type_id) 669 if type = Void then 670 set_bad_format("visit_proxy_new: unknown type") 671 else 672 create {LIBERTY_ASM_NEW} resolved_instruction.make(type) 673 resolved_instruction.set_position(a_instruction.position) 674 end 675 end 676 677 visit_proxy_invoke (a_instruction: LIBERTY_ASM_INSTRUCTION_PROXY; method_id, type_id: INTEGER) is 678 local 679 type: LIBERTY_ASM_TYPE 680 method: LIBERTY_ASM_METHOD 681 do 682 type := types_map.reference_at(type_id) 683 if type = Void then 684 set_bad_format("visit_proxy_invoke: unknown type") 685 else 686 method := type.resolve_method(method_id) 687 if method = Void then 688 set_bad_format("visit_proxy_invoke: unknown method") 689 end 690 create {LIBERTY_ASM_INVOKE} resolved_instruction.make(method) 691 resolved_instruction.set_position(a_instruction.position) 692 end 693 end 694 695 visit_proxy_jump (a_instruction: LIBERTY_ASM_INSTRUCTION_PROXY; position: INTEGER) is 696 local 697 target: LIBERTY_ASM_INSTRUCTION 698 do 699 target := resolve_target(position) 700 if target /= Void then 701 create {LIBERTY_ASM_JUMP} resolved_instruction.set_target(target) 702 resolved_instruction.set_position(a_instruction.position) 703 end 704 end 705 706feature {} 707 error_bad_format: STRING is "Bad data format in " 708 709 set_bad_format (where: STRING) is 710 do 711 error := error_bad_format + where 712 sedb_breakpoint 713 end 714 715invariant 716 types_map = Void implies error /= Void 717 718end -- class LIBERTY_ASM_READER