aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2011-05-25 10:26:03 +0100
committerBen Murdoch <benm@google.com>2011-05-25 16:24:42 +0100
commite0cee9b3ed82e2391fd85d118aeaa4ea361c687d (patch)
tree31c7963cf0dfc88be29e765884e1f235076c03a4 /tools
parent1e0659c275bb392c045087af4f6b0d7565cb3d77 (diff)
downloadv8-e0cee9b3ed82e2391fd85d118aeaa4ea361c687d.tar.gz
Update V8 to r7079 as required by WebKit r80534.
Change-Id: I487c152e485d5a40b68997d7c0d2f1fba5da0834
Diffstat (limited to 'tools')
-rw-r--r--tools/disasm.py92
-rwxr-xr-xtools/grokdump.py840
-rw-r--r--tools/gyp/v8.gyp2
-rwxr-xr-xtools/linux-tick-processor.py78
-rwxr-xr-xtools/ll_prof.py82
-rw-r--r--tools/profile.js141
-rw-r--r--tools/splaytree.py226
-rw-r--r--tools/tickprocessor.js75
-rw-r--r--tools/tickprocessor.py571
-rw-r--r--tools/utils.py2
-rw-r--r--tools/v8.xcodeproj/project.pbxproj6
-rw-r--r--tools/visual_studio/x64.vsprops1
-rwxr-xr-xtools/windows-tick-processor.py137
13 files changed, 1111 insertions, 1142 deletions
diff --git a/tools/disasm.py b/tools/disasm.py
new file mode 100644
index 00000000..c326382d
--- /dev/null
+++ b/tools/disasm.py
@@ -0,0 +1,92 @@
+#!/usr/bin/env python
+#
+# Copyright 2011 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER OR 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.
+
+import os
+import re
+import subprocess
+import tempfile
+
+
+# Avoid using the slow (google-specific) wrapper around objdump.
+OBJDUMP_BIN = "/usr/bin/objdump"
+if not os.path.exists(OBJDUMP_BIN):
+ OBJDUMP_BIN = "objdump"
+
+
+_COMMON_DISASM_OPTIONS = ["-M", "intel-mnemonic", "-C"]
+
+_DISASM_HEADER_RE = re.compile(r"[a-f0-9]+\s+<.*:$")
+_DISASM_LINE_RE = re.compile(r"\s*([a-f0-9]+):\s*(\S.*)")
+
+# Keys must match constants in Logger::LogCodeInfo.
+_ARCH_MAP = {
+ "ia32": "-m i386",
+ "x64": "-m i386 -M x86-64",
+ "arm": "-m arm" # Not supported by our objdump build.
+}
+
+
+def GetDisasmLines(filename, offset, size, arch, inplace):
+ tmp_name = None
+ if not inplace:
+ # Create a temporary file containing a copy of the code.
+ assert arch in _ARCH_MAP, "Unsupported architecture '%s'" % arch
+ arch_flags = _ARCH_MAP[arch]
+ tmp_name = tempfile.mktemp(".v8code")
+ command = "dd if=%s of=%s bs=1 count=%d skip=%d && " \
+ "%s %s -D -b binary %s %s" % (
+ filename, tmp_name, size, offset,
+ OBJDUMP_BIN, ' '.join(_COMMON_DISASM_OPTIONS), arch_flags,
+ tmp_name)
+ else:
+ command = "%s %s --start-address=%d --stop-address=%d -d %s " % (
+ OBJDUMP_BIN, ' '.join(_COMMON_DISASM_OPTIONS),
+ offset,
+ offset + size,
+ filename)
+ process = subprocess.Popen(command,
+ shell=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ out, err = process.communicate()
+ lines = out.split("\n")
+ header_line = 0
+ for i, line in enumerate(lines):
+ if _DISASM_HEADER_RE.match(line):
+ header_line = i
+ break
+ if tmp_name:
+ os.unlink(tmp_name)
+ split_lines = []
+ for line in lines[header_line + 1:]:
+ match = _DISASM_LINE_RE.match(line)
+ if match:
+ line_address = int(match.group(1), 16)
+ split_lines.append((line_address, match.group(2)))
+ return split_lines
diff --git a/tools/grokdump.py b/tools/grokdump.py
new file mode 100755
index 00000000..de681b2b
--- /dev/null
+++ b/tools/grokdump.py
@@ -0,0 +1,840 @@
+#!/usr/bin/env python
+#
+# Copyright 2011 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER OR 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.
+
+import ctypes
+import mmap
+import optparse
+import os
+import disasm
+import sys
+import types
+import codecs
+import re
+
+
+USAGE="""usage: %prog [OPTION]...
+
+Minidump analyzer.
+
+Shows the processor state at the point of exception including the
+stack of the active thread and the referenced objects in the V8
+heap. Code objects are disassembled and the addresses linked from the
+stack (pushed return addresses) are marked with "=>".
+
+
+Examples:
+ $ %prog 12345678-1234-1234-1234-123456789abcd-full.dmp
+"""
+
+DEBUG=False
+
+
+def DebugPrint(s):
+ if not DEBUG: return
+ print s
+
+
+class Descriptor(object):
+ """Descriptor of a structure in a memory."""
+
+ def __init__(self, fields):
+ self.fields = fields
+ self.is_flexible = False
+ for _, type_or_func in fields:
+ if isinstance(type_or_func, types.FunctionType):
+ self.is_flexible = True
+ break
+ if not self.is_flexible:
+ self.ctype = Descriptor._GetCtype(fields)
+ self.size = ctypes.sizeof(self.ctype)
+
+ def Read(self, memory, offset):
+ if self.is_flexible:
+ fields_copy = self.fields[:]
+ last = 0
+ for name, type_or_func in fields_copy:
+ if isinstance(type_or_func, types.FunctionType):
+ partial_ctype = Descriptor._GetCtype(fields_copy[:last])
+ partial_object = partial_ctype.from_buffer(memory, offset)
+ type = type_or_func(partial_object)
+ if type is not None:
+ fields_copy[last] = (name, type)
+ last += 1
+ else:
+ last += 1
+ complete_ctype = Descriptor._GetCtype(fields_copy[:last])
+ else:
+ complete_ctype = self.ctype
+ return complete_ctype.from_buffer(memory, offset)
+
+ @staticmethod
+ def _GetCtype(fields):
+ class Raw(ctypes.Structure):
+ _fields_ = fields
+ _pack_ = 1
+
+ def __str__(self):
+ return "{" + ", ".join("%s: %s" % (field, self.__getattribute__(field))
+ for field, _ in Raw._fields_) + "}"
+ return Raw
+
+
+# Set of structures and constants that describe the layout of minidump
+# files. Based on MSDN and Google Breakpad.
+
+MINIDUMP_HEADER = Descriptor([
+ ("signature", ctypes.c_uint32),
+ ("version", ctypes.c_uint32),
+ ("stream_count", ctypes.c_uint32),
+ ("stream_directories_rva", ctypes.c_uint32),
+ ("checksum", ctypes.c_uint32),
+ ("time_date_stampt", ctypes.c_uint32),
+ ("flags", ctypes.c_uint64)
+])
+
+MINIDUMP_LOCATION_DESCRIPTOR = Descriptor([
+ ("data_size", ctypes.c_uint32),
+ ("rva", ctypes.c_uint32)
+])
+
+MINIDUMP_DIRECTORY = Descriptor([
+ ("stream_type", ctypes.c_uint32),
+ ("location", MINIDUMP_LOCATION_DESCRIPTOR.ctype)
+])
+
+MD_EXCEPTION_MAXIMUM_PARAMETERS = 15
+
+MINIDUMP_EXCEPTION = Descriptor([
+ ("code", ctypes.c_uint32),
+ ("flags", ctypes.c_uint32),
+ ("record", ctypes.c_uint64),
+ ("address", ctypes.c_uint64),
+ ("parameter_count", ctypes.c_uint32),
+ ("unused_alignment", ctypes.c_uint32),
+ ("information", ctypes.c_uint64 * MD_EXCEPTION_MAXIMUM_PARAMETERS)
+])
+
+MINIDUMP_EXCEPTION_STREAM = Descriptor([
+ ("thread_id", ctypes.c_uint32),
+ ("unused_alignment", ctypes.c_uint32),
+ ("exception", MINIDUMP_EXCEPTION.ctype),
+ ("thread_context", MINIDUMP_LOCATION_DESCRIPTOR.ctype)
+])
+
+# Stream types.
+MD_UNUSED_STREAM = 0
+MD_RESERVED_STREAM_0 = 1
+MD_RESERVED_STREAM_1 = 2
+MD_THREAD_LIST_STREAM = 3
+MD_MODULE_LIST_STREAM = 4
+MD_MEMORY_LIST_STREAM = 5
+MD_EXCEPTION_STREAM = 6
+MD_SYSTEM_INFO_STREAM = 7
+MD_THREAD_EX_LIST_STREAM = 8
+MD_MEMORY_64_LIST_STREAM = 9
+MD_COMMENT_STREAM_A = 10
+MD_COMMENT_STREAM_W = 11
+MD_HANDLE_DATA_STREAM = 12
+MD_FUNCTION_TABLE_STREAM = 13
+MD_UNLOADED_MODULE_LIST_STREAM = 14
+MD_MISC_INFO_STREAM = 15
+MD_MEMORY_INFO_LIST_STREAM = 16
+MD_THREAD_INFO_LIST_STREAM = 17
+MD_HANDLE_OPERATION_LIST_STREAM = 18
+
+MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE = 80
+
+MINIDUMP_FLOATING_SAVE_AREA_X86 = Descriptor([
+ ("control_word", ctypes.c_uint32),
+ ("status_word", ctypes.c_uint32),
+ ("tag_word", ctypes.c_uint32),
+ ("error_offset", ctypes.c_uint32),
+ ("error_selector", ctypes.c_uint32),
+ ("data_offset", ctypes.c_uint32),
+ ("data_selector", ctypes.c_uint32),
+ ("register_area", ctypes.c_uint8 * MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE),
+ ("cr0_npx_state", ctypes.c_uint32)
+])
+
+MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE = 512
+
+# Context flags.
+MD_CONTEXT_X86 = 0x00010000
+MD_CONTEXT_X86_CONTROL = (MD_CONTEXT_X86 | 0x00000001)
+MD_CONTEXT_X86_INTEGER = (MD_CONTEXT_X86 | 0x00000002)
+MD_CONTEXT_X86_SEGMENTS = (MD_CONTEXT_X86 | 0x00000004)
+MD_CONTEXT_X86_FLOATING_POINT = (MD_CONTEXT_X86 | 0x00000008)
+MD_CONTEXT_X86_DEBUG_REGISTERS = (MD_CONTEXT_X86 | 0x00000010)
+MD_CONTEXT_X86_EXTENDED_REGISTERS = (MD_CONTEXT_X86 | 0x00000020)
+
+def EnableOnFlag(type, flag):
+ return lambda o: [None, type][int((o.context_flags & flag) != 0)]
+
+MINIDUMP_CONTEXT_X86 = Descriptor([
+ ("context_flags", ctypes.c_uint32),
+ # MD_CONTEXT_X86_DEBUG_REGISTERS.
+ ("dr0", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
+ ("dr1", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
+ ("dr2", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
+ ("dr3", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
+ ("dr6", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
+ ("dr7", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
+ # MD_CONTEXT_X86_FLOATING_POINT.
+ ("float_save", EnableOnFlag(MINIDUMP_FLOATING_SAVE_AREA_X86.ctype,
+ MD_CONTEXT_X86_FLOATING_POINT)),
+ # MD_CONTEXT_X86_SEGMENTS.
+ ("gs", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)),
+ ("fs", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)),
+ ("es", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)),
+ ("ds", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)),
+ # MD_CONTEXT_X86_INTEGER.
+ ("edi", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
+ ("esi", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
+ ("ebx", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
+ ("edx", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
+ ("ecx", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
+ ("eax", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
+ # MD_CONTEXT_X86_CONTROL.
+ ("ebp", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
+ ("eip", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
+ ("cs", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
+ ("eflags", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
+ ("esp", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
+ ("ss", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
+ # MD_CONTEXT_X86_EXTENDED_REGISTERS.
+ ("extended_registers",
+ EnableOnFlag(ctypes.c_uint8 * MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE,
+ MD_CONTEXT_X86_EXTENDED_REGISTERS))
+])
+
+MINIDUMP_MEMORY_DESCRIPTOR = Descriptor([
+ ("start", ctypes.c_uint64),
+ ("memory", MINIDUMP_LOCATION_DESCRIPTOR.ctype)
+])
+
+MINIDUMP_MEMORY_DESCRIPTOR64 = Descriptor([
+ ("start", ctypes.c_uint64),
+ ("size", ctypes.c_uint64)
+])
+
+MINIDUMP_MEMORY_LIST = Descriptor([
+ ("range_count", ctypes.c_uint32),
+ ("ranges", lambda m: MINIDUMP_MEMORY_DESCRIPTOR.ctype * m.range_count)
+])
+
+MINIDUMP_MEMORY_LIST64 = Descriptor([
+ ("range_count", ctypes.c_uint64),
+ ("base_rva", ctypes.c_uint64),
+ ("ranges", lambda m: MINIDUMP_MEMORY_DESCRIPTOR64.ctype * m.range_count)
+])
+
+MINIDUMP_THREAD = Descriptor([
+ ("id", ctypes.c_uint32),
+ ("suspend_count", ctypes.c_uint32),
+ ("priority_class", ctypes.c_uint32),
+ ("priority", ctypes.c_uint32),
+ ("ted", ctypes.c_uint64),
+ ("stack", MINIDUMP_MEMORY_DESCRIPTOR.ctype),
+ ("context", MINIDUMP_LOCATION_DESCRIPTOR.ctype)
+])
+
+MINIDUMP_THREAD_LIST = Descriptor([
+ ("thread_count", ctypes.c_uint32),
+ ("threads", lambda t: MINIDUMP_THREAD.ctype * t.thread_count)
+])
+
+
+class MinidumpReader(object):
+ """Minidump (.dmp) reader."""
+
+ _HEADER_MAGIC = 0x504d444d
+
+ def __init__(self, options, minidump_name):
+ self.minidump_name = minidump_name
+ self.minidump_file = open(minidump_name, "r")
+ self.minidump = mmap.mmap(self.minidump_file.fileno(), 0, mmap.MAP_PRIVATE)
+ self.header = MINIDUMP_HEADER.Read(self.minidump, 0)
+ if self.header.signature != MinidumpReader._HEADER_MAGIC:
+ print >>sys.stderr, "Warning: unsupported minidump header magic"
+ DebugPrint(self.header)
+ directories = []
+ offset = self.header.stream_directories_rva
+ for _ in xrange(self.header.stream_count):
+ directories.append(MINIDUMP_DIRECTORY.Read(self.minidump, offset))
+ offset += MINIDUMP_DIRECTORY.size
+ self.exception = None
+ self.exception_context = None
+ self.memory_list = None
+ self.thread_map = {}
+ for d in directories:
+ DebugPrint(d)
+ # TODO(vitalyr): extract system info including CPU features.
+ if d.stream_type == MD_EXCEPTION_STREAM:
+ self.exception = MINIDUMP_EXCEPTION_STREAM.Read(
+ self.minidump, d.location.rva)
+ DebugPrint(self.exception)
+ self.exception_context = MINIDUMP_CONTEXT_X86.Read(
+ self.minidump, self.exception.thread_context.rva)
+ DebugPrint(self.exception_context)
+ elif d.stream_type == MD_THREAD_LIST_STREAM:
+ thread_list = MINIDUMP_THREAD_LIST.Read(self.minidump, d.location.rva)
+ assert ctypes.sizeof(thread_list) == d.location.data_size
+ DebugPrint(thread_list)
+ for thread in thread_list.threads:
+ DebugPrint(thread)
+ self.thread_map[thread.id] = thread
+ elif d.stream_type == MD_MEMORY_LIST_STREAM:
+ print >>sys.stderr, "Warning: not a full minidump"
+ ml = MINIDUMP_MEMORY_LIST.Read(self.minidump, d.location.rva)
+ DebugPrint(ml)
+ for m in ml.ranges:
+ DebugPrint(m)
+ elif d.stream_type == MD_MEMORY_64_LIST_STREAM:
+ assert self.memory_list is None
+ self.memory_list = MINIDUMP_MEMORY_LIST64.Read(
+ self.minidump, d.location.rva)
+ assert ctypes.sizeof(self.memory_list) == d.location.data_size
+ DebugPrint(self.memory_list)
+
+ def IsValidAddress(self, address):
+ return self.FindLocation(address) is not None
+
+ def ReadU8(self, address):
+ location = self.FindLocation(address)
+ return ctypes.c_uint8.from_buffer(self.minidump, location).value
+
+ def ReadU32(self, address):
+ location = self.FindLocation(address)
+ return ctypes.c_uint32.from_buffer(self.minidump, location).value
+
+ def ReadBytes(self, address, size):
+ location = self.FindLocation(address)
+ return self.minidump[location:location + size]
+
+ def FindLocation(self, address):
+ # TODO(vitalyr): only works for full minidumps (...64 structure variants).
+ offset = 0
+ for r in self.memory_list.ranges:
+ if r.start <= address < r.start + r.size:
+ return self.memory_list.base_rva + offset + address - r.start
+ offset += r.size
+ return None
+
+ def GetDisasmLines(self, address, size):
+ location = self.FindLocation(address)
+ if location is None: return []
+ return disasm.GetDisasmLines(self.minidump_name,
+ location,
+ size,
+ "ia32",
+ False)
+
+
+ def Dispose(self):
+ self.minidump.close()
+ self.minidump_file.close()
+
+
+# List of V8 instance types. Obtained by adding the code below to any .cc file.
+#
+# #define DUMP_TYPE(T) printf("%d: \"%s\",\n", T, #T);
+# struct P {
+# P() {
+# printf("{\n");
+# INSTANCE_TYPE_LIST(DUMP_TYPE)
+# printf("}\n");
+# }
+# };
+# static P p;
+INSTANCE_TYPES = {
+ 64: "SYMBOL_TYPE",
+ 68: "ASCII_SYMBOL_TYPE",
+ 65: "CONS_SYMBOL_TYPE",
+ 69: "CONS_ASCII_SYMBOL_TYPE",
+ 66: "EXTERNAL_SYMBOL_TYPE",
+ 74: "EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE",
+ 70: "EXTERNAL_ASCII_SYMBOL_TYPE",
+ 0: "STRING_TYPE",
+ 4: "ASCII_STRING_TYPE",
+ 1: "CONS_STRING_TYPE",
+ 5: "CONS_ASCII_STRING_TYPE",
+ 2: "EXTERNAL_STRING_TYPE",
+ 10: "EXTERNAL_STRING_WITH_ASCII_DATA_TYPE",
+ 6: "EXTERNAL_ASCII_STRING_TYPE",
+ 6: "PRIVATE_EXTERNAL_ASCII_STRING_TYPE",
+ 128: "MAP_TYPE",
+ 129: "CODE_TYPE",
+ 130: "ODDBALL_TYPE",
+ 131: "JS_GLOBAL_PROPERTY_CELL_TYPE",
+ 132: "HEAP_NUMBER_TYPE",
+ 133: "PROXY_TYPE",
+ 134: "BYTE_ARRAY_TYPE",
+ 135: "PIXEL_ARRAY_TYPE",
+ 136: "EXTERNAL_BYTE_ARRAY_TYPE",
+ 137: "EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE",
+ 138: "EXTERNAL_SHORT_ARRAY_TYPE",
+ 139: "EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE",
+ 140: "EXTERNAL_INT_ARRAY_TYPE",
+ 141: "EXTERNAL_UNSIGNED_INT_ARRAY_TYPE",
+ 142: "EXTERNAL_FLOAT_ARRAY_TYPE",
+ 143: "FILLER_TYPE",
+ 144: "ACCESSOR_INFO_TYPE",
+ 145: "ACCESS_CHECK_INFO_TYPE",
+ 146: "INTERCEPTOR_INFO_TYPE",
+ 147: "CALL_HANDLER_INFO_TYPE",
+ 148: "FUNCTION_TEMPLATE_INFO_TYPE",
+ 149: "OBJECT_TEMPLATE_INFO_TYPE",
+ 150: "SIGNATURE_INFO_TYPE",
+ 151: "TYPE_SWITCH_INFO_TYPE",
+ 152: "SCRIPT_TYPE",
+ 153: "CODE_CACHE_TYPE",
+ 156: "FIXED_ARRAY_TYPE",
+ 157: "SHARED_FUNCTION_INFO_TYPE",
+ 158: "JS_MESSAGE_OBJECT_TYPE",
+ 159: "JS_VALUE_TYPE",
+ 160: "JS_OBJECT_TYPE",
+ 161: "JS_CONTEXT_EXTENSION_OBJECT_TYPE",
+ 162: "JS_GLOBAL_OBJECT_TYPE",
+ 163: "JS_BUILTINS_OBJECT_TYPE",
+ 164: "JS_GLOBAL_PROXY_TYPE",
+ 165: "JS_ARRAY_TYPE",
+ 166: "JS_REGEXP_TYPE",
+ 167: "JS_FUNCTION_TYPE",
+ 154: "DEBUG_INFO_TYPE",
+ 155: "BREAK_POINT_INFO_TYPE",
+}
+
+
+class Printer(object):
+ """Printer with indentation support."""
+
+ def __init__(self):
+ self.indent = 0
+
+ def Indent(self):
+ self.indent += 2
+
+ def Dedent(self):
+ self.indent -= 2
+
+ def Print(self, string):
+ print "%s%s" % (self._IndentString(), string)
+
+ def PrintLines(self, lines):
+ indent = self._IndentString()
+ print "\n".join("%s%s" % (indent, line) for line in lines)
+
+ def _IndentString(self):
+ return self.indent * " "
+
+
+ADDRESS_RE = re.compile(r"0x[0-9a-fA-F]+")
+
+
+def FormatDisasmLine(start, heap, line):
+ line_address = start + line[0]
+ stack_slot = heap.stack_map.get(line_address)
+ marker = " "
+ if stack_slot:
+ marker = "=>"
+ code = AnnotateAddresses(heap, line[1])
+ return "%s%08x %08x: %s" % (marker, line_address, line[0], code)
+
+
+def AnnotateAddresses(heap, line):
+ extra = []
+ for m in ADDRESS_RE.finditer(line):
+ maybe_address = int(m.group(0), 16)
+ object = heap.FindObject(maybe_address)
+ if not object: continue
+ extra.append(str(object))
+ if len(extra) == 0: return line
+ return "%s ;; %s" % (line, ", ".join(extra))
+
+
+class HeapObject(object):
+ def __init__(self, heap, map, address):
+ self.heap = heap
+ self.map = map
+ self.address = address
+
+ def Is(self, cls):
+ return isinstance(self, cls)
+
+ def Print(self, p):
+ p.Print(str(self))
+
+ def __str__(self):
+ return "HeapObject(%08x, %s)" % (self.address,
+ INSTANCE_TYPES[self.map.instance_type])
+
+ def ObjectField(self, offset):
+ field_value = self.heap.reader.ReadU32(self.address + offset)
+ return self.heap.FindObjectOrSmi(field_value)
+
+ def SmiField(self, offset):
+ field_value = self.heap.reader.ReadU32(self.address + offset)
+ assert (field_value & 1) == 0
+ return field_value / 2
+
+
+class Map(HeapObject):
+ INSTANCE_TYPE_OFFSET = 8
+
+ def __init__(self, heap, map, address):
+ HeapObject.__init__(self, heap, map, address)
+ self.instance_type = \
+ heap.reader.ReadU8(self.address + Map.INSTANCE_TYPE_OFFSET)
+
+
+class String(HeapObject):
+ LENGTH_OFFSET = 4
+
+ def __init__(self, heap, map, address):
+ HeapObject.__init__(self, heap, map, address)
+ self.length = self.SmiField(String.LENGTH_OFFSET)
+
+ def GetChars(self):
+ return "?string?"
+
+ def Print(self, p):
+ p.Print(str(self))
+
+ def __str__(self):
+ return "\"%s\"" % self.GetChars()
+
+
+class SeqString(String):
+ CHARS_OFFSET = 12
+
+ def __init__(self, heap, map, address):
+ String.__init__(self, heap, map, address)
+ self.chars = heap.reader.ReadBytes(self.address + SeqString.CHARS_OFFSET,
+ self.length)
+
+ def GetChars(self):
+ return self.chars
+
+
+class ExternalString(String):
+ RESOURCE_OFFSET = 12
+
+ WEBKIT_RESOUCE_STRING_IMPL_OFFSET = 4
+ WEBKIT_STRING_IMPL_CHARS_OFFSET = 8
+
+ def __init__(self, heap, map, address):
+ String.__init__(self, heap, map, address)
+ reader = heap.reader
+ self.resource = \
+ reader.ReadU32(self.address + ExternalString.RESOURCE_OFFSET)
+ self.chars = "?external string?"
+ if not reader.IsValidAddress(self.resource): return
+ string_impl_address = self.resource + \
+ ExternalString.WEBKIT_RESOUCE_STRING_IMPL_OFFSET
+ if not reader.IsValidAddress(string_impl_address): return
+ string_impl = reader.ReadU32(string_impl_address)
+ chars_ptr_address = string_impl + \
+ ExternalString.WEBKIT_STRING_IMPL_CHARS_OFFSET
+ if not reader.IsValidAddress(chars_ptr_address): return
+ chars_ptr = reader.ReadU32(chars_ptr_address)
+ if not reader.IsValidAddress(chars_ptr): return
+ raw_chars = reader.ReadBytes(chars_ptr, 2 * self.length)
+ self.chars = codecs.getdecoder("utf16")(raw_chars)[0]
+
+ def GetChars(self):
+ return self.chars
+
+
+class ConsString(String):
+ LEFT_OFFSET = 12
+ RIGHT_OFFSET = 16
+
+ def __init__(self, heap, map, address):
+ String.__init__(self, heap, map, address)
+ self.left = self.ObjectField(ConsString.LEFT_OFFSET)
+ self.right = self.ObjectField(ConsString.RIGHT_OFFSET)
+
+ def GetChars(self):
+ return self.left.GetChars() + self.right.GetChars()
+
+
+class Oddball(HeapObject):
+ TO_STRING_OFFSET = 4
+
+ def __init__(self, heap, map, address):
+ HeapObject.__init__(self, heap, map, address)
+ self.to_string = self.ObjectField(Oddball.TO_STRING_OFFSET)
+
+ def Print(self, p):
+ p.Print(str(self))
+
+ def __str__(self):
+ return "<%s>" % self.to_string.GetChars()
+
+
+class FixedArray(HeapObject):
+ LENGTH_OFFSET = 4
+ ELEMENTS_OFFSET = 8
+
+ def __init__(self, heap, map, address):
+ HeapObject.__init__(self, heap, map, address)
+ self.length = self.SmiField(FixedArray.LENGTH_OFFSET)
+
+ def Print(self, p):
+ p.Print("FixedArray(%08x) {" % self.address)
+ p.Indent()
+ p.Print("length: %d" % self.length)
+ for i in xrange(self.length):
+ offset = FixedArray.ELEMENTS_OFFSET + 4 * i
+ p.Print("[%08d] = %s" % (i, self.ObjectField(offset)))
+ p.Dedent()
+ p.Print("}")
+
+ def __str__(self):
+ return "FixedArray(%08x, length=%d)" % (self.address, self.length)
+
+
+class JSFunction(HeapObject):
+ CODE_ENTRY_OFFSET = 12
+ SHARED_OFFSET = 20
+
+ def __init__(self, heap, map, address):
+ HeapObject.__init__(self, heap, map, address)
+ code_entry = \
+ heap.reader.ReadU32(self.address + JSFunction.CODE_ENTRY_OFFSET)
+ self.code = heap.FindObject(code_entry - Code.ENTRY_OFFSET + 1)
+ self.shared = self.ObjectField(JSFunction.SHARED_OFFSET)
+
+ def Print(self, p):
+ source = "\n".join(" %s" % line for line in self._GetSource().split("\n"))
+ p.Print("JSFunction(%08x) {" % self.address)
+ p.Indent()
+ p.Print("inferred name: %s" % self.shared.inferred_name)
+ if self.shared.script.Is(Script) and self.shared.script.name.Is(String):
+ p.Print("script name: %s" % self.shared.script.name)
+ p.Print("source:")
+ p.PrintLines(self._GetSource().split("\n"))
+ p.Print("code:")
+ self.code.Print(p)
+ if self.code != self.shared.code:
+ p.Print("unoptimized code:")
+ self.shared.code.Print(p)
+ p.Dedent()
+ p.Print("}")
+
+ def __str__(self):
+ inferred_name = ""
+ if self.shared.Is(SharedFunctionInfo):
+ inferred_name = self.shared.inferred_name
+ return "JSFunction(%08x, %s)" % (self.address, inferred_name)
+
+ def _GetSource(self):
+ source = "?source?"
+ start = self.shared.start_position
+ end = self.shared.end_position
+ if not self.shared.script.Is(Script): return source
+ script_source = self.shared.script.source
+ if not script_source.Is(String): return source
+ return script_source.GetChars()[start:end]
+
+
+class SharedFunctionInfo(HeapObject):
+ CODE_OFFSET = 2 * 4
+ SCRIPT_OFFSET = 7 * 4
+ INFERRED_NAME_OFFSET = 9 * 4
+ START_POSITION_AND_TYPE_OFFSET = 17 * 4
+ END_POSITION_OFFSET = 18 * 4
+
+ def __init__(self, heap, map, address):
+ HeapObject.__init__(self, heap, map, address)
+ self.code = self.ObjectField(SharedFunctionInfo.CODE_OFFSET)
+ self.script = self.ObjectField(SharedFunctionInfo.SCRIPT_OFFSET)
+ self.inferred_name = \
+ self.ObjectField(SharedFunctionInfo.INFERRED_NAME_OFFSET)
+ start_position_and_type = \
+ self.SmiField(SharedFunctionInfo.START_POSITION_AND_TYPE_OFFSET)
+ self.start_position = start_position_and_type >> 2
+ self.end_position = self.SmiField(SharedFunctionInfo.END_POSITION_OFFSET)
+
+
+class Script(HeapObject):
+ SOURCE_OFFSET = 4
+ NAME_OFFSET = 8
+
+ def __init__(self, heap, map, address):
+ HeapObject.__init__(self, heap, map, address)
+ self.source = self.ObjectField(Script.SOURCE_OFFSET)
+ self.name = self.ObjectField(Script.NAME_OFFSET)
+
+
+class Code(HeapObject):
+ INSTRUCTION_SIZE_OFFSET = 4
+ ENTRY_OFFSET = 32
+
+ def __init__(self, heap, map, address):
+ HeapObject.__init__(self, heap, map, address)
+ self.entry = self.address + Code.ENTRY_OFFSET
+ self.instruction_size = \
+ heap.reader.ReadU32(self.address + Code.INSTRUCTION_SIZE_OFFSET)
+
+ def Print(self, p):
+ lines = self.heap.reader.GetDisasmLines(self.entry, self.instruction_size)
+ p.Print("Code(%08x) {" % self.address)
+ p.Indent()
+ p.Print("instruction_size: %d" % self.instruction_size)
+ p.PrintLines(self._FormatLine(line) for line in lines)
+ p.Dedent()
+ p.Print("}")
+
+ def _FormatLine(self, line):
+ return FormatDisasmLine(self.entry, self.heap, line)
+
+
+class V8Heap(object):
+ CLASS_MAP = {
+ "SYMBOL_TYPE": SeqString,
+ "ASCII_SYMBOL_TYPE": SeqString,
+ "CONS_SYMBOL_TYPE": ConsString,
+ "CONS_ASCII_SYMBOL_TYPE": ConsString,
+ "EXTERNAL_SYMBOL_TYPE": ExternalString,
+ "EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE": ExternalString,
+ "EXTERNAL_ASCII_SYMBOL_TYPE": ExternalString,
+ "STRING_TYPE": SeqString,
+ "ASCII_STRING_TYPE": SeqString,
+ "CONS_STRING_TYPE": ConsString,
+ "CONS_ASCII_STRING_TYPE": ConsString,
+ "EXTERNAL_STRING_TYPE": ExternalString,
+ "EXTERNAL_STRING_WITH_ASCII_DATA_TYPE": ExternalString,
+ "EXTERNAL_ASCII_STRING_TYPE": ExternalString,
+
+ "MAP_TYPE": Map,
+ "ODDBALL_TYPE": Oddball,
+ "FIXED_ARRAY_TYPE": FixedArray,
+ "JS_FUNCTION_TYPE": JSFunction,
+ "SHARED_FUNCTION_INFO_TYPE": SharedFunctionInfo,
+ "SCRIPT_TYPE": Script,
+ "CODE_TYPE": Code
+ }
+
+ def __init__(self, reader, stack_map):
+ self.reader = reader
+ self.stack_map = stack_map
+ self.objects = {}
+
+ def FindObjectOrSmi(self, tagged_address):
+ if (tagged_address & 1) == 0: return tagged_address / 2
+ return self.FindObject(tagged_address)
+
+ def FindObject(self, tagged_address):
+ if tagged_address in self.objects:
+ return self.objects[tagged_address]
+ if (tagged_address & 1) != 1: return None
+ address = tagged_address - 1
+ if not self.reader.IsValidAddress(address): return None
+ map_tagged_address = self.reader.ReadU32(address)
+ if tagged_address == map_tagged_address:
+ # Meta map?
+ meta_map = Map(self, None, address)
+ instance_type_name = INSTANCE_TYPES.get(meta_map.instance_type)
+ if instance_type_name != "MAP_TYPE": return None
+ meta_map.map = meta_map
+ object = meta_map
+ else:
+ map = self.FindObject(map_tagged_address)
+ if map is None: return None
+ instance_type_name = INSTANCE_TYPES.get(map.instance_type)
+ if instance_type_name is None: return None
+ cls = V8Heap.CLASS_MAP.get(instance_type_name, HeapObject)
+ object = cls(self, map, address)
+ self.objects[tagged_address] = object
+ return object
+
+
+EIP_PROXIMITY = 64
+
+
+def AnalyzeMinidump(options, minidump_name):
+ reader = MinidumpReader(options, minidump_name)
+ DebugPrint("========================================")
+ if reader.exception is None:
+ print "Minidump has no exception info"
+ return
+ print "Exception info:"
+ exception_thread = reader.thread_map[reader.exception.thread_id]
+ print " thread id: %d" % exception_thread.id
+ print " code: %08X" % reader.exception.exception.code
+ print " context:"
+ print " eax: %08x" % reader.exception_context.eax
+ print " ebx: %08x" % reader.exception_context.ebx
+ print " ecx: %08x" % reader.exception_context.ecx
+ print " edx: %08x" % reader.exception_context.edx
+ print " edi: %08x" % reader.exception_context.edi
+ print " esi: %08x" % reader.exception_context.esi
+ print " ebp: %08x" % reader.exception_context.ebp
+ print " esp: %08x" % reader.exception_context.esp
+ print " eip: %08x" % reader.exception_context.eip
+ # TODO(vitalyr): decode eflags.
+ print " eflags: %s" % bin(reader.exception_context.eflags)[2:]
+ print
+
+ stack_bottom = exception_thread.stack.start + \
+ exception_thread.stack.memory.data_size
+ stack_map = {reader.exception_context.eip: -1}
+ for slot in xrange(reader.exception_context.esp, stack_bottom, 4):
+ maybe_address = reader.ReadU32(slot)
+ if not maybe_address in stack_map:
+ stack_map[maybe_address] = slot
+ heap = V8Heap(reader, stack_map)
+
+ print "Disassembly around exception.eip:"
+ start = reader.exception_context.eip - EIP_PROXIMITY
+ lines = reader.GetDisasmLines(start, 2 * EIP_PROXIMITY)
+ for line in lines:
+ print FormatDisasmLine(start, heap, line)
+ print
+
+ print "Annotated stack (from exception.esp to bottom):"
+ for slot in xrange(reader.exception_context.esp, stack_bottom, 4):
+ maybe_address = reader.ReadU32(slot)
+ heap_object = heap.FindObject(maybe_address)
+ print "%08x: %08x" % (slot, maybe_address)
+ if heap_object:
+ heap_object.Print(Printer())
+ print
+
+ reader.Dispose()
+
+
+if __name__ == "__main__":
+ parser = optparse.OptionParser(USAGE)
+ options, args = parser.parse_args()
+ if len(args) != 1:
+ parser.print_help()
+ sys.exit(1)
+ AnalyzeMinidump(options, args[0])
diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp
index 15185671..6dab52d8 100644
--- a/tools/gyp/v8.gyp
+++ b/tools/gyp/v8.gyp
@@ -598,6 +598,8 @@
'../../src/arm/lithium-arm.h',
'../../src/arm/lithium-codegen-arm.cc',
'../../src/arm/lithium-codegen-arm.h',
+ '../../src/arm/lithium-gap-resolver-arm.cc',
+ '../../src/arm/lithium-gap-resolver-arm.h',
'../../src/arm/macro-assembler-arm.cc',
'../../src/arm/macro-assembler-arm.h',
'../../src/arm/regexp-macro-assembler-arm.cc',
diff --git a/tools/linux-tick-processor.py b/tools/linux-tick-processor.py
deleted file mode 100755
index 67c3b955..00000000
--- a/tools/linux-tick-processor.py
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2008 the V8 project authors. All rights reserved.
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * 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.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
-# OWNER OR 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.
-
-# Usage: process-ticks.py <logfile>
-# Where <logfile> is the log file name (eg, v8.log).
-
-import subprocess, re, sys, tickprocessor
-
-class LinuxTickProcessor(tickprocessor.TickProcessor):
-
- def ParseVMSymbols(self, filename, start, end):
- """Extract symbols and add them to the cpp entries."""
- # Extra both dynamic and non-dynamic symbols.
- command = 'nm -C -n "%s"; nm -C -n -D "%s"' % (filename, filename)
- process = subprocess.Popen(command, shell=True,
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT)
- pipe = process.stdout
- try:
- for line in pipe:
- row = re.match('^([0-9a-fA-F]{8}) . (.*)$', line)
- if row:
- addr = int(row.group(1), 16)
- if addr < start and addr < end - start:
- addr += start
- self.cpp_entries.Insert(addr, tickprocessor.CodeEntry(addr, row.group(2)))
- finally:
- pipe.close()
-
-
-class LinuxCmdLineProcessor(tickprocessor.CmdLineProcessor):
-
- def GetRequiredArgsNames(self):
- return 'log_file'
-
- def ProcessRequiredArgs(self, args):
- if len(args) != 1:
- self.PrintUsageAndExit()
- else:
- self.log_file = args[0]
-
-
-def Main():
- cmdline_processor = LinuxCmdLineProcessor()
- cmdline_processor.ProcessArguments()
- tick_processor = LinuxTickProcessor()
- cmdline_processor.RunLogfileProcessing(tick_processor)
- tick_processor.PrintResults()
-
-
-if __name__ == '__main__':
- Main()
diff --git a/tools/ll_prof.py b/tools/ll_prof.py
index 8390d4af..7f12c133 100755
--- a/tools/ll_prof.py
+++ b/tools/ll_prof.py
@@ -30,13 +30,13 @@
import bisect
import collections
import ctypes
+import disasm
import mmap
import optparse
import os
import re
import subprocess
import sys
-import tempfile
import time
@@ -74,27 +74,12 @@ V8_GC_FAKE_MMAP = "/tmp/__v8_gc__"
JS_ORIGIN = "js"
JS_SNAPSHOT_ORIGIN = "js-snapshot"
-# Avoid using the slow (google-specific) wrapper around objdump.
-OBJDUMP_BIN = "/usr/bin/objdump"
-if not os.path.exists(OBJDUMP_BIN):
- OBJDUMP_BIN = "objdump"
+OBJDUMP_BIN = disasm.OBJDUMP_BIN
class Code(object):
"""Code object."""
- _COMMON_DISASM_OPTIONS = ["-M", "intel-mnemonic", "-C"]
-
- _DISASM_HEADER_RE = re.compile(r"[a-f0-9]+\s+<.*:$")
- _DISASM_LINE_RE = re.compile(r"\s*([a-f0-9]+):.*")
-
- # Keys must match constants in Logger::LogCodeInfo.
- _ARCH_MAP = {
- "ia32": "-m i386",
- "x64": "-m i386 -M x86-64",
- "arm": "-m arm" # Not supported by our objdump build.
- }
-
_id = 0
def __init__(self, name, start_address, end_address, origin, origin_offset):
@@ -150,12 +135,7 @@ class Code(object):
ticks_offsets = [t[0] for t in ticks_map]
ticks_counts = [t[1] for t in ticks_map]
# Get a list of disassembled lines and their addresses.
- lines = []
- for line in self._GetDisasmLines(code_info, options):
- match = Code._DISASM_LINE_RE.match(line)
- if match:
- line_address = int(match.group(1), 16)
- lines.append((line_address, line))
+ lines = self._GetDisasmLines(code_info, options)
if len(lines) == 0:
return
# Print annotated lines.
@@ -179,9 +159,9 @@ class Code(object):
total_count += count
count = 100.0 * count / self.self_ticks
if count >= 0.01:
- print "%15.2f %s" % (count, lines[i][1])
+ print "%15.2f %x: %s" % (count, lines[i][0], lines[i][1])
else:
- print "%s %s" % (" " * 15, lines[i][1])
+ print "%s %x: %s" % (" " * 15, lines[i][0], lines[i][1])
print
assert total_count == self.self_ticks, \
"Lost ticks (%d != %d) in %s" % (total_count, self.self_ticks, self)
@@ -195,39 +175,17 @@ class Code(object):
self.origin)
def _GetDisasmLines(self, code_info, options):
- tmp_name = None
if self.origin == JS_ORIGIN or self.origin == JS_SNAPSHOT_ORIGIN:
- assert code_info.arch in Code._ARCH_MAP, \
- "Unsupported architecture '%s'" % arch
- arch_flags = Code._ARCH_MAP[code_info.arch]
- # Create a temporary file just with this code object.
- tmp_name = tempfile.mktemp(".v8code")
- size = self.end_address - self.start_address
- command = "dd if=%s.code of=%s bs=1 count=%d skip=%d && " \
- "%s %s -D -b binary %s %s" % (
- options.log, tmp_name, size, self.origin_offset,
- OBJDUMP_BIN, ' '.join(Code._COMMON_DISASM_OPTIONS), arch_flags,
- tmp_name)
+ inplace = False
+ filename = options.log + ".code"
else:
- command = "%s %s --start-address=%d --stop-address=%d -d %s " % (
- OBJDUMP_BIN, ' '.join(Code._COMMON_DISASM_OPTIONS),
- self.origin_offset,
- self.origin_offset + self.end_address - self.start_address,
- self.origin)
- process = subprocess.Popen(command,
- shell=True,
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT)
- out, err = process.communicate()
- lines = out.split("\n")
- header_line = 0
- for i, line in enumerate(lines):
- if Code._DISASM_HEADER_RE.match(line):
- header_line = i
- break
- if tmp_name:
- os.unlink(tmp_name)
- return lines[header_line + 1:]
+ inplace = True
+ filename = self.origin
+ return disasm.GetDisasmLines(filename,
+ self.origin_offset,
+ self.end_address - self.start_address,
+ code_info.arch,
+ inplace)
class CodePage(object):
@@ -353,7 +311,7 @@ class CodeLogReader(object):
r"code-info,([^,]+),(\d+)")
_CODE_CREATE_RE = re.compile(
- r"code-creation,([^,]+),(0x[a-f0-9]+),(\d+),\"(.*)\"(?:,(\d+))?")
+ r"code-creation,([^,]+),(0x[a-f0-9]+),(\d+),\"(.*)\"(?:,(0x[a-f0-9]+),([~*])?)?(?:,(\d+))?")
_CODE_MOVE_RE = re.compile(
r"code-move,(0x[a-f0-9]+),(0x[a-f0-9]+)")
@@ -400,12 +358,18 @@ class CodeLogReader(object):
name = self.address_to_snapshot_name[start_address]
origin = JS_SNAPSHOT_ORIGIN
else:
- name = "%s:%s" % (match.group(1), match.group(4))
+ tag = match.group(1)
+ optimization_status = match.group(6)
+ func_name = match.group(4)
+ if optimization_status:
+ name = "%s:%s%s" % (tag, optimization_status, func_name)
+ else:
+ name = "%s:%s" % (tag, func_name)
origin = JS_ORIGIN
if self.is_snapshot:
origin_offset = 0
else:
- origin_offset = int(match.group(5))
+ origin_offset = int(match.group(7))
code = Code(name, start_address, end_address, origin, origin_offset)
conficting_code = self.code_map.Find(start_address)
if conficting_code:
diff --git a/tools/profile.js b/tools/profile.js
index 03bee839..c9c9437e 100644
--- a/tools/profile.js
+++ b/tools/profile.js
@@ -38,11 +38,6 @@ function Profile() {
this.bottomUpTree_ = new CallTree();
};
-/**
- * Version of profiler log.
- */
-Profile.VERSION = 2;
-
/**
* Returns whether a function with the specified name must be skipped.
@@ -69,6 +64,18 @@ Profile.Operation = {
/**
+ * Enum for code state regarding its dynamic optimization.
+ *
+ * @enum {number}
+ */
+Profile.CodeState = {
+ COMPILED: 0,
+ OPTIMIZABLE: 1,
+ OPTIMIZED: 2
+};
+
+
+/**
* Called whenever the specified operation has failed finding a function
* containing the specified address. Should be overriden by subclasses.
* See the Profile.Operation enum for the list of
@@ -134,17 +141,30 @@ Profile.prototype.addCode = function(
/**
- * Creates an alias entry for a code entry.
+ * Registers dynamic (JIT-compiled) code entry.
*
- * @param {number} aliasAddr Alias address.
- * @param {number} addr Code entry address.
- */
-Profile.prototype.addCodeAlias = function(
- aliasAddr, addr) {
- var entry = this.codeMap_.findDynamicEntryByStartAddress(addr);
- if (entry) {
- this.codeMap_.addCode(aliasAddr, entry);
+ * @param {string} type Code entry type.
+ * @param {string} name Code entry name.
+ * @param {number} start Starting address.
+ * @param {number} size Code entry size.
+ * @param {number} funcAddr Shared function object address.
+ * @param {Profile.CodeState} state Optimization state.
+ */
+Profile.prototype.addFuncCode = function(
+ type, name, start, size, funcAddr, state) {
+ // As code and functions are in the same address space,
+ // it is safe to put them in a single code map.
+ var func = this.codeMap_.findDynamicEntryByStartAddress(funcAddr);
+ if (!func) {
+ func = new Profile.FunctionEntry(name);
+ this.codeMap_.addCode(funcAddr, func);
+ } else if (func.name !== name) {
+ // Function object has been overwritten with a new one.
+ func.name = name;
}
+ var entry = new Profile.DynamicFuncCodeEntry(size, type, func, state);
+ this.codeMap_.addCode(start, entry);
+ return entry;
};
@@ -183,7 +203,7 @@ Profile.prototype.deleteCode = function(start) {
* @param {number} from Current code entry address.
* @param {number} to New code entry address.
*/
-Profile.prototype.safeMoveDynamicCode = function(from, to) {
+Profile.prototype.moveFunc = function(from, to) {
if (this.codeMap_.findDynamicEntryByStartAddress(from)) {
this.codeMap_.moveCode(from, to);
}
@@ -191,18 +211,6 @@ Profile.prototype.safeMoveDynamicCode = function(from, to) {
/**
- * Reports about deletion of a dynamic code entry.
- *
- * @param {number} start Starting address.
- */
-Profile.prototype.safeDeleteDynamicCode = function(start) {
- if (this.codeMap_.findDynamicEntryByStartAddress(start)) {
- this.codeMap_.deleteCode(start);
- }
-};
-
-
-/**
* Retrieves a code entry by an address.
*
* @param {number} addr Entry address.
@@ -383,14 +391,7 @@ Profile.DynamicCodeEntry = function(size, type, name) {
* Returns node name.
*/
Profile.DynamicCodeEntry.prototype.getName = function() {
- var name = this.name;
- if (name.length == 0) {
- name = '<anonymous>';
- } else if (name.charAt(0) == ' ') {
- // An anonymous function with location: " aaa.js:10".
- name = '<anonymous>' + name;
- }
- return this.type + ': ' + name;
+ return this.type + ': ' + this.name;
};
@@ -403,9 +404,73 @@ Profile.DynamicCodeEntry.prototype.getRawName = function() {
Profile.DynamicCodeEntry.prototype.isJSFunction = function() {
- return this.type == "Function" ||
- this.type == "LazyCompile" ||
- this.type == "Script";
+ return false;
+};
+
+
+/**
+ * Creates a dynamic code entry.
+ *
+ * @param {number} size Code size.
+ * @param {string} type Code type.
+ * @param {Profile.FunctionEntry} func Shared function entry.
+ * @param {Profile.CodeState} state Code optimization state.
+ * @constructor
+ */
+Profile.DynamicFuncCodeEntry = function(size, type, func, state) {
+ CodeMap.CodeEntry.call(this, size);
+ this.type = type;
+ this.func = func;
+ this.state = state;
+};
+
+Profile.DynamicFuncCodeEntry.STATE_PREFIX = ["", "~", "*"];
+
+/**
+ * Returns node name.
+ */
+Profile.DynamicFuncCodeEntry.prototype.getName = function() {
+ var name = this.func.getName();
+ return this.type + ': ' + Profile.DynamicFuncCodeEntry.STATE_PREFIX[this.state] + name;
+};
+
+
+/**
+ * Returns raw node name (without type decoration).
+ */
+Profile.DynamicFuncCodeEntry.prototype.getRawName = function() {
+ return this.func.getName();
+};
+
+
+Profile.DynamicFuncCodeEntry.prototype.isJSFunction = function() {
+ return true;
+};
+
+
+/**
+ * Creates a shared function object entry.
+ *
+ * @param {string} name Function name.
+ * @constructor
+ */
+Profile.FunctionEntry = function(name) {
+ CodeMap.CodeEntry.call(this, 0, name);
+};
+
+
+/**
+ * Returns node name.
+ */
+Profile.FunctionEntry.prototype.getName = function() {
+ var name = this.name;
+ if (name.length == 0) {
+ name = '<anonymous>';
+ } else if (name.charAt(0) == ' ') {
+ // An anonymous function with location: " aaa.js:10".
+ name = '<anonymous>' + name;
+ }
+ return name;
};
diff --git a/tools/splaytree.py b/tools/splaytree.py
deleted file mode 100644
index 8c3c4fe1..00000000
--- a/tools/splaytree.py
+++ /dev/null
@@ -1,226 +0,0 @@
-# Copyright 2008 the V8 project authors. All rights reserved.
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * 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.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
-# OWNER OR 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.
-
-
-class Node(object):
- """Nodes in the splay tree."""
-
- def __init__(self, key, value):
- self.key = key
- self.value = value
- self.left = None
- self.right = None
-
-
-class KeyNotFoundError(Exception):
- """KeyNotFoundError is raised when removing a non-existing node."""
-
- def __init__(self, key):
- self.key = key
-
-
-class SplayTree(object):
- """The splay tree itself is just a reference to the root of the tree."""
-
- def __init__(self):
- """Create a new SplayTree."""
- self.root = None
-
- def IsEmpty(self):
- """Is the SplayTree empty?"""
- return not self.root
-
- def Insert(self, key, value):
- """Insert a new node in the SplayTree."""
- # If the tree is empty, insert the new node.
- if self.IsEmpty():
- self.root = Node(key, value)
- return
- # Splay on the key to move the last node on the search path for
- # the key to the root of the tree.
- self.Splay(key)
- # Ignore repeated insertions with the same key.
- if self.root.key == key:
- return
- # Insert the new node.
- node = Node(key, value)
- if key > self.root.key:
- node.left = self.root
- node.right = self.root.right
- self.root.right = None
- else:
- node.right = self.root
- node.left = self.root.left
- self.root.left = None
- self.root = node
-
- def Remove(self, key):
- """Remove the node with the given key from the SplayTree."""
- # Raise exception for key that is not found if the tree is empty.
- if self.IsEmpty():
- raise KeyNotFoundError(key)
- # Splay on the key to move the node with the given key to the top.
- self.Splay(key)
- # Raise exception for key that is not found.
- if self.root.key != key:
- raise KeyNotFoundError(key)
- removed = self.root
- # Link out the root node.
- if not self.root.left:
- # No left child, so the new tree is just the right child.
- self.root = self.root.right
- else:
- # Left child exists.
- right = self.root.right
- # Make the original left child the new root.
- self.root = self.root.left
- # Splay to make sure that the new root has an empty right child.
- self.Splay(key)
- # Insert the original right child as the right child of the new
- # root.
- self.root.right = right
- return removed
-
- def Find(self, key):
- """Returns the node with the given key or None if no such node exists."""
- if self.IsEmpty():
- return None
- self.Splay(key)
- if self.root.key == key:
- return self.root
- return None
-
- def FindMax(self):
- """Returns the node with the largest key value."""
- if self.IsEmpty():
- return None
- current = self.root
- while current.right != None:
- current = current.right
- return current
-
- # Returns the node with the smallest key value.
- def FindMin(self):
- if self.IsEmpty():
- return None
- current = self.root
- while current.left != None:
- current = current.left
- return current
-
- def FindGreatestsLessThan(self, key):
- """Returns node with greatest key less than or equal to the given key."""
- if self.IsEmpty():
- return None
- # Splay on the key to move the node with the given key or the last
- # node on the search path to the top of the tree.
- self.Splay(key)
- # Now the result is either the root node or the greatest node in
- # the left subtree.
- if self.root.key <= key:
- return self.root
- else:
- tmp = self.root
- self.root = self.root.left
- result = self.FindMax()
- self.root = tmp
- return result
-
- def ExportValueList(self):
- """Returns a list containing all the values of the nodes in the tree."""
- result = []
- nodes_to_visit = [self.root]
- while len(nodes_to_visit) > 0:
- node = nodes_to_visit.pop()
- if not node:
- continue
- result.append(node.value)
- nodes_to_visit.append(node.left)
- nodes_to_visit.append(node.right)
- return result
-
- def Splay(self, key):
- """Perform splay operation.
-
- Perform the splay operation for the given key. Moves the node with
- the given key to the top of the tree. If no node has the given
- key, the last node on the search path is moved to the top of the
- tree.
-
- This uses the simplified top-down splaying algorithm from:
-
- "Self-adjusting Binary Search Trees" by Sleator and Tarjan
-
- """
- if self.IsEmpty():
- return
- # Create a dummy node. The use of the dummy node is a bit
- # counter-intuitive: The right child of the dummy node will hold
- # the L tree of the algorithm. The left child of the dummy node
- # will hold the R tree of the algorithm. Using a dummy node, left
- # and right will always be nodes and we avoid special cases.
- dummy = left = right = Node(None, None)
- current = self.root
- while True:
- if key < current.key:
- if not current.left:
- break
- if key < current.left.key:
- # Rotate right.
- tmp = current.left
- current.left = tmp.right
- tmp.right = current
- current = tmp
- if not current.left:
- break
- # Link right.
- right.left = current
- right = current
- current = current.left
- elif key > current.key:
- if not current.right:
- break
- if key > current.right.key:
- # Rotate left.
- tmp = current.right
- current.right = tmp.left
- tmp.left = current
- current = tmp
- if not current.right:
- break
- # Link left.
- left.right = current
- left = current
- current = current.right
- else:
- break
- # Assemble.
- left.right = current.left
- right.left = current.right
- current.left = dummy.right
- current.right = dummy.left
- self.root = current
diff --git a/tools/tickprocessor.js b/tools/tickprocessor.js
index db2f3c9b..f105a21c 100644
--- a/tools/tickprocessor.js
+++ b/tools/tickprocessor.js
@@ -57,10 +57,23 @@ function readFile(fileName) {
}
+/**
+ * Parser for dynamic code optimization state.
+ */
+function parseState(s) {
+ switch (s) {
+ case "": return Profile.CodeState.COMPILED;
+ case "~": return Profile.CodeState.OPTIMIZABLE;
+ case "*": return Profile.CodeState.OPTIMIZED;
+ }
+ throw new Error("unknown code state: " + s);
+}
+
+
function SnapshotLogProcessor() {
LogReader.call(this, {
'code-creation': {
- parsers: [null, parseInt, parseInt, null],
+ parsers: [null, parseInt, parseInt, null, 'var-args'],
processor: this.processCodeCreation },
'code-move': { parsers: [parseInt, parseInt],
processor: this.processCodeMove },
@@ -69,6 +82,7 @@ function SnapshotLogProcessor() {
'function-creation': null,
'function-move': null,
'function-delete': null,
+ 'sfi-move': null,
'snapshot-pos': { parsers: [parseInt, parseInt],
processor: this.processSnapshotPosition }});
@@ -93,8 +107,14 @@ inherits(SnapshotLogProcessor, LogReader);
SnapshotLogProcessor.prototype.processCodeCreation = function(
- type, start, size, name) {
- var entry = this.profile_.addCode(type, name, start, size);
+ type, start, size, name, maybe_func) {
+ if (maybe_func.length) {
+ var funcAddr = parseInt(maybe_func[0]);
+ var state = parseState(maybe_func[1]);
+ this.profile_.addFuncCode(type, name, start, size, funcAddr, state);
+ } else {
+ this.profile_.addCode(type, name, start, size);
+ }
};
@@ -131,18 +151,14 @@ function TickProcessor(
'shared-library': { parsers: [null, parseInt, parseInt],
processor: this.processSharedLibrary },
'code-creation': {
- parsers: [null, parseInt, parseInt, null],
+ parsers: [null, parseInt, parseInt, null, 'var-args'],
processor: this.processCodeCreation },
'code-move': { parsers: [parseInt, parseInt],
processor: this.processCodeMove },
'code-delete': { parsers: [parseInt],
processor: this.processCodeDelete },
- 'function-creation': { parsers: [parseInt, parseInt],
- processor: this.processFunctionCreation },
- 'function-move': { parsers: [parseInt, parseInt],
+ 'sfi-move': { parsers: [parseInt, parseInt],
processor: this.processFunctionMove },
- 'function-delete': { parsers: [parseInt],
- processor: this.processFunctionDelete },
'snapshot-pos': { parsers: [parseInt, parseInt],
processor: this.processSnapshotPosition },
'tick': { parsers: [parseInt, parseInt, parseInt, parseInt, 'var-args'],
@@ -155,6 +171,9 @@ function TickProcessor(
processor: this.processJSProducer },
// Ignored events.
'profiler': null,
+ 'function-creation': null,
+ 'function-move': null,
+ 'function-delete': null,
'heap-sample-stats': null,
'heap-sample-item': null,
'heap-js-cons-item': null,
@@ -285,9 +304,15 @@ TickProcessor.prototype.processSharedLibrary = function(
TickProcessor.prototype.processCodeCreation = function(
- type, start, size, name) {
+ type, start, size, name, maybe_func) {
name = this.deserializedEntriesNames_[start] || name;
- var entry = this.profile_.addCode(type, name, start, size);
+ if (maybe_func.length) {
+ var funcAddr = parseInt(maybe_func[0]);
+ var state = parseState(maybe_func[1]);
+ this.profile_.addFuncCode(type, name, start, size, funcAddr, state);
+ } else {
+ this.profile_.addCode(type, name, start, size);
+ }
};
@@ -301,19 +326,8 @@ TickProcessor.prototype.processCodeDelete = function(start) {
};
-TickProcessor.prototype.processFunctionCreation = function(
- functionAddr, codeAddr) {
- this.profile_.addCodeAlias(functionAddr, codeAddr);
-};
-
-
TickProcessor.prototype.processFunctionMove = function(from, to) {
- this.profile_.safeMoveDynamicCode(from, to);
-};
-
-
-TickProcessor.prototype.processFunctionDelete = function(start) {
- this.profile_.safeDeleteDynamicCode(start);
+ this.profile_.moveFunc(from, to);
};
@@ -330,7 +344,7 @@ TickProcessor.prototype.includeTick = function(vmState) {
};
-TickProcessor.prototype.processTick = function(pc, sp, func, vmState, stack) {
+TickProcessor.prototype.processTick = function(pc, sp, tos, vmState, stack) {
this.ticks_.total++;
if (vmState == TickProcessor.VmStates.GC) this.ticks_.gc++;
if (!this.includeTick(vmState)) {
@@ -338,19 +352,14 @@ TickProcessor.prototype.processTick = function(pc, sp, func, vmState, stack) {
return;
}
- if (func) {
- var funcEntry = this.profile_.findEntry(func);
+ if (tos) {
+ var funcEntry = this.profile_.findEntry(tos);
if (!funcEntry || !funcEntry.isJSFunction || !funcEntry.isJSFunction()) {
- func = 0;
- } else {
- var currEntry = this.profile_.findEntry(pc);
- if (!currEntry || !currEntry.isJSFunction || currEntry.isJSFunction()) {
- func = 0;
- }
+ tos = 0;
}
}
- this.profile_.recordTick(this.processStack(pc, func, stack));
+ this.profile_.recordTick(this.processStack(pc, tos, stack));
};
diff --git a/tools/tickprocessor.py b/tools/tickprocessor.py
deleted file mode 100644
index c932e3fc..00000000
--- a/tools/tickprocessor.py
+++ /dev/null
@@ -1,571 +0,0 @@
-# Copyright 2008 the V8 project authors. All rights reserved.
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * 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.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
-# OWNER OR 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.
-
-import csv, splaytree, sys, re
-from operator import itemgetter
-import getopt, os, string
-
-class CodeEntry(object):
-
- def __init__(self, start_addr, name):
- self.start_addr = start_addr
- self.tick_count = 0
- self.name = name
- self.stacks = {}
-
- def Tick(self, pc, stack):
- self.tick_count += 1
- if len(stack) > 0:
- stack.insert(0, self.ToString())
- stack_key = tuple(stack)
- self.stacks[stack_key] = self.stacks.setdefault(stack_key, 0) + 1
-
- def RegionTicks(self):
- return None
-
- def SetStartAddress(self, start_addr):
- self.start_addr = start_addr
-
- def ToString(self):
- return self.name
-
- def IsSharedLibraryEntry(self):
- return False
-
- def IsICEntry(self):
- return False
-
- def IsJSFunction(self):
- return False
-
-class SharedLibraryEntry(CodeEntry):
-
- def __init__(self, start_addr, name):
- CodeEntry.__init__(self, start_addr, name)
-
- def IsSharedLibraryEntry(self):
- return True
-
-
-class JSCodeEntry(CodeEntry):
-
- def __init__(self, start_addr, name, type, size, assembler):
- CodeEntry.__init__(self, start_addr, name)
- self.type = type
- self.size = size
- self.assembler = assembler
- self.region_ticks = None
- self.builtin_ic_re = re.compile('^(Keyed)?(Call|Load|Store)IC_')
-
- def Tick(self, pc, stack):
- super(JSCodeEntry, self).Tick(pc, stack)
- if not pc is None:
- offset = pc - self.start_addr
- seen = []
- narrowest = None
- narrowest_width = None
- for region in self.Regions():
- if region.Contains(offset):
- if (not region.name in seen):
- seen.append(region.name)
- if narrowest is None or region.Width() < narrowest.Width():
- narrowest = region
- if len(seen) == 0:
- return
- if self.region_ticks is None:
- self.region_ticks = {}
- for name in seen:
- if not name in self.region_ticks:
- self.region_ticks[name] = [0, 0]
- self.region_ticks[name][0] += 1
- if name == narrowest.name:
- self.region_ticks[name][1] += 1
-
- def RegionTicks(self):
- return self.region_ticks
-
- def Regions(self):
- if self.assembler:
- return self.assembler.regions
- else:
- return []
-
- def ToString(self):
- name = self.name
- if name == '':
- name = '<anonymous>'
- elif name.startswith(' '):
- name = '<anonymous>' + name
- return self.type + ': ' + name
-
- def IsICEntry(self):
- return self.type in ('CallIC', 'LoadIC', 'StoreIC') or \
- (self.type == 'Builtin' and self.builtin_ic_re.match(self.name))
-
- def IsJSFunction(self):
- return self.type in ('Function', 'LazyCompile', 'Script')
-
-class CodeRegion(object):
-
- def __init__(self, start_offset, name):
- self.start_offset = start_offset
- self.name = name
- self.end_offset = None
-
- def Contains(self, pc):
- return (self.start_offset <= pc) and (pc <= self.end_offset)
-
- def Width(self):
- return self.end_offset - self.start_offset
-
-
-class Assembler(object):
-
- def __init__(self):
- # Mapping from region ids to open regions
- self.pending_regions = {}
- self.regions = []
-
-
-class FunctionEnumerator(object):
-
- def __init__(self):
- self.known_funcs = {}
- self.next_func_id = 0
-
- def GetFunctionId(self, name):
- if not self.known_funcs.has_key(name):
- self.known_funcs[name] = self.next_func_id
- self.next_func_id += 1
- return self.known_funcs[name]
-
- def GetKnownFunctions(self):
- known_funcs_items = self.known_funcs.items();
- known_funcs_items.sort(key = itemgetter(1))
- result = []
- for func, id_not_used in known_funcs_items:
- result.append(func)
- return result
-
-
-VMStates = { 'JS': 0, 'GC': 1, 'COMPILER': 2, 'OTHER': 3, 'EXTERNAL' : 4 }
-
-
-class TickProcessor(object):
-
- def __init__(self):
- self.log_file = ''
- self.deleted_code = []
- self.vm_extent = {}
- # Map from assembler ids to the pending assembler objects
- self.pending_assemblers = {}
- # Map from code addresses the have been allocated but not yet officially
- # created to their assemblers.
- self.assemblers = {}
- self.js_entries = splaytree.SplayTree()
- self.cpp_entries = splaytree.SplayTree()
- self.total_number_of_ticks = 0
- self.number_of_library_ticks = 0
- self.unaccounted_number_of_ticks = 0
- self.excluded_number_of_ticks = 0
- self.number_of_gc_ticks = 0
- # Flag indicating whether to ignore unaccounted ticks in the report
- self.ignore_unknown = False
- self.func_enum = FunctionEnumerator()
- self.packed_stacks = []
-
- def ProcessLogfile(self, filename, included_state = None, ignore_unknown = False, separate_ic = False, call_graph_json = False):
- self.log_file = filename
- self.included_state = included_state
- self.ignore_unknown = ignore_unknown
- self.separate_ic = separate_ic
- self.call_graph_json = call_graph_json
-
- try:
- logfile = open(filename, 'rb')
- except IOError:
- sys.exit("Could not open logfile: " + filename)
- try:
- try:
- logreader = csv.reader(logfile)
- row_num = 1
- for row in logreader:
- row_num += 1
- if row[0] == 'tick':
- self.ProcessTick(int(row[1], 16), int(row[2], 16), int(row[3], 16), int(row[4]), self.PreprocessStack(row[5:]))
- elif row[0] == 'code-creation':
- self.ProcessCodeCreation(row[1], int(row[2], 16), int(row[3]), row[4])
- elif row[0] == 'code-move':
- self.ProcessCodeMove(int(row[1], 16), int(row[2], 16))
- elif row[0] == 'code-delete':
- self.ProcessCodeDelete(int(row[1], 16))
- elif row[0] == 'function-creation':
- self.ProcessFunctionCreation(int(row[1], 16), int(row[2], 16))
- elif row[0] == 'function-move':
- self.ProcessFunctionMove(int(row[1], 16), int(row[2], 16))
- elif row[0] == 'function-delete':
- self.ProcessFunctionDelete(int(row[1], 16))
- elif row[0] == 'shared-library':
- self.AddSharedLibraryEntry(row[1], int(row[2], 16), int(row[3], 16))
- self.ParseVMSymbols(row[1], int(row[2], 16), int(row[3], 16))
- elif row[0] == 'begin-code-region':
- self.ProcessBeginCodeRegion(int(row[1], 16), int(row[2], 16), int(row[3], 16), row[4])
- elif row[0] == 'end-code-region':
- self.ProcessEndCodeRegion(int(row[1], 16), int(row[2], 16), int(row[3], 16))
- elif row[0] == 'code-allocate':
- self.ProcessCodeAllocate(int(row[1], 16), int(row[2], 16))
- except csv.Error:
- print("parse error in line " + str(row_num))
- raise
- finally:
- logfile.close()
-
- def AddSharedLibraryEntry(self, filename, start, end):
- # Mark the pages used by this library.
- i = start
- while i < end:
- page = i >> 12
- self.vm_extent[page] = 1
- i += 4096
- # Add the library to the entries so that ticks for which we do not
- # have symbol information is reported as belonging to the library.
- self.cpp_entries.Insert(start, SharedLibraryEntry(start, filename))
-
- def ParseVMSymbols(self, filename, start, end):
- return
-
- def ProcessCodeAllocate(self, addr, assem):
- if assem in self.pending_assemblers:
- assembler = self.pending_assemblers.pop(assem)
- self.assemblers[addr] = assembler
-
- def ProcessCodeCreation(self, type, addr, size, name):
- if addr in self.assemblers:
- assembler = self.assemblers.pop(addr)
- else:
- assembler = None
- self.js_entries.Insert(addr, JSCodeEntry(addr, name, type, size, assembler))
-
- def ProcessCodeMove(self, from_addr, to_addr):
- try:
- removed_node = self.js_entries.Remove(from_addr)
- removed_node.value.SetStartAddress(to_addr);
- self.js_entries.Insert(to_addr, removed_node.value)
- except splaytree.KeyNotFoundError:
- print('Code move event for unknown code: 0x%x' % from_addr)
-
- def ProcessCodeDelete(self, from_addr):
- try:
- removed_node = self.js_entries.Remove(from_addr)
- self.deleted_code.append(removed_node.value)
- except splaytree.KeyNotFoundError:
- print('Code delete event for unknown code: 0x%x' % from_addr)
-
- def ProcessFunctionCreation(self, func_addr, code_addr):
- js_entry_node = self.js_entries.Find(code_addr)
- if js_entry_node:
- js_entry = js_entry_node.value
- self.js_entries.Insert(func_addr, JSCodeEntry(func_addr, js_entry.name, js_entry.type, 1, None))
-
- def ProcessFunctionMove(self, from_addr, to_addr):
- try:
- removed_node = self.js_entries.Remove(from_addr)
- removed_node.value.SetStartAddress(to_addr);
- self.js_entries.Insert(to_addr, removed_node.value)
- except splaytree.KeyNotFoundError:
- return
-
- def ProcessFunctionDelete(self, from_addr):
- try:
- removed_node = self.js_entries.Remove(from_addr)
- self.deleted_code.append(removed_node.value)
- except splaytree.KeyNotFoundError:
- return
-
- def ProcessBeginCodeRegion(self, id, assm, start, name):
- if not assm in self.pending_assemblers:
- self.pending_assemblers[assm] = Assembler()
- assembler = self.pending_assemblers[assm]
- assembler.pending_regions[id] = CodeRegion(start, name)
-
- def ProcessEndCodeRegion(self, id, assm, end):
- assm = self.pending_assemblers[assm]
- region = assm.pending_regions.pop(id)
- region.end_offset = end
- assm.regions.append(region)
-
- def IncludeTick(self, pc, sp, state):
- return (self.included_state is None) or (self.included_state == state)
-
- def FindEntry(self, pc):
- page = pc >> 12
- if page in self.vm_extent:
- entry = self.cpp_entries.FindGreatestsLessThan(pc)
- if entry != None:
- return entry.value
- else:
- return entry
- max = self.js_entries.FindMax()
- min = self.js_entries.FindMin()
- if max != None and pc < (max.key + max.value.size) and pc > min.key:
- return self.js_entries.FindGreatestsLessThan(pc).value
- return None
-
- def PreprocessStack(self, stack):
- # remove all non-addresses (e.g. 'overflow') and convert to int
- result = []
- for frame in stack:
- if frame.startswith('0x'):
- result.append(int(frame, 16))
- return result
-
- def ProcessStack(self, stack):
- result = []
- for frame in stack:
- entry = self.FindEntry(frame)
- if entry != None:
- result.append(entry.ToString())
- return result
-
- def ProcessTick(self, pc, sp, func, state, stack):
- if state == VMStates['GC']:
- self.number_of_gc_ticks += 1
- if not self.IncludeTick(pc, sp, state):
- self.excluded_number_of_ticks += 1;
- return
- self.total_number_of_ticks += 1
- entry = self.FindEntry(pc)
- if entry == None:
- self.unaccounted_number_of_ticks += 1
- return
- if entry.IsSharedLibraryEntry():
- self.number_of_library_ticks += 1
- if entry.IsICEntry() and not self.separate_ic:
- if len(stack) > 0:
- caller_pc = stack.pop(0)
- self.total_number_of_ticks -= 1
- self.ProcessTick(caller_pc, sp, func, state, stack)
- else:
- self.unaccounted_number_of_ticks += 1
- else:
- processed_stack = self.ProcessStack(stack)
- if not entry.IsSharedLibraryEntry() and not entry.IsJSFunction():
- func_entry_node = self.js_entries.Find(func)
- if func_entry_node and func_entry_node.value.IsJSFunction():
- processed_stack.insert(0, func_entry_node.value.ToString())
- entry.Tick(pc, processed_stack)
- if self.call_graph_json:
- self.AddToPackedStacks(pc, stack)
-
- def AddToPackedStacks(self, pc, stack):
- full_stack = stack
- full_stack.insert(0, pc)
- func_names = self.ProcessStack(full_stack)
- func_ids = []
- for func in func_names:
- func_ids.append(self.func_enum.GetFunctionId(func))
- self.packed_stacks.append(func_ids)
-
- def PrintResults(self):
- if not self.call_graph_json:
- self.PrintStatistics()
- else:
- self.PrintCallGraphJSON()
-
- def PrintStatistics(self):
- print('Statistical profiling result from %s, (%d ticks, %d unaccounted, %d excluded).' %
- (self.log_file,
- self.total_number_of_ticks,
- self.unaccounted_number_of_ticks,
- self.excluded_number_of_ticks))
- if self.total_number_of_ticks > 0:
- js_entries = self.js_entries.ExportValueList()
- js_entries.extend(self.deleted_code)
- cpp_entries = self.cpp_entries.ExportValueList()
- # Print the unknown ticks percentage if they are not ignored.
- if not self.ignore_unknown and self.unaccounted_number_of_ticks > 0:
- self.PrintHeader('Unknown')
- self.PrintCounter(self.unaccounted_number_of_ticks)
- # Print the library ticks.
- self.PrintHeader('Shared libraries')
- self.PrintEntries(cpp_entries, lambda e:e.IsSharedLibraryEntry())
- # Print the JavaScript ticks.
- self.PrintHeader('JavaScript')
- self.PrintEntries(js_entries, lambda e:not e.IsSharedLibraryEntry())
- # Print the C++ ticks.
- self.PrintHeader('C++')
- self.PrintEntries(cpp_entries, lambda e:not e.IsSharedLibraryEntry())
- # Print the GC ticks.
- self.PrintHeader('GC')
- self.PrintCounter(self.number_of_gc_ticks)
- # Print call profile.
- print('\n [Call profile]:')
- print(' total call path')
- js_entries.extend(cpp_entries)
- self.PrintCallProfile(js_entries)
-
- def PrintHeader(self, header_title):
- print('\n [%s]:' % header_title)
- print(' ticks total nonlib name')
-
- def PrintCounter(self, ticks_count):
- percentage = ticks_count * 100.0 / self.total_number_of_ticks
- print(' %(ticks)5d %(total)5.1f%%' % {
- 'ticks' : ticks_count,
- 'total' : percentage,
- })
-
- def PrintEntries(self, entries, condition):
- # If ignoring unaccounted ticks don't include these in percentage
- # calculations
- number_of_accounted_ticks = self.total_number_of_ticks
- if self.ignore_unknown:
- number_of_accounted_ticks -= self.unaccounted_number_of_ticks
-
- number_of_non_library_ticks = number_of_accounted_ticks - self.number_of_library_ticks
- entries.sort(key=lambda e: (e.tick_count, e.ToString()), reverse=True)
- for entry in entries:
- if entry.tick_count > 0 and condition(entry):
- total_percentage = entry.tick_count * 100.0 / number_of_accounted_ticks
- if entry.IsSharedLibraryEntry():
- non_library_percentage = 0
- else:
- non_library_percentage = entry.tick_count * 100.0 / number_of_non_library_ticks
- print(' %(ticks)5d %(total)5.1f%% %(nonlib)6.1f%% %(name)s' % {
- 'ticks' : entry.tick_count,
- 'total' : total_percentage,
- 'nonlib' : non_library_percentage,
- 'name' : entry.ToString()
- })
- region_ticks = entry.RegionTicks()
- if not region_ticks is None:
- items = region_ticks.items()
- items.sort(key=lambda e: e[1][1], reverse=True)
- for (name, ticks) in items:
- print(' flat cum')
- print(' %(flat)5.1f%% %(accum)5.1f%% %(name)s' % {
- 'flat' : ticks[1] * 100.0 / entry.tick_count,
- 'accum' : ticks[0] * 100.0 / entry.tick_count,
- 'name': name
- })
-
- def PrintCallProfile(self, entries):
- all_stacks = {}
- total_stacks = 0
- for entry in entries:
- all_stacks.update(entry.stacks)
- for count in entry.stacks.itervalues():
- total_stacks += count
- all_stacks_items = all_stacks.items();
- all_stacks_items.sort(key = itemgetter(1), reverse=True)
- missing_percentage = (self.total_number_of_ticks - total_stacks) * 100.0 / self.total_number_of_ticks
- print(' %(ticks)5d %(total)5.1f%% <no call path information>' % {
- 'ticks' : self.total_number_of_ticks - total_stacks,
- 'total' : missing_percentage
- })
- for stack, count in all_stacks_items:
- total_percentage = count * 100.0 / self.total_number_of_ticks
- print(' %(ticks)5d %(total)5.1f%% %(call_path)s' % {
- 'ticks' : count,
- 'total' : total_percentage,
- 'call_path' : stack[0] + ' <- ' + stack[1]
- })
-
- def PrintCallGraphJSON(self):
- print('\nvar __profile_funcs = ["' +
- '",\n"'.join(self.func_enum.GetKnownFunctions()) +
- '"];')
- print('var __profile_ticks = [')
- str_packed_stacks = []
- for stack in self.packed_stacks:
- str_packed_stacks.append('[' + ','.join(map(str, stack)) + ']')
- print(',\n'.join(str_packed_stacks))
- print('];')
-
-class CmdLineProcessor(object):
-
- def __init__(self):
- self.options = ["js",
- "gc",
- "compiler",
- "other",
- "external",
- "ignore-unknown",
- "separate-ic",
- "call-graph-json"]
- # default values
- self.state = None
- self.ignore_unknown = False
- self.log_file = None
- self.separate_ic = False
- self.call_graph_json = False
-
- def ProcessArguments(self):
- try:
- opts, args = getopt.getopt(sys.argv[1:], "jgcoe", self.options)
- except getopt.GetoptError:
- self.PrintUsageAndExit()
- for key, value in opts:
- if key in ("-j", "--js"):
- self.state = VMStates['JS']
- if key in ("-g", "--gc"):
- self.state = VMStates['GC']
- if key in ("-c", "--compiler"):
- self.state = VMStates['COMPILER']
- if key in ("-o", "--other"):
- self.state = VMStates['OTHER']
- if key in ("-e", "--external"):
- self.state = VMStates['EXTERNAL']
- if key in ("--ignore-unknown"):
- self.ignore_unknown = True
- if key in ("--separate-ic"):
- self.separate_ic = True
- if key in ("--call-graph-json"):
- self.call_graph_json = True
- self.ProcessRequiredArgs(args)
-
- def ProcessRequiredArgs(self, args):
- return
-
- def GetRequiredArgsNames(self):
- return
-
- def PrintUsageAndExit(self):
- print('Usage: %(script_name)s --{%(opts)s} %(req_opts)s' % {
- 'script_name': os.path.basename(sys.argv[0]),
- 'opts': string.join(self.options, ','),
- 'req_opts': self.GetRequiredArgsNames()
- })
- sys.exit(2)
-
- def RunLogfileProcessing(self, tick_processor):
- tick_processor.ProcessLogfile(self.log_file, self.state, self.ignore_unknown,
- self.separate_ic, self.call_graph_json)
-
-
-if __name__ == '__main__':
- sys.exit('You probably want to run windows-tick-processor.py or linux-tick-processor.py.')
diff --git a/tools/utils.py b/tools/utils.py
index 8083091b..fb94d141 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -49,6 +49,8 @@ def GuessOS():
return 'linux'
elif id == 'Darwin':
return 'macos'
+ elif id.find('CYGWIN') >= 0:
+ return 'cygwin'
elif id == 'Windows' or id == 'Microsoft':
# On Windows Vista platform.system() can return 'Microsoft' with some
# versions of Python, see http://bugs.python.org/issue1082
diff --git a/tools/v8.xcodeproj/project.pbxproj b/tools/v8.xcodeproj/project.pbxproj
index 24321e52..10fbc58a 100644
--- a/tools/v8.xcodeproj/project.pbxproj
+++ b/tools/v8.xcodeproj/project.pbxproj
@@ -211,6 +211,7 @@
895692A512D4ED240072C313 /* objects-printer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8946827412C26EB700C914BC /* objects-printer.cc */; };
8956B6CF0F5D86730033B5A2 /* debug-agent.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8956B6CD0F5D86570033B5A2 /* debug-agent.cc */; };
895FA753107FFED3006F39D4 /* constants-arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = 895FA748107FFE73006F39D4 /* constants-arm.cc */; };
+ 896FA1E5130F93D300042054 /* lithium-gap-resolver-arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = 896FA1E3130F93D300042054 /* lithium-gap-resolver-arm.cc */; };
896FD03A0E78D717003DFB6A /* libv8-arm.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 89F23C870E78D5B2006B2466 /* libv8-arm.a */; };
897C77D012B68E3D000767A8 /* d8-debug.cc in Sources */ = {isa = PBXBuildFile; fileRef = 893988150F2A3686007D5254 /* d8-debug.cc */; };
897C77D112B68E3D000767A8 /* d8-js.cc in Sources */ = {isa = PBXBuildFile; fileRef = 893988320F2A3B8B007D5254 /* d8-js.cc */; };
@@ -647,6 +648,8 @@
895FA751107FFEAE006F39D4 /* register-allocator-arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "register-allocator-arm.h"; path = "arm/register-allocator-arm.h"; sourceTree = "<group>"; };
8964482B0E9C00F700E7C516 /* codegen-ia32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "codegen-ia32.h"; path = "ia32/codegen-ia32.h"; sourceTree = "<group>"; };
896448BC0E9D530500E7C516 /* codegen-arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "codegen-arm.h"; path = "arm/codegen-arm.h"; sourceTree = "<group>"; };
+ 896FA1E3130F93D300042054 /* lithium-gap-resolver-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "lithium-gap-resolver-arm.cc"; path = "arm/lithium-gap-resolver-arm.cc"; sourceTree = "<group>"; };
+ 896FA1E4130F93D300042054 /* lithium-gap-resolver-arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "lithium-gap-resolver-arm.h"; path = "arm/lithium-gap-resolver-arm.h"; sourceTree = "<group>"; };
8970F2F00E719FB2006AE7B5 /* libv8.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libv8.a; sourceTree = BUILT_PRODUCTS_DIR; };
897C77D912B68E3D000767A8 /* d8-arm */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "d8-arm"; sourceTree = BUILT_PRODUCTS_DIR; };
897F767A0E71B4CC007ACF34 /* v8_shell */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = v8_shell; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -1538,6 +1541,8 @@
893E24C812B14B510083370F /* lithium-arm.h */,
893E24C912B14B520083370F /* lithium-codegen-arm.cc */,
893E24CA12B14B520083370F /* lithium-codegen-arm.h */,
+ 896FA1E3130F93D300042054 /* lithium-gap-resolver-arm.cc */,
+ 896FA1E4130F93D300042054 /* lithium-gap-resolver-arm.h */,
897FF1540E719B8F00D62E90 /* macro-assembler-arm.cc */,
897FF1550E719B8F00D62E90 /* macro-assembler-arm.h */,
89A15C700EE466D000B48DEB /* regexp-macro-assembler-arm.cc */,
@@ -2290,6 +2295,7 @@
894A59EA12D777E80000766D /* lithium.cc in Sources */,
89D7DDDC12E8DE09001E2B82 /* gdb-jit.cc in Sources */,
89D7DDDD12E8DE09001E2B82 /* inspector.cc in Sources */,
+ 896FA1E5130F93D300042054 /* lithium-gap-resolver-arm.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/tools/visual_studio/x64.vsprops b/tools/visual_studio/x64.vsprops
index 79904403..04d9c655 100644
--- a/tools/visual_studio/x64.vsprops
+++ b/tools/visual_studio/x64.vsprops
@@ -12,6 +12,7 @@
/>
<Tool
Name="VCLinkerTool"
+ StackReserveSize="2091752"
TargetMachine="17"
/>
</VisualStudioPropertySheet>
diff --git a/tools/windows-tick-processor.py b/tools/windows-tick-processor.py
deleted file mode 100755
index ade2bf27..00000000
--- a/tools/windows-tick-processor.py
+++ /dev/null
@@ -1,137 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2008 the V8 project authors. All rights reserved.
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * 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.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
-# OWNER OR 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.
-
-
-# Usage: process-ticks.py <binary> <logfile>
-#
-# Where <binary> is the binary program name (eg, v8_shell.exe) and
-# <logfile> is the log file name (eg, v8.log).
-#
-# This tick processor expects to find a map file for the binary named
-# binary.map if the binary is named binary.exe. The tick processor
-# only works for statically linked executables - no information about
-# shared libraries is logged from v8 on Windows.
-
-import os, re, sys, tickprocessor
-
-class WindowsTickProcessor(tickprocessor.TickProcessor):
-
- def Unmangle(self, name):
- """Performs very simple unmangling of C++ names.
-
- Does not handle arguments and template arguments. The mangled names have
- the form:
-
- ?LookupInDescriptor@JSObject@internal@v8@@...arguments info...
-
- """
- # Name is mangled if it starts with a question mark.
- is_mangled = re.match("^\?(.*)", name)
- if is_mangled:
- substrings = is_mangled.group(1).split('@')
- try:
- # The function name is terminated by two @s in a row. Find the
- # substrings that are part of the function name.
- index = substrings.index('')
- substrings = substrings[0:index]
- except ValueError:
- # If we did not find two @s in a row, the mangled name is not in
- # the format we expect and we give up.
- return name
- substrings.reverse()
- function_name = "::".join(substrings)
- return function_name
- return name
-
-
- def ParseMapFile(self, filename):
- """Parse map file and add symbol information to the cpp entries."""
- # Locate map file.
- has_dot = re.match('^([a-zA-F0-9_-]*)[\.]?.*$', filename)
- if has_dot:
- map_file_name = has_dot.group(1) + '.map'
- try:
- map_file = open(map_file_name, 'rb')
- except IOError:
- sys.exit("Could not open map file: " + map_file_name)
- else:
- sys.exit("Could not find map file for executable: " + filename)
- try:
- max_addr = 0
- min_addr = 2**30
- # Process map file and search for function entries.
- row_regexp = re.compile(' 0001:[0-9a-fA-F]{8}\s*([_\?@$0-9a-zA-Z]*)\s*([0-9a-fA-F]{8}).*')
- for line in map_file:
- row = re.match(row_regexp, line)
- if row:
- addr = int(row.group(2), 16)
- if addr > max_addr:
- max_addr = addr
- if addr < min_addr:
- min_addr = addr
- mangled_name = row.group(1)
- name = self.Unmangle(mangled_name)
- self.cpp_entries.Insert(addr, tickprocessor.CodeEntry(addr, name));
- i = min_addr
- # Mark the pages for which there are functions in the map file.
- while i < max_addr:
- page = i >> 12
- self.vm_extent[page] = 1
- i += 4096
- finally:
- map_file.close()
-
-
-class WindowsCmdLineProcessor(tickprocessor.CmdLineProcessor):
-
- def __init__(self):
- super(WindowsCmdLineProcessor, self).__init__()
- self.binary_file = None
-
- def GetRequiredArgsNames(self):
- return 'binary log_file'
-
- def ProcessRequiredArgs(self, args):
- if len(args) != 2:
- self.PrintUsageAndExit()
- else:
- self.binary_file = args[0]
- self.log_file = args[1]
-
-
-def Main():
- cmdline_processor = WindowsCmdLineProcessor()
- cmdline_processor.ProcessArguments()
- tickprocessor = WindowsTickProcessor()
- tickprocessor.ParseMapFile(cmdline_processor.binary_file)
- cmdline_processor.RunLogfileProcessing(tickprocessor)
- tickprocessor.PrintResults()
-
-if __name__ == '__main__':
- Main()