Add simple inline macros to js2c and use that for typed array constructors.
authordslomov@chromium.org <dslomov@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 5 Nov 2013 14:08:03 +0000 (14:08 +0000)
committerdslomov@chromium.org <dslomov@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 5 Nov 2013 14:08:03 +0000 (14:08 +0000)
R=yangguo@chromium.org

Review URL: https://codereview.chromium.org/44173003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17491 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/typedarray.js
tools/js2c.py [changed mode: 0644->0755]

index 1e67bc3..f2b5d2d 100644 (file)
@@ -34,59 +34,71 @@ var $ArrayBuffer = global.ArrayBuffer;
 
 
 // --------------- Typed Arrays ---------------------
-
-function CreateTypedArrayConstructor(name, elementSize, arrayId, constructor) {
-  function ConstructByArrayBuffer(obj, buffer, byteOffset, length) {
-    var offset = ToPositiveInteger(byteOffset, "invalid_typed_array_length")
-
-    if (offset % elementSize !== 0) {
-      throw MakeRangeError("invalid_typed_array_alignment",
-          "start offset", name, elementSize);
-    }
-    var bufferByteLength = %ArrayBufferGetByteLength(buffer);
-    if (offset > bufferByteLength) {
-      throw MakeRangeError("invalid_typed_array_offset");
-    }
-
-    var newByteLength;
-    var newLength;
-    if (IS_UNDEFINED(length)) {
-      if (bufferByteLength % elementSize !== 0) {
+macro TYPED_ARRAYS(FUNCTION)
+// arrayIds below should be synchronized with Runtime_TypedArrayInitialize.
+FUNCTION(1, Uint8Array, 1)
+FUNCTION(2, Int8Array, 1)
+FUNCTION(3, Uint16Array, 2)
+FUNCTION(4, Int16Array, 2)
+FUNCTION(5, Uint32Array, 4)
+FUNCTION(6, Int32Array, 4)
+FUNCTION(7, Float32Array, 4)
+FUNCTION(8, Float64Array, 8)
+FUNCTION(9, Uint8ClampedArray, 1)
+endmacro
+
+macro TYPED_ARRAY_CONSTRUCTOR(ARRAY_ID, NAME, ELEMENT_SIZE)
+  function NAMEConstructor(arg1, arg2, arg3) {
+    function ConstructByArrayBuffer(obj, buffer, byteOffset, length) {
+      var offset = ToPositiveInteger(byteOffset, "invalid_typed_array_length")
+
+      if (offset % ELEMENT_SIZE !== 0) {
         throw MakeRangeError("invalid_typed_array_alignment",
-          "byte length", name, elementSize);
+            "start offset", "NAME", ELEMENT_SIZE);
       }
-      newByteLength = bufferByteLength - offset;
-      newLength = newByteLength / elementSize;
-    } else {
-      var newLength = ToPositiveInteger(length, "invalid_typed_array_length");
-      newByteLength = newLength * elementSize;
-    }
-    if (offset + newByteLength > bufferByteLength) {
-      throw MakeRangeError("invalid_typed_array_length");
+      var bufferByteLength = %ArrayBufferGetByteLength(buffer);
+      if (offset > bufferByteLength) {
+        throw MakeRangeError("invalid_typed_array_offset");
+      }
+
+      var newByteLength;
+      var newLength;
+      if (IS_UNDEFINED(length)) {
+        if (bufferByteLength % ELEMENT_SIZE !== 0) {
+          throw MakeRangeError("invalid_typed_array_alignment",
+            "byte length", "NAME", ELEMENT_SIZE);
+        }
+        newByteLength = bufferByteLength - offset;
+        newLength = newByteLength / ELEMENT_SIZE;
+      } else {
+        var newLength = ToPositiveInteger(length, "invalid_typed_array_length");
+        newByteLength = newLength * ELEMENT_SIZE;
+      }
+      if (offset + newByteLength > bufferByteLength) {
+        throw MakeRangeError("invalid_typed_array_length");
+      }
+      %TypedArrayInitialize(obj, ARRAY_ID, buffer, offset, newByteLength);
     }
-    %TypedArrayInitialize(obj, arrayId, buffer, offset, newByteLength);
-  }
 
-  function ConstructByLength(obj, length) {
-    var l = ToPositiveInteger(length, "invalid_typed_array_length");
-    var byteLength = l * elementSize;
-    var buffer = new $ArrayBuffer(byteLength);
-    %TypedArrayInitialize(obj, arrayId, buffer, 0, byteLength);
-  }
+    function ConstructByLength(obj, length) {
+      var l = ToPositiveInteger(length, "invalid_typed_array_length");
+      var byteLength = l * ELEMENT_SIZE;
+      var buffer = new $ArrayBuffer(byteLength);
+      %TypedArrayInitialize(obj, ARRAY_ID, buffer, 0, byteLength);
+    }
 
-  function ConstructByArrayLike(obj, arrayLike) {
-    var length = arrayLike.length;
-    var l = ToPositiveInteger(length, "invalid_typed_array_length");
-    if(!%TypedArrayInitializeFromArrayLike(obj, arrayId, arrayLike, l)) {
-      for (var i = 0; i < l; i++) {
-        // It is crucial that we let any execptions from arrayLike[i]
-        // propagate outside the function.
-        obj[i] = arrayLike[i];
+    function ConstructByArrayLike(obj, arrayLike) {
+      var length = arrayLike.length;
+      var l = ToPositiveInteger(length, "invalid_typed_array_length");
+      if(!%TypedArrayInitializeFromArrayLike(obj, ARRAY_ID, arrayLike, l)) {
+        for (var i = 0; i < l; i++) {
+          // It is crucial that we let any execptions from arrayLike[i]
+          // propagate outside the function.
+          obj[i] = arrayLike[i];
+        }
       }
     }
-  }
 
-  return function (arg1, arg2, arg3) {
     if (%_IsConstructCall()) {
       if (IS_ARRAYBUFFER(arg1)) {
         ConstructByArrayBuffer(this, arg1, arg2, arg3);
@@ -97,10 +109,12 @@ function CreateTypedArrayConstructor(name, elementSize, arrayId, constructor) {
         ConstructByArrayLike(this, arg1);
       }
     } else {
-      throw MakeTypeError("constructor_not_function", [name])
+      throw MakeTypeError("constructor_not_function", ["NAME"])
     }
   }
-}
+endmacro
+
+TYPED_ARRAYS(TYPED_ARRAY_CONSTRUCTOR)
 
 function TypedArrayGetBuffer() {
   return %TypedArrayGetBuffer(this);
@@ -247,10 +261,8 @@ function TypedArraySet(obj, offset) {
 
 // -------------------------------------------------------------------
 
-function SetupTypedArray(arrayId, name, constructor, elementSize) {
+function SetupTypedArray(constructor, fun, elementSize) {
   %CheckIsBootstrapping();
-  var fun = CreateTypedArrayConstructor(name, elementSize,
-                                        arrayId, constructor);
   %SetCode(constructor, fun);
   %FunctionSetPrototype(constructor, new $Object());
 
@@ -272,17 +284,12 @@ function SetupTypedArray(arrayId, name, constructor, elementSize) {
   ));
 }
 
-// arrayIds below should be synchronized with Runtime_TypedArrayInitialize.
-SetupTypedArray(1, "Uint8Array", global.Uint8Array, 1);
-SetupTypedArray(2, "Int8Array", global.Int8Array, 1);
-SetupTypedArray(3, "Uint16Array", global.Uint16Array, 2);
-SetupTypedArray(4, "Int16Array", global.Int16Array, 2);
-SetupTypedArray(5, "Uint32Array", global.Uint32Array, 4);
-SetupTypedArray(6, "Int32Array", global.Int32Array, 4);
-SetupTypedArray(7, "Float32Array", global.Float32Array, 4);
-SetupTypedArray(8, "Float64Array", global.Float64Array, 8);
-SetupTypedArray(9, "Uint8ClampedArray", global.Uint8ClampedArray, 1);
 
+macro SETUP_TYPED_ARRAY(ARRAY_ID, NAME, ELEMENT_SIZE)
+  SetupTypedArray (global.NAME, NAMEConstructor, ELEMENT_SIZE);
+endmacro
+
+TYPED_ARRAYS(SETUP_TYPED_ARRAY)
 
 // --------------------------- DataView -----------------------------
 
old mode 100644 (file)
new mode 100755 (executable)
index 9492b00..f67d053
@@ -116,41 +116,47 @@ def ExpandConstants(lines, constants):
   return lines
 
 
+def ExpandMacroDefinition(lines, pos, name_pattern, macro, expander):
+  pattern_match = name_pattern.search(lines, pos)
+  while pattern_match is not None:
+    # Scan over the arguments
+    height = 1
+    start = pattern_match.start()
+    end = pattern_match.end()
+    assert lines[end - 1] == '('
+    last_match = end
+    arg_index = [0]  # Wrap state into array, to work around Python "scoping"
+    mapping = { }
+    def add_arg(str):
+      # Remember to expand recursively in the arguments
+      replacement = expander(str.strip())
+      mapping[macro.args[arg_index[0]]] = replacement
+      arg_index[0] += 1
+    while end < len(lines) and height > 0:
+      # We don't count commas at higher nesting levels.
+      if lines[end] == ',' and height == 1:
+        add_arg(lines[last_match:end])
+        last_match = end + 1
+      elif lines[end] in ['(', '{', '[']:
+        height = height + 1
+      elif lines[end] in [')', '}', ']']:
+        height = height - 1
+      end = end + 1
+    # Remember to add the last match.
+    add_arg(lines[last_match:end-1])
+    result = macro.expand(mapping)
+    # Replace the occurrence of the macro with the expansion
+    lines = lines[:start] + result + lines[end:]
+    pattern_match = name_pattern.search(lines, start + len(result))
+  return lines
+
 def ExpandMacros(lines, macros):
   # We allow macros to depend on the previously declared macros, but
   # we don't allow self-dependecies or recursion.
   for name_pattern, macro in reversed(macros):
-    pattern_match = name_pattern.search(lines, 0)
-    while pattern_match is not None:
-      # Scan over the arguments
-      height = 1
-      start = pattern_match.start()
-      end = pattern_match.end()
-      assert lines[end - 1] == '('
-      last_match = end
-      arg_index = [0]  # Wrap state into array, to work around Python "scoping"
-      mapping = { }
-      def add_arg(str):
-        # Remember to expand recursively in the arguments
-        replacement = ExpandMacros(str.strip(), macros)
-        mapping[macro.args[arg_index[0]]] = replacement
-        arg_index[0] += 1
-      while end < len(lines) and height > 0:
-        # We don't count commas at higher nesting levels.
-        if lines[end] == ',' and height == 1:
-          add_arg(lines[last_match:end])
-          last_match = end + 1
-        elif lines[end] in ['(', '{', '[']:
-          height = height + 1
-        elif lines[end] in [')', '}', ']']:
-          height = height - 1
-        end = end + 1
-      # Remember to add the last match.
-      add_arg(lines[last_match:end-1])
-      result = macro.expand(mapping)
-      # Replace the occurrence of the macro with the expansion
-      lines = lines[:start] + result + lines[end:]
-      pattern_match = name_pattern.search(lines, start + len(result))
+    def expander(s):
+      return ExpandMacros(s, macros)
+    lines = ExpandMacroDefinition(lines, 0, name_pattern, macro, expander)
   return lines
 
 class TextMacro:
@@ -210,6 +216,34 @@ def ReadMacros(lines):
           raise ("Illegal line: " + line)
   return (constants, macros)
 
+INLINE_MACRO_PATTERN = re.compile(r'macro\s+([a-zA-Z0-9_]+)\s*\(([^)]*)\)\s*\n')
+INLINE_MACRO_END_PATTERN = re.compile(r'endmacro\s*\n')
+
+def ExpandInlineMacros(lines, filename):
+  pos = 0
+  while True:
+    macro_match = INLINE_MACRO_PATTERN.search(lines, pos)
+    if macro_match is None:
+      # no more macros
+      return lines
+    name = macro_match.group(1)
+    args = [match.strip() for match in macro_match.group(2).split(',')]
+    end_macro_match = INLINE_MACRO_END_PATTERN.search(lines, macro_match.end());
+    if end_macro_match is None:
+      raise ("Macro %s unclosed in %s" % (name, filename))
+    body = lines[macro_match.end():end_macro_match.start()]
+
+    # remove macro definition
+    lines = lines[:macro_match.start()] + lines[end_macro_match.end():]
+    name_pattern = re.compile("\\b%s\\(" % name)
+    macro = TextMacro(args, body)
+
+    # advance position to where the macro defintion was
+    pos = macro_match.start()
+
+    def non_expander(s):
+      return s
+    lines = ExpandMacroDefinition(lines, pos, name_pattern, macro, non_expander)
 
 HEADER_TEMPLATE = """\
 // Copyright 2011 Google Inc. All Rights Reserved.
@@ -325,6 +359,8 @@ def JS2C(source, target, env):
     lines = ReadFile(filename)
     lines = ExpandConstants(lines, consts)
     lines = ExpandMacros(lines, macros)
+    lines = RemoveCommentsAndTrailingWhitespace(lines)
+    lines = ExpandInlineMacros(lines, filename)
     Validate(lines, filename)
     lines = minifier.JSMinify(lines)
     id = (os.path.split(filename)[1])[:-3]