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