offlineasm: fix macro scoping
https://bugs.webkit.org/show_bug.cgi?id=189902

Reviewed by Mark Lam.

In the code below, the reference to `f` in `g`, which should refer to
the outer macro definition will instead refer to the f argument of the
anonymous macro passed to `g`. That leads to this code failing to
compile (f expected 0 args but got 1).

```
macro f(x)
    move x, t0
end

macro g(fn)
    fn(macro () f(42) end)
end

g(macro(f) f() end)
```

* offlineasm/ast.rb:
* offlineasm/transform.rb:


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@236434 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 14c340f..a5eccf3 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,5 +1,32 @@
 2018-09-24  Tadeu Zagallo  <tzagallo@apple.com>
 
+        offlineasm: fix macro scoping
+        https://bugs.webkit.org/show_bug.cgi?id=189902
+
+        Reviewed by Mark Lam.
+
+        In the code below, the reference to `f` in `g`, which should refer to
+        the outer macro definition will instead refer to the f argument of the
+        anonymous macro passed to `g`. That leads to this code failing to
+        compile (f expected 0 args but got 1).
+        
+        ```
+        macro f(x)
+            move x, t0
+        end
+        
+        macro g(fn)
+            fn(macro () f(42) end)
+        end
+        
+        g(macro(f) f() end)
+        ```
+
+        * offlineasm/ast.rb:
+        * offlineasm/transform.rb:
+
+2018-09-24  Tadeu Zagallo  <tzagallo@apple.com>
+
         Add forEach method for iterating CodeBlock's ValueProfiles
         https://bugs.webkit.org/show_bug.cgi?id=189897
 
diff --git a/Source/JavaScriptCore/offlineasm/ast.rb b/Source/JavaScriptCore/offlineasm/ast.rb
index 0ccf7b3..bfe866b 100644
--- a/Source/JavaScriptCore/offlineasm/ast.rb
+++ b/Source/JavaScriptCore/offlineasm/ast.rb
@@ -727,26 +727,31 @@
 class Variable < NoChildren
     attr_reader :name
     
-    def initialize(codeOrigin, name)
+    def initialize(codeOrigin, name, originalName = nil)
         super(codeOrigin)
         @name = name
+        @originalName = originalName
     end
     
     @@mapping = {}
     
-    def self.forName(codeOrigin, name)
+    def self.forName(codeOrigin, name, originalName = nil)
         unless @@mapping[name]
-            @@mapping[name] = Variable.new(codeOrigin, name)
+            @@mapping[name] = Variable.new(codeOrigin, name, originalName)
         end
         @@mapping[name]
     end
+
+    def originalName
+        @originalName || name
+    end
     
     def dump
-        name
+        originalName
     end
     
     def inspect
-        "<variable #{name} at #{codeOriginString}>"
+        "<variable #{originalName} at #{codeOriginString}>"
     end
 end
 
@@ -1455,13 +1460,18 @@
 class MacroCall < Node
     attr_reader :name, :operands, :annotation
     
-    def initialize(codeOrigin, name, operands, annotation)
+    def initialize(codeOrigin, name, operands, annotation, originalName = nil)
         super(codeOrigin)
         @name = name
         @operands = operands
         raise unless @operands
         @operands.each{|v| raise unless v}
         @annotation = annotation
+        @originalName = originalName
+    end
+
+    def originalName
+        @originalName || name
     end
     
     def children
@@ -1469,11 +1479,11 @@
     end
     
     def mapChildren(&proc)
-        MacroCall.new(codeOrigin, @name, @operands.map(&proc), @annotation)
+        MacroCall.new(codeOrigin, @name, @operands.map(&proc), @annotation, @originalName)
     end
     
     def dump
-        "\t#{name}(" + operands.collect{|v| v.dump}.join(", ") + ")"
+        "\t#{originalName}(" + operands.collect{|v| v.dump}.join(", ") + ")"
     end
 end
 
diff --git a/Source/JavaScriptCore/offlineasm/transform.rb b/Source/JavaScriptCore/offlineasm/transform.rb
index 2a08255..75a4b34 100644
--- a/Source/JavaScriptCore/offlineasm/transform.rb
+++ b/Source/JavaScriptCore/offlineasm/transform.rb
@@ -134,7 +134,20 @@
     end
 end
 
+$uniqueMacroVarID = 0
 class Macro
+    def capture
+        mapping = {}
+        newVars = []
+        variables.each do |var|
+            $uniqueMacroVarID += 1
+            newVar = Variable.forName(var.codeOrigin, "_var#{$uniqueMacroVarID}", var.originalName)
+            newVars << newVar
+            mapping[var] = newVar
+        end
+        Macro.new(codeOrigin, name, newVars, body.substitute(mapping))
+    end
+
     def substitute(mapping)
         myMapping = {}
         mapping.each_pair {
@@ -150,6 +163,17 @@
     end
 end
 
+class MacroCall
+    def substitute(mapping)
+        newName = Variable.forName(codeOrigin, name)
+        if mapping[newName]
+            newName = mapping[newName]
+        end
+        newOperands = operands.map { |operand| operand.substitute(mapping) }
+        MacroCall.new(codeOrigin, newName.name, newOperands, annotation, originalName)
+    end
+end
+
 class Variable
     def substitute(mapping)
         if mapping[self]
@@ -203,7 +227,7 @@
         @list.each {
             | item |
             if item.is_a? Macro
-                myMacros[item.name] = item
+                myMacros[item.name] = item.capture
             end
         }
         newList = []
@@ -214,15 +238,15 @@
             elsif item.is_a? MacroCall
                 mapping = {}
                 myMyMacros = myMacros.dup
-                raise "Could not find macro #{item.name} at #{item.codeOriginString}" unless myMacros[item.name]
-                raise "Argument count mismatch for call to #{item.name} at #{item.codeOriginString}" unless item.operands.size == myMacros[item.name].variables.size
+                raise "Could not find macro #{item.originalName} at #{item.codeOriginString}" unless myMacros[item.name]
+                raise "Argument count mismatch for call to #{item.originalName} at #{item.codeOriginString}" unless item.operands.size == myMacros[item.name].variables.size
                 item.operands.size.times {
                     | idx |
                     if item.operands[idx].is_a? Variable and myMacros[item.operands[idx].name]
                         myMyMacros[myMacros[item.name].variables[idx].name] = myMacros[item.operands[idx].name]
                         mapping[myMacros[item.name].variables[idx].name] = nil
                     elsif item.operands[idx].is_a? Macro
-                        myMyMacros[myMacros[item.name].variables[idx].name] = item.operands[idx]
+                        myMyMacros[myMacros[item.name].variables[idx].name] = item.operands[idx].capture
                         mapping[myMacros[item.name].variables[idx].name] = nil
                     else
                         myMyMacros[myMacros[item.name].variables[idx]] = nil
@@ -232,7 +256,7 @@
                 if item.annotation
                     newList << Instruction.new(item.codeOrigin, "localAnnotation", [], item.annotation)
                 end
-                newList += myMacros[item.name].body.substitute(mapping).demacroify(myMyMacros).renameLabels(item.name).list
+                newList += myMacros[item.name].body.substitute(mapping).demacroify(myMyMacros).renameLabels(item.originalName).list
             else
                 newList << item.demacroify(myMacros)
             end