/src/tools/compiler/asm/marshall/liberty_asm_reader.e

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