[vm/tools] Update python scripts to avoid quadratic string concat.

Change-Id: Id675c6b804be6c4df5849ea9c0c2c1d6d3377868
Reviewed-on: https://dart-review.googlesource.com/c/88707
Commit-Queue: Vyacheslav Egorov <vegorov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
diff --git a/runtime/tools/create_archive.py b/runtime/tools/create_archive.py
index ebad9c9..fafbcfe 100755
--- a/runtime/tools/create_archive.py
+++ b/runtime/tools/create_archive.py
@@ -76,13 +76,14 @@
                 name,
                 tar_archive,
                 ):
-  cc_text = '''
+  with open(output_file, 'w') as out:
+    out.write('''
 // Copyright (c) %d, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-''' % date.today().year
-  cc_text += '''
+''' % date.today().year)
+    out.write('''
 
 #if defined(_WIN32)
 typedef unsigned __int8 uint8_t;
@@ -92,31 +93,31 @@
 #endif
 #include <stddef.h>
 
-'''
-  cc_text += 'namespace %s {\n' % outer_namespace
-  if inner_namespace != None:
-    cc_text += 'namespace %s {\n' % inner_namespace
-  cc_text += '\n\n'
-  # Write the archive.
-  cc_text += 'static const uint8_t %s_[] = {\n   ' % name
-  lineCounter = 0
-  for byte in tar_archive:
-    cc_text += r" %d," % ord(byte)
-    lineCounter += 1
-    if lineCounter == 10:
-      cc_text += '\n   '
-      lineCounter = 0
-  if lineCounter != 0:
-    cc_text += '\n   '
-  cc_text += '\n};\n'
-  cc_text += '\nunsigned int %s_len = %d;\n' % (name, len(tar_archive))
-  cc_text += '\nconst uint8_t* %s = %s_;\n\n' % (name, name)
-  if inner_namespace != None:
-    cc_text += '}  // namespace %s\n' % inner_namespace
-  cc_text += '} // namespace %s\n' % outer_namespace
-
-  open(output_file, 'w').write(cc_text)
-
+''')
+    out.write('namespace %s {\n' % outer_namespace)
+    if inner_namespace != None:
+      out.write('namespace %s {\n' % inner_namespace)
+    out.write('\n\n')
+    # Write the byte contents of the archive as a comma separated list of
+    # integers, one integer for each byte.
+    out.write('static const uint8_t %s_[] = {\n' % name)
+    line = '   '
+    lineCounter = 0
+    for byte in tar_archive:
+      line += r" %d," % ord(byte)
+      lineCounter += 1
+      if lineCounter == 10:
+        out.write(line + '\n')
+        line = '   '
+        lineCounter = 0
+    if lineCounter != 0:
+      out.write(line + '\n')
+    out.write('};\n')
+    out.write('\nunsigned int %s_len = %d;\n' % (name, len(tar_archive)))
+    out.write('\nconst uint8_t* %s = %s_;\n\n' % (name, name))
+    if inner_namespace != None:
+      out.write('}  // namespace %s\n' % inner_namespace)
+    out.write('} // namespace %s\n' % outer_namespace)
 
 def MakeCCFile(options):
   if not options.output:
diff --git a/runtime/tools/create_snapshot_file.py b/runtime/tools/create_snapshot_file.py
index d31cc06..d862a45 100755
--- a/runtime/tools/create_snapshot_file.py
+++ b/runtime/tools/create_snapshot_file.py
@@ -4,14 +4,15 @@
 # for details. All rights reserved. Use of this source code is governed by a
 # BSD-style license that can be found in the LICENSE file.
 
-# Script to create snapshot files.
+# Script to convert snapshot files to a C++ file which can be compiled and
+# linked together with VM binary.
 
 import getopt
 import optparse
 import string
 import subprocess
 import sys
-import utils
+import google3.third_party.dart_lang.v2_1_1_dev_0_1.runtime.tools.utils as utils
 
 
 HOST_OS = utils.GuessOS()
@@ -54,28 +55,46 @@
   return True
 
 
-def makeString(input_file):
-  result = ' '
-  fileHandle = open(input_file, 'rb')
-  lineCounter = 0
-  for byte in fileHandle.read():
-    result += ' %d,' % ord(byte)
-    lineCounter += 1
-    if lineCounter == 10:
-      result += '\n   '
-      lineCounter = 0
-  if lineCounter != 0:
-    result += '\n   '
-  return result
+def WriteBytesAsText(out, input_file):
+  """Writes byte contents of the input_file into out file as text.
+
+  Output is formatted as a list of comma separated integer values - one value
+  for each byte.
+  """
+  with open(input_file, 'rb') as input:
+    lineCounter = 0
+    line = ' '
+    for byte in input.read():
+      line += ' %d,' % ord(byte)
+      lineCounter += 1
+      if lineCounter == 10:
+        out.write(line + '\n')
+        line = ' '
+        lineCounter = 0
+    if lineCounter != 0:
+      out.write(line + '\n')
 
 
-def makeFile(output_file, input_cc_file,
+def GenerateFileFromTemplate(output_file, input_cc_file,
              vm_isolate_input_file, isolate_input_file):
+  """Generates C++ file based on a input_cc_file template and two binary files
+
+  Template is expected to have two %s placehoders which would be filled
+  with binary contents of the given files each formatted as a comma separated
+  list of integers.
+  """
   snapshot_cc_text = open(input_cc_file).read()
-  snapshot_cc_text = snapshot_cc_text % (makeString(vm_isolate_input_file),
-                                         makeString(isolate_input_file))
-  open(output_file, 'w').write(snapshot_cc_text)
-  return True
+  chunks = snapshot_cc_text.split("%s")
+  if len(chunks) != 3:
+    raise Exception("Template %s should contain exactly two %%s occurrences"
+        % input_cc_file)
+
+  with open(output_file, 'w') as out:
+    out.write(chunks[0])
+    WriteBytesAsText(out, vm_isolate_input_file)
+    out.write(chunks[1])
+    WriteBytesAsText(out, isolate_input_file)
+    out.write(chunks[2])
 
 
 def Main():
@@ -91,10 +110,8 @@
     parser.print_help()
     return 1
 
-  if not makeFile(options.output, options.input_cc,
-                  options.vm_input_bin, options.input_bin):
-    print "Unable to generate snapshot in C buffer form"
-    return -1
+  GenerateFileFromTemplate(options.output, options.input_cc,
+                           options.vm_input_bin, options.input_bin)
 
   return 0