Diff
Modified: trunk/Source/_javascript_Core/CMakeLists.txt (259733 => 259734)
--- trunk/Source/_javascript_Core/CMakeLists.txt 2020-04-08 18:18:47 UTC (rev 259733)
+++ trunk/Source/_javascript_Core/CMakeLists.txt 2020-04-08 18:23:51 UTC (rev 259734)
@@ -220,6 +220,7 @@
DEPENDS ${GENERATOR} bytecode/BytecodeList.rb
COMMAND ${RUBY_EXECUTABLE} ${_javascript_CORE_DIR}/generator/main.rb --bytecodes_h ${_javascript_Core_DERIVED_SOURCES_DIR}/Bytecodes.h --init_bytecodes_asm ${_javascript_Core_DERIVED_SOURCES_DIR}/InitBytecodes.asm --bytecode_structs_h ${_javascript_Core_DERIVED_SOURCES_DIR}/BytecodeStructs.h --bytecode_indices_h ${_javascript_Core_DERIVED_SOURCES_DIR}/BytecodeIndices.h ${_javascript_CORE_DIR}/bytecode/BytecodeList.rb --wasm_json ${_javascript_CORE_DIR}/wasm/wasm.json --wasm_llint_generator_h ${_javascript_Core_DERIVED_SOURCES_DIR}/WasmLLIntGeneratorInlines.h --init_wasm_llint ${_javascript_Core_DERIVED_SOURCES_DIR}/InitWasm.asm --bytecode_dumper ${_javascript_Core_DERIVED_SOURCES_DIR}/BytecodeDumperGenerated.cpp
VERBATIM)
+add_custom_target(Bytecodes DEPENDS "${_javascript_Core_DERIVED_SOURCES_DIR}/Bytecodes.h")
if (WTF_OS_MAC_OS_X)
@@ -323,7 +324,7 @@
OUTPUT ${_javascript_Core_DERIVED_SOURCES_DIR}/${LLIntOutput}
MAIN_DEPENDENCY ${_javascript_CORE_DIR}/offlineasm/asm.rb
DEPENDS LLIntOffsetsExtractor ${LLINT_ASM} ${OFFLINE_ASM} ${_javascript_Core_DERIVED_SOURCES_DIR}/InitBytecodes.asm ${_javascript_Core_DERIVED_SOURCES_DIR}/InitWasm.asm
- COMMAND ${RUBY_EXECUTABLE} ${_javascript_CORE_DIR}/offlineasm/asm.rb -I${_javascript_Core_DERIVED_SOURCES_DIR}/ ${_javascript_CORE_DIR}/llint/LowLevelInterpreter.asm $<TARGET_FILE:LLIntOffsetsExtractor> ${_javascript_Core_DERIVED_SOURCES_DIR}/${LLIntOutput} ${OFFLINE_ASM_ARGS}
+ COMMAND ${CMAKE_COMMAND} -E env CMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID} GCC_OFFLINEASM_SOURCE_MAP=${GCC_OFFLINEASM_SOURCE_MAP} ${RUBY_EXECUTABLE} ${_javascript_CORE_DIR}/offlineasm/asm.rb -I${_javascript_Core_DERIVED_SOURCES_DIR}/ ${_javascript_CORE_DIR}/llint/LowLevelInterpreter.asm $<TARGET_FILE:LLIntOffsetsExtractor> ${_javascript_Core_DERIVED_SOURCES_DIR}/${LLIntOutput} ${OFFLINE_ASM_ARGS}
COMMAND ${CMAKE_COMMAND} -E touch_nocreate ${_javascript_Core_DERIVED_SOURCES_DIR}/${LLIntOutput}
WORKING_DIRECTORY ${_javascript_Core_DERIVED_SOURCES_DIR}
VERBATIM)
@@ -348,10 +349,17 @@
COMMAND ${MASM_EXECUTABLE} ${LLINT_MASM_FLAGS} ${_javascript_Core_DERIVED_SOURCES_DIR}/LowLevelInterpreterWin.obj ${_javascript_Core_DERIVED_SOURCES_DIR}/LowLevelInterpreterWin.asm
VERBATIM)
list(APPEND _javascript_Core_SOURCES ${_javascript_Core_DERIVED_SOURCES_DIR}/LowLevelInterpreterWin.obj)
+ add_library(LowLevelInterpreterLib OBJECT llint/LowLevelInterpreter.cpp)
else ()
- list(APPEND _javascript_Core_HEADERS
- ${_javascript_Core_DERIVED_SOURCES_DIR}/LLIntAssembly.h
- )
+ # As there's poor toolchain support for using `.file` directives in
+ # inline asm (i.e. there's no way to avoid clashes with the `.file`
+ # directives generated by the C code in the compilation unit), we
+ # introduce a postprocessing pass for the asm that gets assembled into
+ # an object file. We only need to do this for LowLevelInterpreter.cpp
+ # and cmake doesn't allow us to introduce a compiler wrapper for a
+ # single source file, so we need to create a separate target for it.
+ add_library(LowLevelInterpreterLib OBJECT llint/LowLevelInterpreter.cpp
+ ${_javascript_Core_DERIVED_SOURCES_DIR}/${LLIntOutput})
endif ()
# WebAssembly generator
@@ -1366,6 +1374,30 @@
add_subdirectory(shell)
+target_include_directories(LowLevelInterpreterLib
+ PRIVATE "$<TARGET_PROPERTY:_javascript_Core,INCLUDE_DIRECTORIES>")
+add_dependencies(LowLevelInterpreterLib WTF_CopyHeaders Bytecodes)
+
+if (CMAKE_COMPILER_IS_GNUCXX AND GCC_OFFLINEASM_SOURCE_MAP)
+ message(STATUS "Enabling asm postprocessing")
+
+ set(LowLevelInterpreter_LAUNCHER "${_javascript_Core_SCRIPTS_SOURCES_DIR}/postprocess-asm")
+ get_target_property(PROP_RULE_LAUNCH_COMPILE LowLevelInterpreterLib RULE_LAUNCH_COMPILE)
+ if (PROP_RULE_LAUNCH_COMPILE)
+ set(LowLevelInterpreter_LAUNCHER "${LowLevelInterpreter_LAUNCHER} ${PROP_RULE_LAUNCH_COMPILE}")
+ endif ()
+ set_property(TARGET LowLevelInterpreterLib
+ PROPERTY RULE_LAUNCH_COMPILE "${LowLevelInterpreter_LAUNCHER}")
+
+ # Pass in the filename as a magic preprocessor directive, so that
+ # the wrapper can accurately identify the source file.
+ set_source_files_properties("llint/LowLevelInterpreter.cpp"
+ PROPERTIES
+ COMPILE_DEFINITIONS "POSTPROCESS_ASM=llint/LowLevelInterpreter.cpp")
+endif ()
+
+list(APPEND _javascript_Core_SOURCES $<TARGET_OBJECTS:LowLevelInterpreterLib>)
+
WEBKIT_COMPUTE_SOURCES(_javascript_Core)
WEBKIT_WRAP_SOURCELIST(${_javascript_Core_SOURCES})
WEBKIT_FRAMEWORK(_javascript_Core)
Modified: trunk/Source/_javascript_Core/ChangeLog (259733 => 259734)
--- trunk/Source/_javascript_Core/ChangeLog 2020-04-08 18:18:47 UTC (rev 259733)
+++ trunk/Source/_javascript_Core/ChangeLog 2020-04-08 18:23:51 UTC (rev 259734)
@@ -1,3 +1,33 @@
+2020-04-08 Angelos Oikonomopoulos <[email protected]>
+
+ Enable offlineasm debug annotations for GCC
+ https://bugs.webkit.org/show_bug.cgi?id=207119
+
+ Reviewed by Darin Adler.
+
+ This simply reuses the existing code that generates debug
+ annotations, adding two workarounds for limitations in GCC and
+ GDB.
+
+ First, the .file directives that offlineasm inserts in inline asm
+ use file slots that conflict with those in the compilation unit
+ that includes LLIntAssembly.h (specifically,
+ LowLevelInterpreter.cpp). Clang's built-in assembler will
+ transparently fix that for us, but for GCC we need to
+ post-process the generated assembler.
+
+ Unfortunately, cmake doesn't allow us to introduce a compiler wrapper for a
+ single source file, so we need to create a separate target for it. This
+ wrapping only happens when building with GCC and the user has explicitly
+ requested debug information, either by selecting a Debug/RelWithDebInfo build
+ or setting GCC_OFFLINEASM_SOURCE_MAP.
+
+ Second, GDB will only look at the line table for a compilation unit if
+ it can first resolve the address to one of the known symbols in the
+ file. Introduce marker symbols to work around this bug.
+
+ * CMakeLists.txt:
+
2020-04-08 Truitt Savell <[email protected]>
Unreviewed, reverting r259708.
Added: trunk/Source/_javascript_Core/Scripts/postprocess-asm (0 => 259734)
--- trunk/Source/_javascript_Core/Scripts/postprocess-asm (rev 0)
+++ trunk/Source/_javascript_Core/Scripts/postprocess-asm 2020-04-08 18:23:51 UTC (rev 259734)
@@ -0,0 +1,191 @@
+#!/usr/bin/env ruby
+
+# Copyright (C) 2020 Igalia S. L.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+# Wrapper for a .cpp -> .o compilation command. It
+# 1. converts the command to generate a `.s' file
+# 2. runs the ASM postprocessor on it to generate the final `.s` file
+# 3. assembles the `.s` file to a `.o` file
+
+$asm_suffix_pre = ".pre.s"
+$asm_suffix = ".s"
+$postprocessor = "#{File.dirname($0)}/resolve-asm-file-conflicts.rb"
+
+
+$intermediate_paths = []
+
+# We need to work with indices a lot and unfortunately 'getoptlong' in
+# the standard library doesn't expose optind, so we're going with
+# array searches for simplicity.
+def index_nofail(ary, f, errmsg)
+ idx = ary.index { |el|
+ f.call(el)
+ }
+ if idx.nil?
+ $stderr.puts(errmsg)
+ exit(3)
+ end
+ idx
+end
+
+# Find and return the source file for this compilation command,
+# removing it from the args. Note that the path (A) as it appears here
+# (coming from a cmake rule) is likely to be different to the
+# anonymous argument (B) to the compilation command. However, A will
+# be a suffix of B.
+#
+# Exit with an error if the argument is not there. This has already
+# been checked by `cxx-wrapper`, otherwise we wouldn't be running.
+def extract_input!(args)
+ prefix = '-DPOSTPROCESS_ASM='
+
+ idx = index_nofail(args, Proc.new { |arg|
+ arg.start_with?(prefix)
+ }, "No `-DPOSTPROCESS_ASM` argument`")
+
+ path = args[idx][prefix.size..-1]
+ if path.size == 0
+ $stderr.puts("Empty path in -DPOSTPROCESS_ASM=")
+ exit(3)
+ end
+ # We only need this to be defined for the preprocessor (not any
+ # wrapper) from now on.
+ args[idx] = "-DPOSTPROCESS_ASM"
+ return path
+end
+
+# Get the index of the first argument ending in this suffix.
+#
+# Exit with an error if the argument isn't there. We're only ever
+# called with arguments we know are being passed in by the build
+# system.
+def get_arg_idx_suffix(args, wanted)
+ index_nofail(args, Proc.new { |arg|
+ arg.end_with?(wanted)
+ }, "No argument ends with #{wanted}")
+end
+
+# Get index of a given argument. Die if it's not there.
+def get_arg_idx(args, wanted)
+ index_nofail(args, Proc.new { |arg|
+ arg == wanted
+ }, "No `#{wanted}` argument")
+end
+
+# Get the index of `-o` and verify that an argument follows.
+# Both are guaranteed to exist (from our build system).
+def get_o_idx(args)
+ i = get_arg_idx(args, '-o')
+ if (i + 1) >= args.size
+ $stderr.puts("No argument to `-o`")
+ exit(3)
+ end
+ i
+end
+
+# Run command and die if it fails, propagating the exit code.
+def run_cmd(cmd)
+ pid = Process.spawn(*cmd)
+ Process.waitpid(pid)
+ ret = $?
+ if not ret.success?
+ $stderr.puts("Error running cmd: #{ret}")
+ exit(ret.exitstatus)
+ end
+end
+
+# Convert
+# cxx -o blah.o -c blah.cpp
+# to
+# cxx -o blah.s -S blah.cpp
+def build_cxx_cmd(args)
+ c_idx = get_arg_idx(args, '-c')
+ o_idx = get_o_idx(args)
+
+ cxx_args = args.clone
+
+ cxx_args[c_idx] = '-S'
+ o_path = cxx_args[o_idx + 1]
+ cxx_args[o_idx + 1] = o_path.sub(/[.]o$/, $asm_suffix)
+ $intermediate_paths << cxx_args[o_idx + 1]
+ if cxx_args[o_idx + 1] == o_path
+ $stderr.puts("Output file name not an object file: `#{o_path}`")
+ exit(3)
+ end
+ cxx_args
+end
+
+# Do
+# mv blah.S blah.pre.S
+# The reason we do a rename instead of directly generating the .pre.s
+# file when compiling is so that the corresponding .dwo file will have
+# the correct name embedded.
+def rename_s_file(args)
+ o_path = args[get_o_idx(args) + 1]
+ File.rename(o_path.sub(/[.]o$/, $asm_suffix),
+ o_path.sub(/[.]o$/, $asm_suffix_pre))
+end
+
+# Build
+# postprocessor blah.pre.S blah.S
+def build_postprocessor_cmd(args)
+ o_path = args[get_o_idx(args) + 1]
+
+ pp_args = [
+ $postprocessor,
+ o_path.sub(/[.]o$/, $asm_suffix_pre), # input
+ o_path.sub(/[.]o$/, $asm_suffix) # output
+ ]
+ $intermediate_paths << pp_args[-2]
+ $intermediate_paths << pp_args[-1]
+ pp_args
+end
+
+# Build
+# cxx -o blah.o -c blah.S
+def build_as_cmd(args, i_path)
+ i_idx = get_arg_idx_suffix(args, i_path)
+ o_path = args[get_o_idx(args) + 1]
+
+ as_args = args.clone
+ i_path = as_args[i_idx]
+ as_args[i_idx] = o_path.sub(/[.]o$/, $asm_suffix)
+ as_args
+end
+
+args = ARGV.to_a
+i_path = extract_input!(args)
+
+begin
+ run_cmd(build_cxx_cmd(args))
+ rename_s_file(args)
+ run_cmd(build_postprocessor_cmd(args))
+ run_cmd(build_as_cmd(args, i_path))
+ensure
+ $intermediate_paths.each { |p|
+ if File.exist?(p)
+ File.delete(p)
+ end
+ }
+end
Property changes on: trunk/Source/_javascript_Core/Scripts/postprocess-asm
___________________________________________________________________
Added: svn:executable
+*
\ No newline at end of property
Added: trunk/Source/_javascript_Core/Scripts/resolve-asm-file-conflicts.rb (0 => 259734)
--- trunk/Source/_javascript_Core/Scripts/resolve-asm-file-conflicts.rb (rev 0)
+++ trunk/Source/_javascript_Core/Scripts/resolve-asm-file-conflicts.rb 2020-04-08 18:23:51 UTC (rev 259734)
@@ -0,0 +1,399 @@
+#!/usr/bin/env ruby
+
+# Copyright (C) 2020 Igalia S. L.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+# Resolve conflicts in `.file` directives in assembler files. Those
+# may result from inline asm statements which themselves have `.file`
+# directives. As the inline asm has no idea what the next free file
+# number is, it'll generally have its own numbering. To get things to
+# work we have to
+# 1. remap conflicting file numbers
+# 2. change `.loc` directives to reference the appropriate file number.
+#
+# To be able to do that, we need some concept of "scope", i.e. which
+# set of files a given `.loc` directive refers to. We get that by
+# tracking the #APP/#NOAPP directives that the compiler emits when it
+# switch to/from inline asm.
+#
+# In effect, we convert
+# .file 1 "foo"
+# #APP
+# .file 1 "bar"
+# .file 2 "foo"
+# .loc 1, X
+# #NOAPP
+# .loc 1, Y
+# to
+# .file 1 "foo"
+# #APP
+# .file 2 "bar"
+# .file 1 "foo"
+# .loc 2, X
+# #NOAPP
+# .loc 1, Y
+
+require 'pathname'
+require 'stringio'
+require 'strscan'
+
+ParseResultSuccess = Struct.new(:str)
+ParseResultError = Struct.new(:error)
+
+# Parses the single string literal following a .file assembler directive
+class FileDirectiveArgScanner
+ def initialize(s)
+ @s = StringScanner.new(s)
+ end
+ def parse
+ @s.skip(/\s*/)
+
+ # We require at least one string literal
+ ret = parse_string_literal
+ if ret.respond_to?(:error)
+ return ret
+ end
+
+ @s.skip(/\s*/)
+ if not @s.eos?
+ return ParseResultError.new("Expected end of line after #{ret.str}")
+ end
+ return ParseResultSuccess.new(ret.str)
+ end
+ def parse_string_literal
+ if @s.scan(/"/).nil?
+ err = "Expected string literal at `#{@s.string}` (pos #{@s.pos})"
+ return ParseResultError.new(err)
+ end
+ parse_until_end_of_string_literal
+ end
+ def parse_until_end_of_string_literal
+ start_pos = @s.pos
+ while true
+ # Search for our special characters
+ @s.skip(/[^"\\]+/)
+ if @s.scan(/\\/)
+ if @s.scan(/\\/)
+ # When we see '\\', consume both characters so that the
+ # second '\' will not be treated as an escape char.
+ next
+ elsif @s.scan(/"/)
+ # For '\"', consume both characters so that the '"' will not
+ # terminate the string.
+ next
+ end
+ next
+ elsif @s.scan(/"/)
+ # '"' without a preceeding '\'; terminate the literal.
+ # We're already past the '"', so the literal ends at -2
+ # characters.
+ return ParseResultSuccess.new(@s.string[start_pos..(@s.pos - 2)])
+ elsif @s.eos?
+ err = "Unterminated string literal (starting at pos #{start_pos} in #{@s.string}"
+ return ParseResultError.new(err)
+ end
+ raise "Internal error (#{@s.inspect})"
+ end
+ end
+end
+
+def test(outf, str, res)
+ pr = FileDirectiveArgScanner.new(str).parse
+ if res.is_a?(Array)
+ if pr.respond_to?(:error)
+ outf.puts("Parse result is `#{pr.error}` but expected #{res}")
+ return false
+ end
+ if pr.str != res[0]
+ outf.puts("Parsed path `#{pr.str}` but expected `#{res[0]}`")
+ return false
+ end
+ return true
+ elsif res.is_a?(String)
+ if pr.respond_to?(:error)
+ if not pr.error.downcase.include?(res.downcase)
+ err = "Error message `#{pr.error}` does not include expected substring `#{res}`"
+ outf.puts(err)
+ return false
+ end
+ return true
+ end
+ outf.puts("Expected error (#{res}) but got successful parse #{pr.str}")
+ return false
+ else
+ raise "Internal error #{res.class}"
+ end
+end
+
+def selftest
+ nr_succeeded = 0
+ tests = [
+ # simple string
+ ['"foo/bar"', ["foo/bar"]],
+
+ ['"foo', "Unterminated string literal"],
+
+ ['"foo\"', "Unterminated string literal"],
+
+ # "foo\"
+ ["\"foo\\\"", "Unterminated string literal"],
+
+ # "foo\\"
+ ["\"foo\\\\\"", ["foo\x5c\x5c"]],
+
+ # Can escape '"'
+ ['"foo\"bar"', ['foo\"bar']],
+
+ # Can parse relative
+ ['"foo/bar"', ['foo/bar']],
+
+ # Can parse absolute
+ ['"/bar"', ['/bar']],
+
+ # Can parse absolute with two components
+ ['"/bar/baz"', ['/bar/baz']],
+
+ # Can detect stray token
+ ['"foo" bar', "Expected end of line"],
+
+ # Can detect stray token without whitespace
+ ['"foo"bar', "Expected end of line"],
+
+ # Will not accept clang-style .file directives
+ ['"working_directory" "path"', "Expected end of line"]
+ ]
+ outf = StringIO.new("")
+ tests.each { |str, res|
+ if test(outf, str, res)
+ nr_succeeded += 1
+ end
+ }
+ if nr_succeeded != tests.size
+ $stderr.puts(outf.string)
+ $stderr.puts("Some self tests failed #{nr_succeeded}/#{tests.size}")
+ exit(3)
+ end
+end
+
+# Keep track of which fileno is assigned to which file path. We call
+# the fileno a 'slot'.
+class FileSlotTracker
+ @@next_free = 1 # Next free global slot
+ @@paths = {} # Maps path -> global slot
+ def initialize(parent)
+ @parent = parent
+ # This maps from our own local slots (i.e. within an APP section)
+ # to a global slot.
+ @slot_map = {}
+ end
+ # We make sure that .file directives that specify the same path are
+ # dedup'd, i.e. if we see
+ # .file N "/path/to/include.h"
+ # ...
+ # .file M "/path/to/include.h"
+ # then the "local" N, M slots will be mapped to the same "global" slot.
+ def register_path(path, slot)
+ curr_slot = @@paths[path]
+ if curr_slot.nil?
+ # We haven't seen this file before
+ if slot <= @@next_free
+ # Desired file slot either clashes with an existing one, or is
+ # the next one to be allocated. In either case, assign the
+ # next free slot.
+ assign_next_slot(path)
+ else
+ # Don't allow slot gaps. Technically we could handle them, but
+ # they should never happen; bail now rather than papering over
+ # an earlier error.
+ $stderr.puts("File wants slot #{slot} but only seen #{@@next_free} so far")
+ exit(2)
+ end
+ else
+ # We've already assigned a slot for this file.
+ end
+ @slot_map[slot] = @@paths[path]
+ if @slot_map[slot].nil?
+ raise "Didn't map local slot #{slot}"
+ end
+ end
+ # Return global slot for path
+ def slot_for_path(path)
+ return @@paths[path]
+ end
+ # Return global slot that will replace the local slot
+ def remap_slot(slot)
+ ret = nil
+ if @slot_map.size > 0
+ # If the current NO_APP segment has defined a .file, only look
+ # in the current FileSlotTracker. This is the case for a
+ # top-level inline asm statement.
+ ret = @slot_map[slot]
+ elsif not @parent.nil?
+ # If the current NO_APP segment has not defined a .file, clearly
+ # all .loc directives refer to files defined in the APP
+ # part. This is the case for non-top-level inline asm
+ # statements.
+ ret = @parent.remap_slot(slot)
+ end
+ if ret.nil?
+ raise "No global slot for #{slot}"
+ end
+ ret
+ end
+ private
+ def assign_next_slot(path)
+ @@paths[path] = @@next_free
+ @@next_free += 1
+ end
+end
+
+# Return sequential lines, while keeping track of whether we're in an
+# #APP or #NOAPP section.
+class AsmReader
+ attr_reader :in_app
+ attr_accessor :app_to_noapp, :noapp_to_app
+ def initialize(f)
+ @f = f
+ @f.rewind
+ @linenr = 0
+ @in_app = false
+ @last_switch = "start of file" # For error messages
+ end
+ def next_line
+ while true
+ l = @f.gets
+ if l.nil?
+ return l
+ end
+ @linenr += 1
+ if /^#\s*APP\s*/.match(l)
+ if @in_app
+ raise "#APP on line #{@linenr} but already in #APP (#{@last_switch})"
+ end
+ @in_app = true
+ @last_switch = @linenr
+ if @noapp_to_app
+ @noapp_to_app.call()
+ end
+ end
+ if /^#\s*NO_APP\s*/.match(l)
+ if not @in_app
+ raise "#NOAPP on line #{@linenr} but was not in #APP (last swich at #{@last_switch})"
+ end
+ @in_app = false
+ @last_switch = @linenr
+ if @app_to_noapp
+ @app_to_noapp.call()
+ end
+ end
+ return l
+ end
+ end
+end
+
+class FileConflictResolver
+ @@file_re = /^\s*[.]file\s+(?<slot>\d+)\s+(?<rest>.*)$/
+ @@loc_re = /^(?<white1>\s*)[.]loc(?<white2>\s+)(?<slot>\d+)(?<rest>\s+\d+.*)$/
+ def initialize(inf, outf)
+ @outf = outf
+ @trackers = [FileSlotTracker.new(nil)]
+ @asm_reader = AsmReader.new(inf)
+ # When we enter an #APP section (i.e. asm emitted from an expanded
+ # inline asm statement), create a new file tracker, in effect
+ # processing the .file and .loc directives in a new "namespace"
+ # (as far as the file numbers are concerned). This is an array,
+ # but in practice the size will either be 1 (NOAPP) or 2 (APP).
+ @asm_reader.app_to_noapp = Proc.new { ||
+ @trackers.pop
+ }
+ @asm_reader.noapp_to_app = Proc.new { ||
+ @trackers.push(FileSlotTracker.new(@trackers[-1]))
+ }
+ end
+ def run
+ while true
+ l = @asm_reader.next_line
+ break unless l
+
+ md = @@file_re.match(l)
+ if md
+ file_directive(md)
+ next
+ end
+ md = @@loc_re.match(l)
+ if md
+ loc_directive(md)
+ next
+ end
+ @outf.write(l)
+ next
+ end
+ end
+ def loc_directive(md)
+ tracker = @trackers.last
+ slot = tracker.remap_slot(md[:slot].to_i)
+ @outf.puts("#{md[:white1]}.loc#{md[:white2]}#{slot}#{md[:rest]}")
+ end
+ def file_directive(md)
+ tracker = @trackers.last
+
+ pr = FileDirectiveArgScanner.new(md[:rest]).parse
+ if pr.respond_to?(:error)
+ $stderr.puts("Error parsing path argument to .file directive: #{pr.error}")
+ exit(2)
+ end
+
+ path = pr.str
+ tracker.register_path(path, md[:slot].to_i)
+
+ slot = tracker.slot_for_path(path)
+ @outf.puts("\t.file\t#{slot} #{md[:rest]}")
+ end
+end
+
+# First, make sure our tests still pass. This only takes a fraction of
+# our runtime and ensures the tests will get run by anyone trying out
+# changes to this file.
+selftest
+
+if ARGV.size != 2
+ $stderr.puts("Usage: #{$0} input output")
+ exit(2)
+end
+
+inpath, outpath = ARGV.collect { |n| Pathname.new(n) }
+
+if not inpath.file?
+ $stderr.puts("Not a regular file: `#{inpath}`")
+ exit(2)
+end
+
+if inpath.extname.upcase != ".S"
+ $stderr.puts("warning: file `#{inpath}` doesn't have a `.s` or `.S` extension. Going on anyway...")
+end
+
+File.open(inpath, "r") { |inf|
+ File.open(outpath, "w") { |outf|
+ FileConflictResolver.new(inf, outf).run
+ }
+}
Property changes on: trunk/Source/_javascript_Core/Scripts/resolve-asm-file-conflicts.rb
___________________________________________________________________
Added: svn:executable
+*
\ No newline at end of property
Modified: trunk/Source/_javascript_Core/Sources.txt (259733 => 259734)
--- trunk/Source/_javascript_Core/Sources.txt 2020-04-08 18:18:47 UTC (rev 259733)
+++ trunk/Source/_javascript_Core/Sources.txt 2020-04-08 18:23:51 UTC (rev 259734)
@@ -677,8 +677,6 @@
llint/LLIntExceptions.cpp
llint/LLIntSlowPaths.cpp
llint/LLIntThunks.cpp
-// FIXME: We can't bundle this file due to a clang bug.
-llint/LowLevelInterpreter.cpp @no-unify
parser/Lexer.cpp
parser/ModuleAnalyzer.cpp
Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter.cpp (259733 => 259734)
--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter.cpp 2020-04-08 18:18:47 UTC (rev 259733)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter.cpp 2020-04-08 18:23:51 UTC (rev 259734)
@@ -537,8 +537,19 @@
#define OFFLINE_ASM_OPCODE_DEBUG_LABEL(label)
#endif
+// This works around a bug in GDB where, if the compilation unit
+// doesn't have any address range information, its line table won't
+// even be consulted. Emit {before,after}_llint_asm so that the code
+// emitted in the top level inline asm statement is within functions
+// visible to the compiler. This way, GDB can resolve a PC in the
+// llint asm code to this compilation unit and the successfully look
+// up the line number information.
+DEBUGGER_ANNOTATION_MARKER(before_llint_asm)
+
// This is a file generated by offlineasm, which contains all of the assembly code
// for the interpreter, as compiled from LowLevelInterpreter.asm.
#include "LLIntAssembly.h"
+DEBUGGER_ANNOTATION_MARKER(after_llint_asm)
+
#endif // ENABLE(C_LOOP)
Modified: trunk/Source/_javascript_Core/offlineasm/config.rb (259733 => 259734)
--- trunk/Source/_javascript_Core/offlineasm/config.rb 2020-04-08 18:18:47 UTC (rev 259733)
+++ trunk/Source/_javascript_Core/offlineasm/config.rb 2020-04-08 18:23:51 UTC (rev 259734)
@@ -89,6 +89,10 @@
end
end
end
+ elsif ENV["CMAKE_CXX_COMPILER_ID"] == 'GNU' and
+ ENV["GCC_OFFLINEASM_SOURCE_MAP"] == 'ON'
+ # All GCC versions that can build JSC support debug annotations
+ return true
end
false
Modified: trunk/Source/WTF/wtf/Compiler.h (259733 => 259734)
--- trunk/Source/WTF/wtf/Compiler.h 2020-04-08 18:18:47 UTC (rev 259733)
+++ trunk/Source/WTF/wtf/Compiler.h 2020-04-08 18:23:51 UTC (rev 259734)
@@ -382,6 +382,17 @@
#define WARN_UNUSED_RETURN
#endif
+/* DEBUGGER_ANNOTATION_MARKER */
+
+#if !defined(DEBUGGER_ANNOTATION_MARKER) && COMPILER(GCC)
+#define DEBUGGER_ANNOTATION_MARKER(name) \
+ __attribute__((__no_reorder__)) void name(void) { __asm__(""); }
+#endif
+
+#if !defined(DEBUGGER_ANNOTATION_MARKER)
+#define DEBUGGER_ANNOTATION_MARKER(name)
+#endif
+
#if !defined(__has_include) && COMPILER(MSVC)
#define __has_include(path) 0
#endif
Modified: trunk/Source/cmake/OptionsCommon.cmake (259733 => 259734)
--- trunk/Source/cmake/OptionsCommon.cmake 2020-04-08 18:18:47 UTC (rev 259733)
+++ trunk/Source/cmake/OptionsCommon.cmake 2020-04-08 18:23:51 UTC (rev 259734)
@@ -112,6 +112,15 @@
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gdb-index")
endif ()
+set(GCC_OFFLINEASM_SOURCE_MAP_DEFAULT OFF)
+if (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
+ set(GCC_OFFLINEASM_SOURCE_MAP_DEFAULT ON)
+endif ()
+
+option(GCC_OFFLINEASM_SOURCE_MAP
+ "Produce debug line information for offlineasm-generated code"
+ ${GCC_OFFLINEASM_SOURCE_MAP_DEFAULT})
+
# Enable the usage of OpenMP.
# - At this moment, OpenMP is only used as an alternative implementation
# to native threads for the parallelization of the SVG filters.