PageRenderTime 54ms CodeModel.GetById 28ms app.highlight 13ms RepoModel.GetById 1ms app.codeStats 1ms

/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--
 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