OfflineASM Pretty printing and commenting enhancements.
https://bugs.webkit.org/show_bug.cgi?id=91281

Patch by Mark Lam <mark.lam@apple.com> on 2012-07-13
Reviewed by Filip Pizlo.

Added some minor pretty printing in the OfflineASM.
Also added infrastruture for adding multiple types of comments and
annotations with the ability to enable/disable them in the generated
output as desired.

* GNUmakefile.list.am: add new file config.rb.
* llint/LLIntOfflineAsmConfig.h:
  Added OFFLINE_ASM_BEGIN, OFFLINE_ASM_END, and OFFLINE_ASM_LOCAL_LABEL macros.
  This will allow us to redefine these for other backends later.
* llint/LowLevelInterpreter32_64.asm:
  Add a small example of instruction annotations for now.
* llint/LowLevelInterpreter64.asm:
  Add a small example of instruction annotations for now.
* offlineasm/armv7.rb: Added handling of annotations.
* offlineasm/asm.rb:
  Added machinery to dump the new comments and annotations.
  Also added some indentations to make the output a little prettier.
* offlineasm/ast.rb: Added annotation field in class Instruction.
* offlineasm/backends.rb:
* offlineasm/config.rb: Added.
  Currently only contains commenting options.  This file is meant to be
  a centralized place for build config values much like config.h for
  JavaScriptCore.
* offlineasm/generate_offset_extractor.rb:
* offlineasm/instructions.rb:
* offlineasm/offsets.rb:
* offlineasm/opt.rb:
* offlineasm/parser.rb: Parse and record annotations.
* offlineasm/registers.rb:
* offlineasm/self_hash.rb:
* offlineasm/settings.rb:
* offlineasm/transform.rb:
* offlineasm/x86.rb: Added handling of annotations.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@122650 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/offlineasm/armv7.rb b/Source/JavaScriptCore/offlineasm/armv7.rb
index 69df51a..1853812 100644
--- a/Source/JavaScriptCore/offlineasm/armv7.rb
+++ b/Source/JavaScriptCore/offlineasm/armv7.rb
@@ -21,6 +21,7 @@
 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 # THE POSSIBILITY OF SUCH DAMAGE.
 
+require "config"
 require "ast"
 require "opt"
 
@@ -147,6 +148,7 @@
     list.each {
         | node |
         if node.is_a? Instruction
+            annotation = node.annotation
             case node.opcode
             when /^b(addi|subi|ori|addp)/
                 op = $1
@@ -161,17 +163,17 @@
                     op = "oris"
                 end
                 
-                newList << Instruction.new(node.codeOrigin, op, node.operands[0..-2])
+                newList << Instruction.new(node.codeOrigin, op, node.operands[0..-2], annotation)
                 newList << Instruction.new(node.codeOrigin, branch, [node.operands[-1]])
             when "bmulio"
                 tmp1 = Tmp.new(node.codeOrigin, :gpr)
                 tmp2 = Tmp.new(node.codeOrigin, :gpr)
-                newList << Instruction.new(node.codeOrigin, "smulli", [node.operands[0], node.operands[1], node.operands[1], tmp1])
+                newList << Instruction.new(node.codeOrigin, "smulli", [node.operands[0], node.operands[1], node.operands[1], tmp1], annotation)
                 newList << Instruction.new(node.codeOrigin, "rshifti", [node.operands[-2], Immediate.new(node.codeOrigin, 31), tmp2])
                 newList << Instruction.new(node.codeOrigin, "bineq", [tmp1, tmp2, node.operands[-1]])
             when /^bmuli/
                 condition = $~.post_match
-                newList << Instruction.new(node.codeOrigin, "muli", node.operands[0..-2])
+                newList << Instruction.new(node.codeOrigin, "muli", node.operands[0..-2], annotation)
                 newList << Instruction.new(node.codeOrigin, "bti" + condition, [node.operands[-2], node.operands[-1]])
             else
                 newList << node
@@ -210,9 +212,9 @@
             case node.opcode
             when "lshifti", "rshifti", "urshifti", "lshiftp", "rshiftp", "urshiftp"
                 if node.operands.size == 2
-                    newList << Instruction.new(node.codeOrigin, node.opcode, [armV7SanitizeShift(node.operands[0], newList), node.operands[1]])
+                    newList << Instruction.new(node.codeOrigin, node.opcode, [armV7SanitizeShift(node.operands[0], newList), node.operands[1]], node.annotation)
                 else
-                    newList << Instruction.new(node.codeOrigin, node.opcode, [node.operands[0], armV7SanitizeShift(node.operands[1], newList), node.operands[2]])
+                    newList << Instruction.new(node.codeOrigin, node.opcode, [node.operands[0], armV7SanitizeShift(node.operands[1], newList), node.operands[2]], node.annotation)
                     raise "Wrong number of operands for shift at #{node.codeOriginString}" unless node.operands.size == 3
                 end
             else
@@ -321,9 +323,9 @@
         if node.is_a? Instruction
             case node.opcode
             when "loadd"
-                newList << Instruction.new(node.codeOrigin, "loadd", [node.operands[0].armV7DoubleAddress(newList), node.operands[1]])
+                newList << Instruction.new(node.codeOrigin, "loadd", [node.operands[0].armV7DoubleAddress(newList), node.operands[1]], node.annotation)
             when "stored"
-                newList << Instruction.new(node.codeOrigin, "stored", [node.operands[0], node.operands[1].armV7DoubleAddress(newList)])
+                newList << Instruction.new(node.codeOrigin, "stored", [node.operands[0], node.operands[1].armV7DoubleAddress(newList)], node.annotation)
             else
                 newList << node
             end
@@ -364,7 +366,7 @@
                         newOperands << operand
                     end
                 }
-                newList << Instruction.new(node.codeOrigin, node.opcode, newOperands)
+                newList << Instruction.new(node.codeOrigin, node.opcode, newOperands, node.annotation)
             else
                 newList << node
             end
@@ -431,6 +433,7 @@
     list.each {
         | node |
         if node.is_a? Instruction
+            annotation = node.annotation
             case node.opcode
             when "move"
                 newList << node
@@ -445,14 +448,15 @@
                         newOpcode = "add" + node.opcode[-1..-1]
                     end
                     newList << Instruction.new(node.codeOrigin, newOpcode,
-                                               [Immediate.new(-node.operands[0].value)] + node.operands[1..-1])
+                                               [Immediate.new(-node.operands[0].value)] + node.operands[1..-1],
+                                               annotation)
                 else
                     newList << node.armV7LowerMalformedImmediatesRecurse(newList)
                 end
             when "muli", "mulp"
                 if node.operands[0].is_a? Immediate
                     tmp = Tmp.new(codeOrigin, :gpr)
-                    newList << Instruction.new(node.codeOrigin, "move", [node.operands[0], tmp])
+                    newList << Instruction.new(node.codeOrigin, "move", [node.operands[0], tmp], annotation)
                     newList << Instruction.new(node.codeOrigin, "muli", [tmp] + node.operands[1..-1])
                 else
                     newList << node.armV7LowerMalformedImmediatesRecurse(newList)
@@ -514,30 +518,36 @@
         | node |
         if node.is_a? Instruction
             postInstructions = []
+            annotation = node.annotation
             case node.opcode
             when "addi", "addp", "addis", "andi", "andp", "lshifti", "lshiftp", "muli", "mulp", "negi",
                 "negp", "noti", "ori", "oris", "orp", "rshifti", "urshifti", "rshiftp", "urshiftp", "subi",
                 "subp", "subis", "xori", "xorp", /^bi/, /^bp/, /^bti/, /^btp/, /^ci/, /^cp/, /^ti/
                 newList << Instruction.new(node.codeOrigin,
                                            node.opcode,
-                                           armV7AsRegisters(newList, postInstructions, node.operands, "i"))
+                                           armV7AsRegisters(newList, postInstructions, node.operands, "i"),
+                                           annotation)
             when "bbeq", "bbneq", "bba", "bbaeq", "bbb", "bbbeq", "btbo", "btbz", "btbnz", "tbz", "tbnz",
                 "tbo", "cbeq", "cbneq", "cba", "cbaeq", "cbb", "cbbeq"
                 newList << Instruction.new(node.codeOrigin,
                                            node.opcode,
-                                           armV7AsRegisters(newList, postInstructions, node.operands, "b"))
+                                           armV7AsRegisters(newList, postInstructions, node.operands, "b"),
+                                           annotation)
             when "bbgt", "bbgteq", "bblt", "bblteq", "btbs", "tbs", "cbgt", "cbgteq", "cblt", "cblteq"
                 newList << Instruction.new(node.codeOrigin,
                                            node.opcode,
-                                           armV7AsRegisters(newList, postInstructions, node.operands, "bs"))
+                                           armV7AsRegisters(newList, postInstructions, node.operands, "bs"),
+                                           annotation)
             when "addd", "divd", "subd", "muld", "sqrtd", /^bd/
                 newList << Instruction.new(node.codeOrigin,
                                            node.opcode,
-                                           armV7AsRegisters(newList, postInstructions, node.operands, "d"))
+                                           armV7AsRegisters(newList, postInstructions, node.operands, "d"),
+                                           annotation)
             when "jmp", "call"
                 newList << Instruction.new(node.codeOrigin,
                                            node.opcode,
-                                           [armV7AsRegister(newList, postInstructions, node.operands[0], "p", false)])
+                                           [armV7AsRegister(newList, postInstructions, node.operands[0], "p", false)],
+                                           annotation)
             else
                 newList << node
             end
@@ -565,6 +575,7 @@
     list.each {
         | node |
         if node.is_a? Instruction
+            annotation = node.annotation
             case node.opcode
             when "cieq", "cineq", "cia", "ciaeq", "cib", "cibeq", "cigt", "cigteq", "cilt", "cilteq",
                 "cpeq", "cpneq", "cpa", "cpaeq", "cpb", "cpbeq", "cpgt", "cpgteq", "cplt", "cplteq",
@@ -573,7 +584,7 @@
                 if node.operands.size == 2
                     if node.operands[0] == node.operands[1]
                         tmp = Tmp.new(node.codeOrigin, :gpr)
-                        newList << Instruction.new(node.codeOrigin, "move", [node.operands[0], tmp])
+                        newList << Instruction.new(node.codeOrigin, "move", [node.operands[0], tmp], annotation)
                         newList << Instruction.new(node.codeOrigin, node.opcode, [tmp, node.operands[1]])
                     else
                         newList << node
@@ -582,11 +593,11 @@
                     raise "Wrong number of arguments at #{node.codeOriginString}" unless node.operands.size == 3
                     if node.operands[0] == node.operands[2]
                         tmp = Tmp.new(node.codeOrigin, :gpr)
-                        newList << Instruction.new(node.codeOrigin, "move", [node.operands[0], tmp])
+                        newList << Instruction.new(node.codeOrigin, "move", [node.operands[0], tmp], annotation)
                         newList << Instruction.new(node.codeOrigin, node.opcode, [tmp, node.operands[1], node.operands[2]])
                     elsif node.operands[1] == node.operands[2]
                         tmp = Tmp.new(node.codeOrigin, :gpr)
-                        newList << Instruction.new(node.codeOrigin, "move", [node.operands[1], tmp])
+                        newList << Instruction.new(node.codeOrigin, "move", [node.operands[1], tmp], annotation)
                         newList << Instruction.new(node.codeOrigin, node.opcode, [node.operands[0], tmp, node.operands[2]])
                     else
                         newList << node
@@ -732,7 +743,9 @@
 
 class Instruction
     def lowerARMv7
-        $asm.comment codeOriginString
+        $asm.codeOrigin codeOriginString
+        $asm.annotation annotation
+
         case opcode
         when "addi", "addp", "addis"
             if opcode == "addis"
diff --git a/Source/JavaScriptCore/offlineasm/asm.rb b/Source/JavaScriptCore/offlineasm/asm.rb
index 50f9bc8..0cf6320 100644
--- a/Source/JavaScriptCore/offlineasm/asm.rb
+++ b/Source/JavaScriptCore/offlineasm/asm.rb
@@ -25,6 +25,7 @@
 
 $: << File.dirname(__FILE__)
 
+require "config"
 require "backends"
 require "digest/sha1"
 require "offsets"
@@ -39,16 +40,21 @@
         @state = :cpp
         @commentState = :none
         @comment = nil
+        @internalComment = nil
+        @annotation = nil
+        @codeOrigin = nil
+        @numLocalLabels = 0
+        @numGlobalLabels = 0
     end
     
     def enterAsm
-        @outp.puts "asm ("
+        @outp.puts "OFFLINE_ASM_BEGIN"
         @state = :asm
     end
     
     def leaveAsm
         putsLastComment
-        @outp.puts ");"
+        @outp.puts "OFFLINE_ASM_END"
         @state = :cpp
     end
     
@@ -58,17 +64,35 @@
         leaveAsm
     end
     
+    # Concatenates all the various components of the comment to dump.
     def lastComment
-        if @comment
-            result = "// #{@comment}"
-        else
-            result = ""
+        result = ""
+        result = " #{@comment} ." if @comment
+        result += " #{@annotation} ." if @annotation and $enableTrailingInstrAnnotations
+        result += " #{@internalComment} ." if @internalComment
+        result += " #{@codeOrigin} ." if @codeOrigin and $enableCodeOriginComments
+        if result != ""
+            result = "  //" + result
         end
+
+        # Reset all the components that we've just sent to be dumped.
         @commentState = :none
         @comment = nil
+        @internalComment = nil
+        @annotation = nil
+        @codeOrigin = nil
         result
     end
     
+    # Dumps the current instruction annotation in interlaced mode if appropriate.
+    def putInterlacedAnnotation()
+        raise unless @state == :asm
+        if $enableInterlacedInstrAnnotations
+            @outp.puts("    // #{@annotation}") if @annotation
+            @annotation = nil
+        end
+    end
+
     def putsLastComment
         comment = lastComment
         unless comment.empty?
@@ -78,7 +102,8 @@
     
     def puts(*line)
         raise unless @state == :asm
-        @outp.puts("\"\\t" + line.join('') + "\\n\" #{lastComment}")
+        putInterlacedAnnotation
+        @outp.puts("    \"\\t" + line.join('') + "\\n\"#{lastComment}")
     end
     
     def print(line)
@@ -88,12 +113,18 @@
     
     def putsLabel(labelName)
         raise unless @state == :asm
-        @outp.puts("OFFLINE_ASM_GLOBAL_LABEL(#{labelName}) #{lastComment}")
+        @numGlobalLabels += 1
+        @outp.puts("\n")
+        @internalComment = $enableLabelCountComments ? "Global Label #{@numGlobalLabels}" : nil
+        @outp.puts("OFFLINE_ASM_GLOBAL_LABEL(#{labelName})#{lastComment}")
     end
     
     def putsLocalLabel(labelName)
         raise unless @state == :asm
-        @outp.puts("LOCAL_LABEL_STRING(#{labelName}) \":\\n\" #{lastComment}")
+        @numLocalLabels += 1
+        @outp.puts("\n")
+        @internalComment = $enableLabelCountComments ? "Local Label #{@numLocalLabels}" : nil
+        @outp.puts("OFFLINE_ASM_LOCAL_LABEL(#{labelName})#{lastComment}")
     end
     
     def self.labelReference(labelName)
@@ -104,22 +135,31 @@
         "\" LOCAL_LABEL_STRING(#{labelName}) \""
     end
     
-    def comment(text)
+    def codeOrigin(text)
         case @commentState
         when :none
-            @comment = text
+            @codeOrigin = text
             @commentState = :one
         when :one
-            @outp.puts "// #{@comment}"
-            @outp.puts "// #{text}"
-            @comment = nil
+            if $enableCodeOriginComments
+                @outp.puts "    // #{@codeOrigin}"
+                @outp.puts "    // #{text}"
+            end
+            @codeOrigin = nil
             @commentState = :many
         when :many
-            @outp.puts "// #{text}"
+            @outp.puts "// #{text}" if $enableCodeOriginComments
         else
             raise
         end
     end
+
+    def comment(text)
+        @comment = text
+    end
+    def annotation(text)
+        @annotation = text
+    end
 end
 
 asmFile = ARGV.shift
diff --git a/Source/JavaScriptCore/offlineasm/ast.rb b/Source/JavaScriptCore/offlineasm/ast.rb
index e555b5d..86ad6bc 100644
--- a/Source/JavaScriptCore/offlineasm/ast.rb
+++ b/Source/JavaScriptCore/offlineasm/ast.rb
@@ -21,6 +21,8 @@
 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 # THE POSSIBILITY OF SUCH DAMAGE.
 
+require "config"
+
 #
 # Base utility types for the AST.
 #
@@ -784,12 +786,13 @@
 end
 
 class Instruction < Node
-    attr_reader :opcode, :operands
+    attr_reader :opcode, :operands, :annotation
     
-    def initialize(codeOrigin, opcode, operands)
+    def initialize(codeOrigin, opcode, operands, annotation=nil)
         super(codeOrigin)
         @opcode = opcode
         @operands = operands
+        @annotation = annotation
     end
     
     def children
@@ -797,7 +800,7 @@
     end
     
     def mapChildren(&proc)
-        Instruction.new(codeOrigin, @opcode, @operands.map(&proc))
+        Instruction.new(codeOrigin, @opcode, @operands.map(&proc), @annotation)
     end
     
     def dump
diff --git a/Source/JavaScriptCore/offlineasm/backends.rb b/Source/JavaScriptCore/offlineasm/backends.rb
index db7a1e2..e33a2a0 100644
--- a/Source/JavaScriptCore/offlineasm/backends.rb
+++ b/Source/JavaScriptCore/offlineasm/backends.rb
@@ -21,6 +21,7 @@
 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 # THE POSSIBILITY OF SUCH DAMAGE.
 
+require "config"
 require "armv7"
 require "ast"
 require "x86"
diff --git a/Source/JavaScriptCore/offlineasm/config.rb b/Source/JavaScriptCore/offlineasm/config.rb
new file mode 100644
index 0000000..ce18981
--- /dev/null
+++ b/Source/JavaScriptCore/offlineasm/config.rb
@@ -0,0 +1,76 @@
+# Copyright (C) 2012 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+
+# Turns on dumping of the count of labels.
+# For example,  the output will look like this:
+#
+#    ...
+#    OFFLINE_ASM_LOCAL_LABEL(_offlineasm_4_functionArityCheck__continue)  // Local Label 24 .
+#    ...
+#    OFFLINE_ASM_GLOBAL_LABEL(llint_op_enter)  // Global Label 8 .
+#    ...
+#
+$enableLabelCountComments = false
+
+# Turns on dumping of source file and line numbers in the output file.
+# For example,  the output will look like this:
+#
+#    ...
+#    "\tmovq -8(%r13), %rcx\n"   // JavaScriptCore/llint/LowLevelInterpreter64.asm:185
+#    "\tmovl 52(%rcx), %ecx\n"   // JavaScriptCore/llint/LowLevelInterpreter64.asm:186
+#    ...
+#
+$enableCodeOriginComments = true
+
+# Turns on recording and dumping of annotations in the generated output file.
+# An annotations can be specified for each instruction in the source asm files.
+#
+# $enableInterlacedInstrAnnotations will interlace the annotation between
+# instructions.  For example, the output will look like this:
+#
+#     ...
+#     // @ t2<CodeBlock> = cfr.CodeBlock
+#    "\tmovq -8(%r13), %rcx\n"
+#     // @ t2<size_t> = t2<CodeBlock>.m_numVars
+#    "\tmovl 52(%rcx), %ecx\n"
+#     ...
+#
+# $enableTrailingInstrAnnotations will insert the annotation in the trailing
+# comment after your instructions.  For example, the output will look like this:
+#
+#     ...
+#    "\tmovq -8(%r13), %rcx\n"   // @ t2<CodeBlock> = cfr.CodeBlock
+#    "\tmovl 52(%rcx), %ecx\n"   // @ t2<size_t> = t2<CodeBlock>.m_numVars
+#     ...
+#
+# If both $enableInterlacedInstrAnnotations and $enableTrailingInstrAnnotations
+# are enabled, interlaced annotations will take precedence, and any available
+# annotations will only be dumped in the interlaced format.
+#
+$enableInterlacedInstrAnnotations = false
+$enableTrailingInstrAnnotations = false
+
+
+# Sanity check for annotation configs.
+$enableInstrAnnotations = ($enableInterlacedInstrAnnotations or $enableTrailingInstrAnnotations)
diff --git a/Source/JavaScriptCore/offlineasm/generate_offset_extractor.rb b/Source/JavaScriptCore/offlineasm/generate_offset_extractor.rb
index b2a8c2c..fefbb12 100644
--- a/Source/JavaScriptCore/offlineasm/generate_offset_extractor.rb
+++ b/Source/JavaScriptCore/offlineasm/generate_offset_extractor.rb
@@ -25,6 +25,7 @@
 
 $: << File.dirname(__FILE__)
 
+require "config"
 require "backends"
 require "digest/sha1"
 require "offsets"
diff --git a/Source/JavaScriptCore/offlineasm/instructions.rb b/Source/JavaScriptCore/offlineasm/instructions.rb
index 67cec6d..aa1a323 100644
--- a/Source/JavaScriptCore/offlineasm/instructions.rb
+++ b/Source/JavaScriptCore/offlineasm/instructions.rb
@@ -21,6 +21,8 @@
 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 # THE POSSIBILITY OF SUCH DAMAGE.
 
+require "config"
+
 # Interesting invariant, which we take advantage of: branching instructions
 # always begin with "b", and no non-branching instructions begin with "b".
 # Terminal instructions are "jmp" and "ret".
diff --git a/Source/JavaScriptCore/offlineasm/offsets.rb b/Source/JavaScriptCore/offlineasm/offsets.rb
index 4f2734f..8a064a2 100644
--- a/Source/JavaScriptCore/offlineasm/offsets.rb
+++ b/Source/JavaScriptCore/offlineasm/offsets.rb
@@ -21,6 +21,7 @@
 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 # THE POSSIBILITY OF SUCH DAMAGE.
 
+require "config"
 require "ast"
 
 def to32Bit(value)
diff --git a/Source/JavaScriptCore/offlineasm/opt.rb b/Source/JavaScriptCore/offlineasm/opt.rb
index 3170d3a..c721758 100644
--- a/Source/JavaScriptCore/offlineasm/opt.rb
+++ b/Source/JavaScriptCore/offlineasm/opt.rb
@@ -21,6 +21,7 @@
 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 # THE POSSIBILITY OF SUCH DAMAGE.
 
+require "config"
 require "ast"
 
 #
diff --git a/Source/JavaScriptCore/offlineasm/parser.rb b/Source/JavaScriptCore/offlineasm/parser.rb
index 11863c7..8696a61 100644
--- a/Source/JavaScriptCore/offlineasm/parser.rb
+++ b/Source/JavaScriptCore/offlineasm/parser.rb
@@ -21,6 +21,7 @@
 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 # THE POSSIBILITY OF SUCH DAMAGE.
 
+require "config"
 require "ast"
 require "instructions"
 require "pathname"
@@ -81,11 +82,20 @@
     fileName = Pathname.new(fileName)
     result = []
     lineNumber = 1
+    annotation = nil
     while not str.empty?
         case str
         when /\A\#([^\n]*)/
             # comment, ignore
+        when /\A\/\/([^\n]*)/
+            # annotation
+            annotation = $1
         when /\A\n/
+            # We've found a '\n'.  Emit the last comment recorded if appropriate:
+            if $enableInstrAnnotations and annotation
+                result << Token.new(CodeOrigin.new(fileName, lineNumber), "@" + annotation)
+                annotation = nil
+            end
             result << Token.new(CodeOrigin.new(fileName, lineNumber), $&)
             lineNumber += 1
         when /\A[a-zA-Z]([a-zA-Z0-9_]*)/
@@ -136,6 +146,10 @@
     token =~ /\A[a-zA-Z]([a-zA-Z0-9_]*)\Z/ and not isKeyword(token)
 end
 
+def isAnnotation(token)
+    token =~ /\A\@([^\n]*)/
+end
+
 def isLabel(token)
     token =~ /\A_([a-zA-Z0-9_]*)\Z/
 end
@@ -535,6 +549,10 @@
                     # Zero operand instruction, and it's the last one.
                     list << Instruction.new(codeOrigin, name, [])
                     break
+                elsif isAnnotation @tokens[@idx]
+                    annotation = @tokens[@idx].string
+                    list << Instruction.new(codeOrigin, name, [], annotation)
+                    @idx += 2 # Consume the newline as well.
                 elsif @tokens[@idx] == "\n"
                     # Zero operand instruction.
                     list << Instruction.new(codeOrigin, name, [])
@@ -543,6 +561,7 @@
                     # It's definitely an instruction, and it has at least one operand.
                     operands = []
                     endOfSequence = false
+                    annotation = nil
                     loop {
                         operands << parseOperand("while inside of instruction #{name}")
                         if (not final and @idx == @tokens.size) or (final and @tokens[@idx] =~ final)
@@ -552,6 +571,10 @@
                         elsif @tokens[@idx] == ","
                             # Has another operand.
                             @idx += 1
+                        elsif isAnnotation @tokens[@idx]
+                            annotation = @tokens[@idx].string
+                            @idx += 2 # Consume the newline as well.
+                            break
                         elsif @tokens[@idx] == "\n"
                             # The end of the instruction.
                             @idx += 1
@@ -560,7 +583,7 @@
                             parseError("Expected a comma, newline, or #{final} after #{operands.last.dump}")
                         end
                     }
-                    list << Instruction.new(codeOrigin, name, operands)
+                    list << Instruction.new(codeOrigin, name, operands, annotation)
                     if endOfSequence
                         break
                     end
diff --git a/Source/JavaScriptCore/offlineasm/registers.rb b/Source/JavaScriptCore/offlineasm/registers.rb
index 2c5a4eb..f062ae6 100644
--- a/Source/JavaScriptCore/offlineasm/registers.rb
+++ b/Source/JavaScriptCore/offlineasm/registers.rb
@@ -21,6 +21,8 @@
 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 # THE POSSIBILITY OF SUCH DAMAGE.
 
+require "config"
+
 GPRS =
     [
      "t0",
diff --git a/Source/JavaScriptCore/offlineasm/self_hash.rb b/Source/JavaScriptCore/offlineasm/self_hash.rb
index 2c300fc..b910573 100644
--- a/Source/JavaScriptCore/offlineasm/self_hash.rb
+++ b/Source/JavaScriptCore/offlineasm/self_hash.rb
@@ -21,6 +21,7 @@
 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 # THE POSSIBILITY OF SUCH DAMAGE.
 
+require "config"
 require "digest/sha1"
 require "pathname"
 
diff --git a/Source/JavaScriptCore/offlineasm/settings.rb b/Source/JavaScriptCore/offlineasm/settings.rb
index b7daa74..601934f 100644
--- a/Source/JavaScriptCore/offlineasm/settings.rb
+++ b/Source/JavaScriptCore/offlineasm/settings.rb
@@ -21,6 +21,7 @@
 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 # THE POSSIBILITY OF SUCH DAMAGE.
 
+require "config"
 require "ast"
 require "backends"
 require "parser"
diff --git a/Source/JavaScriptCore/offlineasm/transform.rb b/Source/JavaScriptCore/offlineasm/transform.rb
index 86c72be..a47ea0a 100644
--- a/Source/JavaScriptCore/offlineasm/transform.rb
+++ b/Source/JavaScriptCore/offlineasm/transform.rb
@@ -21,6 +21,7 @@
 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 # THE POSSIBILITY OF SUCH DAMAGE.
 
+require "config"
 require "ast"
 
 #
diff --git a/Source/JavaScriptCore/offlineasm/x86.rb b/Source/JavaScriptCore/offlineasm/x86.rb
index 383526b..470318a 100644
--- a/Source/JavaScriptCore/offlineasm/x86.rb
+++ b/Source/JavaScriptCore/offlineasm/x86.rb
@@ -21,6 +21,8 @@
 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 # THE POSSIBILITY OF SUCH DAMAGE.
 
+require "config"
+
 def isX64
     case $activeBackend
     when "X86"
@@ -353,7 +355,7 @@
                             operand
                         end
                     }
-                    newNode = Instruction.new(node.codeOrigin, node.opcode, newOperands)
+                    newNode = Instruction.new(node.codeOrigin, node.opcode, newOperands, node.annotation)
                 end
             else
                 unless node.is_a? Label or
@@ -622,7 +624,9 @@
     end
     
     def lowerX86Common
-        $asm.comment codeOriginString
+        $asm.codeOrigin codeOriginString
+        $asm.annotation annotation
+
         case opcode
         when "addi"
             handleX86Add(:int)