generate_offset_extractor.rb 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. #!/usr/bin/env ruby
  2. # Copyright (C) 2011 Apple Inc. All rights reserved.
  3. #
  4. # Redistribution and use in source and binary forms, with or without
  5. # modification, are permitted provided that the following conditions
  6. # are met:
  7. # 1. Redistributions of source code must retain the above copyright
  8. # notice, this list of conditions and the following disclaimer.
  9. # 2. Redistributions in binary form must reproduce the above copyright
  10. # notice, this list of conditions and the following disclaimer in the
  11. # documentation and/or other materials provided with the distribution.
  12. #
  13. # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
  14. # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  15. # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  16. # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
  17. # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  18. # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  19. # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  20. # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  21. # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  22. # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  23. # THE POSSIBILITY OF SUCH DAMAGE.
  24. $: << File.dirname(__FILE__)
  25. require "config"
  26. require "backends"
  27. require "digest/sha1"
  28. require "offsets"
  29. require "parser"
  30. require "self_hash"
  31. require "settings"
  32. require "transform"
  33. inputFlnm = ARGV.shift
  34. outputFlnm = ARGV.shift
  35. $stderr.puts "offlineasm: Parsing #{inputFlnm} and creating offset extractor #{outputFlnm}."
  36. def emitMagicNumber
  37. OFFSET_MAGIC_NUMBERS.each {
  38. | number |
  39. $output.puts "unsigned(#{number}),"
  40. }
  41. end
  42. inputHash = "// offlineasm input hash: #{parseHash(inputFlnm)} #{selfHash}"
  43. if FileTest.exist? outputFlnm
  44. File.open(outputFlnm, "r") {
  45. | inp |
  46. firstLine = inp.gets
  47. if firstLine and firstLine.chomp == inputHash
  48. $stderr.puts "offlineasm: Nothing changed."
  49. exit 0
  50. end
  51. }
  52. end
  53. originalAST = parse(inputFlnm)
  54. #
  55. # Optimize the AST to make configuration extraction faster. This reduces the AST to a form
  56. # that only contains the things that matter for our purposes: offsets, sizes, and if
  57. # statements.
  58. #
  59. class Node
  60. def offsetsPruneTo(sequence)
  61. children.each {
  62. | child |
  63. child.offsetsPruneTo(sequence)
  64. }
  65. end
  66. def offsetsPrune
  67. result = Sequence.new(codeOrigin, [])
  68. offsetsPruneTo(result)
  69. result
  70. end
  71. end
  72. class IfThenElse
  73. def offsetsPruneTo(sequence)
  74. ifThenElse = IfThenElse.new(codeOrigin, predicate, thenCase.offsetsPrune)
  75. ifThenElse.elseCase = elseCase.offsetsPrune
  76. sequence.list << ifThenElse
  77. end
  78. end
  79. class StructOffset
  80. def offsetsPruneTo(sequence)
  81. sequence.list << self
  82. end
  83. end
  84. class Sizeof
  85. def offsetsPruneTo(sequence)
  86. sequence.list << self
  87. end
  88. end
  89. prunedAST = originalAST.offsetsPrune
  90. File.open(outputFlnm, "w") {
  91. | outp |
  92. $output = outp
  93. outp.puts inputHash
  94. length = 0
  95. emitCodeInAllConfigurations(prunedAST) {
  96. | settings, ast, backend, index |
  97. offsetsList = ast.filter(StructOffset).uniq.sort
  98. sizesList = ast.filter(Sizeof).uniq.sort
  99. length += OFFSET_HEADER_MAGIC_NUMBERS.size + (OFFSET_MAGIC_NUMBERS.size + 1) * (1 + offsetsList.size + sizesList.size)
  100. }
  101. outp.puts "static const unsigned extractorTable[#{length}] = {"
  102. emitCodeInAllConfigurations(prunedAST) {
  103. | settings, ast, backend, index |
  104. OFFSET_HEADER_MAGIC_NUMBERS.each {
  105. | number |
  106. $output.puts "unsigned(#{number}),"
  107. }
  108. offsetsList = ast.filter(StructOffset).uniq.sort
  109. sizesList = ast.filter(Sizeof).uniq.sort
  110. emitMagicNumber
  111. outp.puts "#{index},"
  112. offsetsList.each {
  113. | offset |
  114. emitMagicNumber
  115. outp.puts "OFFLINE_ASM_OFFSETOF(#{offset.struct}, #{offset.field}),"
  116. }
  117. sizesList.each {
  118. | offset |
  119. emitMagicNumber
  120. outp.puts "sizeof(#{offset.struct}),"
  121. }
  122. }
  123. outp.puts "};"
  124. }
  125. $stderr.puts "offlineasm: offset extractor #{outputFlnm} successfully generated."